don't stop believing

hecate 실습 (geth) 1 본문

Python/hecate & tmux

hecate 실습 (geth) 1

Tongchun 2018. 9. 17. 15:44

hecate를 설치하고 기본 기능을 확인해 봤다면 실제 업무에서 어떻게 사용될 지 확인해 보겠습니다.

최근 보고있는 geth에 적용해 보겠습니다.

http://dejavuqa.tistory.com/236


어선 작성한 스크립트는 아래와 같습니다.

# coding=utf-8

import hecate.runner as r
from hecate.hecate import Runner, AbnormalExit
import tempfile
import pytest
import sys, os
import time, datetime
import signal

Runner.print_on_exit = True

def test_geth():

	'''
	현재 사용하고있는 Terminal 창 크기를 확인합니다.
	줄수(rows)와 열수(colums)를 확인해 Runner의 width, height 옵션에 적용합니다
	만약 Runner의 width와 height가 현재 Terminal 크기보다 작다면 에러가 발생합니다.
	UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 152: ordinal not in range(128)
	'''
	rows, columns = os.popen('stty size', 'r').read().split()

	# 날짜를 확인하기 위해 여러 형태로 날자 데이터를 불러옵니다.
	i = datetime.datetime.now()
	dt = datetime.datetime(i.year, i.month, i.day, i.hour, i.minute, i.second)
	ts = time.mktime(dt.timetuple())

	# 날짜 데이터를 이용해 로그파일 이름을 지정합니다.
	logFileName = datetime.datetime.fromtimestamp(int(ts)).strftime('%Y%m%d%H%M%S') + ".log"

	# 로그 파일에 Testing 시작을 기록합니다.
	with open(logFileName, 'at') as f:
		data = " Testing Geth (" + str(dt) + ")\n\n"
		f.write(data)
	
	# 로그 파일에 기록되는 것을 볼 수 있도록 tail 명령을 프린트 합니다.
	print('tail -f 100 ' + logFileName)

	'''
	Runner 클래스를 초기화합니다.
	입력값으로 cli application의 실행 경로와 옵션을 넣어줍니다.
	중요한 것은 width와 height입니다. 이것은 가상으로 실행되는 cli application의 size입니다.
	만약 현재 창보다 width가 작다면 실행 시 에러가 납니다.
	또한 height는 cli applicatin의 전체 테스트 길이보다 작아야 합니다.
	그래서 현재 Terminal의 가로폭(columns)를 확인해 width에 넣고 height는 넉넉하게 1000 줄로 잡았습니다.
	'''
	with Runner(	"/usr/local/bin/geth", 
					"--networkid" ,"45", 
					"--nodiscover", 
					"--maxpeers", "0", 
					"--datadir", "/Users/tongchunkim/Documents/Test_Ethereum/data_testnet", 
					"console", 
					"2>>", "/Users/tongchunkim/Documents/Test_Ethereum/data_testnet/geth.log", 
					width=columns, height=1000) as h:

		# geth 실행 후 나오는 "Welcome to the Geth JavaScript console!"로 실행 시작을 확인합니다.
		# Terminal 화면의 폭과 높이안에 나타나는 text를 기준으로 합니다. 따라서 Runner() 옵션의 width와 height를 적절하게 설정해야 합니다.
		h.await_text("Welcome to the Geth JavaScript console!", 5)

		# 로그파일 확인을 위해 같은 테스트를 10번 반복합니다.
		for i in range(0, 10):

			# coinbase를 확인합니다.
			command = "eth.coinbase"
			h.write(command)
			h.press("Enter")
			time.sleep(1)

			'''
			로그 기록과 assert확인을 위해 명령에 대한 결과값을 확인합니다.
			screenshot()은 terminal 화면의 출력 내용을 text로 가져옵니다.
			이걸 splitlines()로 각 열을 리스트(배열)로 만들고 역순으로 정렬합니다.
			리스트에서 command의 index 번호를 찾고 그보다 앞 줄을 결과값로 확인합니다.
			리스트를 역순으로 하는 이유는 같은 command를 반복했을때 배열에서 가장 아래의 내용을 바로 찾기 위해서 입니다.
			'''
			screenReverseArray = h.screenshot().splitlines()[::-1]
			searchindex = screenReverseArray.index("> " + command)
			print(searchindex)
			value = screenReverseArray[searchindex - 1]
			
			# 확인된 command와 value를 로그파일에 기록합니다.
			with open(logFileName, 'wt') as f:
				data = command + ": " + value + "\n\n"
				print(data)
				f.write(data)

			# 명령에 대한 결과값을 assert 명령으로 처리할 수 있습니다.
			assert "0x78ce083531ff41d26c7002efcf4eec1fd11deaa0" in h.screenshot()		
			time.sleep(1)

			# blockNumber를 확인합니다.
			command = "eth.blockNumber"
			h.write(command)
			h.press("Enter")
			time.sleep(1)

			screenReverseArray = h.screenshot().splitlines()[::-1]
			searchindex = screenReverseArray.index("> " + command)
			print(searchindex)
			value = screenReverseArray[searchindex - 1]

			
			with open(logFileName, 'wt') as f:
				data = command + ": " + value + "\n\n"
				print(data)
				f.write(data)

			assert 0 < int(value), "BlockNumber is less then 0."
			time.sleep(1)


		command = "exit"
		h.write(command)
		h.press("Enter")

		screenReverseArray = h.screenshot().splitlines()[::-1]
		searchindex = screenReverseArray.index("> " + command)
		print(searchindex)
		value = screenReverseArray[searchindex - 1]

		with open(logFileName, 'wt') as f:
			data = command + ": " + value + "\n\n"
			print(data)
			f.write(data)

		h.await_exit()


	with open(logFileName, 'wt') as f:
		data = "---------- Testing finish ----------"
		f.write(data)
	

if __name__== "__main__":
	test_geth()


위 코드는 geth 실행 후 coinbase와 blockNumber를 확인하는 테스트입니다.

# coding=utf-8

import hecate.runner as r
from hecate.hecate import Runner, AbnormalExit
import tempfile
import pytest
import sys, os
import time, datetime
import signal

Python 코드를 작성할 때 인코딩을 지정하는 것이 좋습니다.

그리고 필요한 module을 import 합니다.


Runner.print_on_exit = True

Runner가 종료될 때 console 창의 내용을 보여줄 지를 지정합니다.

default 값은 False 입니다.


'''
현재 사용하고있는 Terminal 창 크기를 확인합니다.
줄수(rows)와 열수(colums)를 확인해 Runner의 width, height 옵션에 적용합니다
만약 Runner의 width와 height가 현재 Terminal 크기보다 작다면 에러가 발생합니다.
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 152: ordinal not in range(128)
'''
rows, columns = os.popen('stty size', 'r').read().split()

현재 실행된 Terminal의 세로폭(줄수; rows; height)과 높이(열수; columns; rows; width)를 확인합니다.

Runner 클레스를 초기화 할때 width와 height를 지정해야 합니다. 현재 창의 size를 기준으로 잡기 위해 rows와 columns를 확인합니다.


# 날짜를 확인하기 위해 여러 형태로 날자 데이터를 불러옵니다.
i = datetime.datetime.now()
dt = datetime.datetime(i.year, i.month, i.day, i.hour, i.minute, i.second)
ts = time.mktime(dt.timetuple())

# 날짜 데이터를 이용해 로그파일 이름을 지정합니다.
logFileName = datetime.datetime.fromtimestamp(int(ts)).strftime('%Y%m%d%H%M%S') + ".log"

로그 기록을 위해 날짜 데이터를 여려 형태로 확인합니다.

그리고 날짜 데이터를 이용해 로그 파일 이름을 지정해 줍니다.


# 로그 파일에 Testing 시작을 기록합니다.
with open(logFileName, 'wt') as f:
	data = " Testing Geth (" + str(dt) + ")\n\n"
	f.write(data)

# 로그 파일에 기록되는 것을 볼 수 있도록 tail 명령을 프린트 합니다.
print('tail -f 100 ' + logFileName)

날짜 데이터를 이용해 지정한 로그 파일 이름으로 파일을 생성하고 테스트의 시작을 기록합니다.

그리고 tail 명령과 옵션을 출력해 로그 파일을 바로 확인할 수 있게 합니다.


'''
Runner 클래스를 초기화합니다.
입력값으로 cli application의 실행 경로와 옵션을 넣어줍니다.
중요한 것은 width와 height입니다. 이것은 가상으로 실행되는 cli application의 size입니다.
만약 현재 창보다 width가 작다면 실행 시 에러가 납니다.
또한 height는 cli applicatin의 전체 테스트 길이보다 작아야 합니다.
그래서 현재 Terminal의 가로폭(columns)를 확인해 width에 넣고 height는 넉넉하게 1000 줄로 잡았습니다.
'''
with Runner(	"/usr/local/bin/geth", 
				"--networkid" ,"45", 
				"--nodiscover", 
				"--maxpeers", "0", 
				"--datadir", "/Users/tongchunkim/Documents/Test_Ethereum/data_testnet", 
				"console", 
				"2>>", "/Users/tongchunkim/Documents/Test_Ethereum/data_testnet/geth.log", 
				width=columns, height=1000) as h:

hecate 모듈을 사용할 때 가장 중요한 Runner 클래스 초기화 입니다.

tmux를 이용해 실행시킬 cli application을 지정합니다. 이때 alias 등으로 지정된 명령어보다 해당 경로를 지정하는 것이 좋습니다.

옵션은 공백을 기준으로 여러개의 arguement로 추가합니다.


Runner 클레스에서 중요한 것이 width와 height의 지정입니다.

width는 현재 실행된 terminal의 가로폭으로 지정하면 됩니다. height의 경우 테스트가 종료될 때 까지 필요한 rows를 지정합니다. 만약 Runner에 지정된 width가 현재 실행되고 있는 Terminal보다 크거나 테스트에 사용된 rows가 지정된 height를 넘어갈 경우 에러가 발생합니다.

에러 메시지는 아래와 같이 UnicodeDecodeError로 표시됩니다.

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 114: ordinal not in range(128)


# geth 실행 후 나오는 "Welcome to the Geth JavaScript console!"로 실행 시작을 확인합니다.
# Terminal 화면의 폭과 높이안에 나타나는 text를 기준으로 합니다. 따라서 Runner() 옵션의 width와 height를 적절하게 설정해야 합니다.
h.await_text("Welcome to the Geth JavaScript console!", 5)

Runner 클래스의 await_text()함수를 사용해 'Welcome to the Geth JavaScript console!' 텍스트를 찾을때 까지 대기합니다.

최대 5초동안 기다리도록 지정합니다.


# coinbase를 확인합니다.
command = "eth.coinbase"
h.write(command)
h.press("Enter")
time.sleep(1)

write()함수로 cli application에 타이핑 할 수 있습니다. 그리고 press() 함수로 키를 누릅니다.

geth 명령어인 eth.coinbase를 확인하기 위해 명령어를 입력하고 Enter 키를 누릅니다.

그리고 1초동안 기다립니다.


'''
로그 기록과 assert확인을 위해 명령에 대한 결과값을 확인합니다.
screenshot()은 terminal 화면의 출력 내용을 text로 가져옵니다.
이걸 splitlines()로 각 열을 리스트(배열)로 만들고 역순으로 정렬합니다.
리스트에서 command의 index 번호를 찾고 그보다 앞 줄을 결과값로 확인합니다.
리스트를 역순으로 하는 이유는 같은 command를 반복했을때 배열에서 가장 아래의 내용을 바로 찾기 위해서 입니다.
'''
screenReverseArray = h.screenshot().splitlines()[::-1]
searchindex = screenReverseArray.index("> " + command)
print(searchindex)
value = screenReverseArray[searchindex - 1]

명령을 입력하고 해당 명령에 대한 출력값을 확인하는 코드입니다.

Runner 클래스의 screenshot() 함수는 tmux로 실행된 cli application의 화면을 텍스트로 복사합니다. screenshot() 함수를 바로 print하면 geth 실행 화면이 multiline text로 표현됩니다.

여러줄로된 텍스트를 줄넘김을 기준으로 배열로 만듭니다. 그러면 내가 입력한 명령어가 배열의 어느 위치에 있는지 확인할 수 있고 그 다음 위치에 명령에 대한 결과값이 위치하게 됩니다. 그런데 이 배열을 [::-1]을 이용해 역순으로 변환해 줍니다.

만약 같은 명령을 여러번 입력했을때 정상적인 순서로된 배열의 경우 가장 처음 입력한 명령어만을 반복해서 찾게 됩니다. 배열을 역순으로 변경해 가장 마지막 명령이 배열의 순서상 앞쪽에 있게 변경해 줍니다.

역순으로 변경한 배열에서 명령어의 index 번호를 찾고 그보다 앞에 있는 index를 확인하면 명령에 대한 결과값이 됩니다.


# 확인된 command와 value를 로그파일에 기록합니다.
with open(logFileName, 'wt') as f:
	data = command + ": " + value + "\n\n"
	print(data)
	f.write(data)

명령과 그에 대한 결과값을 확인한 수 로그에 기록해 줍니다.


# 명령에 대한 결과값을 assert 명령으로 처리할 수 있습니다.
assert "0x78ce083531ff41d26c7002efcf4eec1fd11deaa0" in h.screenshot()		
time.sleep(1)

assert를 이용해 해당 결과에 대한 판단을 바로 할 수 있습니다.


여기까지 주요 내용에 대한 설명이며 이하 내용은 같은 내용의 반복입니다.

우선 쓸만한지 더 확인해 봐야겠습니다.


'Python > hecate & tmux' 카테고리의 다른 글

tmux 설치 (on CentOS, Ubuntu)  (0) 2018.10.15
hecate 실습 (geth) 2  (0) 2018.09.20
hecate python module 설치와 기본 사용 (on Mac)  (0) 2018.09.16
Comments