don't stop believing

blockchain 테스트에 사용한 python 함수 - callWS 본문

Python/Basic

blockchain 테스트에 사용한 python 함수 - callWS

Tongchun 2018. 12. 25. 13:32

blockchain 테스트에 사용한 python 함수를 설명합니다.

  • getDateStrings - 날짜 - 년, 월, 일, 시, 분, 초를 확인하는 함수입니다.
  • getLogfileNameWithPath - 로그 기록을 위해 폴더를 생성하고 경로를 반환합니다.
  • getRequestId - ramdom으로 숫자를 반환합니다.
  • moveFile - 특정 파일을 로그 폴더로 이동시킵니다.
  • saveResultData - 데이터를 파일에 저장합니다.
  • convertToHex - String을 hex로 변환합니다.
  • leftPad64 - 왼쪽에 (또는 오른쪽에) 0을 채워 고정된 길이로 만듭니다.
  • getTestConfig - json 형태의 config 파일을 만들고 불러옵니다.
  • waitingCount - time.sleep() 할 때 동적으로 카운트를 셉니다.
  • callRPC - requests 모듈을 사용해 http API를 호출합니다.
  • callWS - websocket 모듈을 사용해 API 통신을 합니다.


blockchain 테스트 대상에는 websocket 도 있습니다. method와 전달하는 data는 RPC와 동일합니다.

Python의 websocket 모듈을 사용해 websocket을 사용해 확인하겠습니다. socket 연결을 맺고 listing을 하는 것은 아닙니다. 단지 websocket 연결해 데이터를 받고 바로 끊습니다. 

함수와 unittest script는 callRPC와 동일하거나 유사합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# coding=utf-8
from websocket import create_connection, WebSocket
import unittest
import json, random
import time, datetime
import sys, pathlib
from pyunitreport import HTMLTestRunner
class nGleUtils():
def getRequestId(self):
'''API request dat id int 1 99 .'''
return random.randint(1,100)
def getDateStrings(self):
''' .'''
i = datetime.datetime.now()
dt = datetime.datetime(i.year, i.month, i.day, i.hour, i.minute, i.second)
ts = time.mktime(dt.timetuple())
return (i, dt, ts)
def getLogfileNameWithPath(self):
'''
log file .
.
'''
# .
i, dt, ts = self.getDateStrings()
# . (:'%Y%m%d%H%M%S')
logFolderName = datetime.datetime.fromtimestamp(int(ts)).strftime('%Y%m%d%H%M%S')
# .
logPath = F"./reports/{logFolderName}"
pathlib.Path(logPath).mkdir(parents=True, exist_ok=True)
# .
logFileName = F"{logPath}/klaytn.log"
# .
return logPath, logFolderName, logFileName
def waitingCount(self, frontString, second, rearString):
'''
.
ex) self.ngle.waitingCount("Waiting for", 5, "seconds until writing in block a transaction.")
'''
for i in range(second, -1, -1):
sys.stdout.write(F"\r{frontString} {i} {rearString}")
sys.stdout.flush()
time.sleep(1)
sys.stdout.write("\n\n")
def callWS(self, nodeHost, wsPort, methodName, params, logfile, saveResult=False):
# methodName param Klaytn RPC request .
HOST = F"ws://{nodeHost}:{str(wsPort)}"
payload = {'jsonrpc':'2.0','method':methodName,'params':params,'id':self.getRequestId()}
isErrer = False
ws = create_connection(HOST)
ws.send(json.dumps(payload))
response = ws.recv()
ws.close()
try:
# result key .
resultJson = json.loads(response)['result']
except KeyError:
# errer key .
resultJson = json.loads(response)['error']
isErrer = True
self.writeLog(logfile, methodName, HOST, payload, response, saveFile=saveResult)
return (resultJson, isErrer)
def writeLog(self, logFileName, klayMethod, host, data, resultText, testingStatus="", testingUnit="", saveFile=False):
'''
Testing .
debug_dumpBlock result .
'''
# result .
if saveFile:
resultText = F"{{\"nGle_Message\": \"{klayMethod} data was saved at a specific file.\"}}"
# testingStatus "Start" "Finish" .
if testingStatus == "Start":
logString = F"------------ Testing Start ({testingUnit}) ------------- \n\n"
elif testingStatus == "Finish":
logString = F"------------ Testing Finish ({testingUnit}) ------------ \n\n"
else:
# testingStatus "Start" "Finish" requests request, response .
# curl curl command .
# curlString = F"curl -H \"Content-Type: application/json\" --data '{str(json.dumps(data))}' {host}"
curlString = F"[\"{host}\"]\n{str(json.dumps(data))}"
jsonResult = json.loads(resultText)
logString = (
F"[{str(datetime.datetime.now())}] [{klayMethod}]\n"
F"{curlString}\n"
F"{json.dumps(jsonResult, indent=4, sort_keys=True)} \n\n"
)
print(logString)
with open(logFileName, 'at') as f:
f.write(F"\n{logString}")
class BlockchainSample(unittest.TestCase):
ngle = nGleUtils()
LOGFOLDER, LOGDATE, LOGPATH = ngle.getLogfileNameWithPath()
blockHost = "10.10.1.168"
wsPort = 8552
def setUp(self):
# unittest TestCase .
print('Test Start')
def test_Accounts_RPC(self):
logTitle = "Account_RPC"
# test log Unit Test .
self.ngle.writeLog(self.LOGPATH, "", "", "", "", testingStatus="Start", testingUnit=logTitle)
# klay_accounts ##############################################################################
methodName = "klay_accounts"
params = []
result, isError = self.ngle.callWS(self.blockHost, self.wsPort, methodName, params, self.LOGPATH)
self.assertFalse(isError, result)
# 5 RPC .
self.ngle.waitingCount("Waiting for", 5, "seconds until writing in block a transaction.")
# klay_blockNumber ##############################################################################
methodName = "klay_blockNumber"
params = []
result, isError = self.ngle.callWS(self.blockHost, self.wsPort, methodName, params, self.LOGPATH)
self.assertFalse(isError, result)
# test log Unit Test .
self.ngle.writeLog(self.LOGPATH, "", "", "", "", testingStatus="Finish", testingUnit=logTitle)
def tearDown(self):
# unittest TestCase .
print('Test Finish')
def suite():
# TestSuite Test addTest .
suite = unittest.TestSuite()
suite.addTest(BlockchainSample('test_Accounts_RPC'))
return suite
# testcase .
if __name__== "__main__":
runner = unittest.TextTestRunner()
# HTMLTestRunner .
kwargs = {
"output": BlockchainSample.LOGDATE,
"report_name": "klayTestReport",
"failfast": True
}
runner = HTMLTestRunner(**kwargs)
runner.run(suite())
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


먼저 request 모듈이 아닌 아래와 같은 websocket 모듈입니다.

from websocket import create_connection, WebSocket


그리고 callRPC가 아닌 callWS을 넣었습니다.


callWS()

input parameter는 아래와 같습니다.

callWS(nodeHost, wsPort, methodName, params, logfile, saveResult=False)

nodeHost는 blockchain node IP 입니다.

wsPort는 websocket port입니다.

methodName, params, logifle, saveResult는 callRPC와 동일합니다.

websocket에 대한 처리는 아래와 같습니다.


ws = create_connection(HOST)

ws.send(json.dumps(payload))

response = ws.recv()

ws.close()


연결하고, payload를 json 형태로 변경해 send 합니다. 그리고 recv()로 데이터를 받으면 websocket을 종료합니다.


writeLog()에서는 callRPC에서 사용한 curl 형태의 string 대신 host와 data(payload)를 그냥 써줍니다.

curlString = F"[\"{host}\"]\n{str(json.dumps(data))}"


unittest의 test 함수에서는 아래와 같이 callWS을 호출합니다.

result, isError = self.ngle.callWS(self.blockHost, self.wsPort, methodName, params, self.LOGPATH)


위 스크립트를 슬행하면 아래와 같이 terminal 창에 출력됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$ python callWS.py
Running tests...
----------------------------------------------------------------------
Test Start
------------ Testing Start (Account_RPC) -------------
[2018-12-25 13:07:06.716017] [klay_accounts]
["ws://10.10.1.168:8552"]
{"jsonrpc": "2.0", "method": "klay_accounts", "params": [], "id": 16}
{
"id": 16,
"jsonrpc": "2.0",
"result": [
"0x859ba4df391ffb81a67a050097527a2c02aef596",
"0x2259cfdae62f9853f84298aaf20c999391b1c6a3",
"0x9789e98e28cbc7f6ff2d6a0f71586e1c10cf829a",
"0xc346de6bd0f3f75d852f481f9f35e3a6452a977e",
"0xabd8ec30f8f896844f01ecb9e7ddb418354d90e5"
]
}
Waiting for 0 seconds until writing in block a transaction.
[2018-12-25 13:07:12.852365] [klay_blockNumber]
["ws://10.10.1.168:8552"]
{"jsonrpc": "2.0", "method": "klay_blockNumber", "params": [], "id": 77}
{
"id": 77,
"jsonrpc": "2.0",
"result": "0x6e8498"
}
------------ Testing Finish (Account_RPC) ------------
Test Finish
test_Accounts_RPC (__main__.BlockchainSample) ... OK (6.310362)s
----------------------------------------------------------------------
Ran 1 test in 6.311s
OK
Generating HTML reports...
Template is not specified, load default template instead.
Reports generated: /Users/tongchunkim/Documents/Test_Python/used_functions/reports/20181225130706/klayTestReport.html
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

callRPC에서와 마찬가지로 klayTestReport.html가 reports 폴더 안에 남았네요.

klaytn.log 파일은 아래와 같이 작성되어 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
------------ Testing Start (Account_RPC) -------------
[2018-12-25 13:07:06.716017] [klay_accounts]
["ws://10.10.1.168:8552"]
{"jsonrpc": "2.0", "method": "klay_accounts", "params": [], "id": 16}
{
"id": 16,
"jsonrpc": "2.0",
"result": [
"0x859ba4df391ffb81a67a050097527a2c02aef596",
"0x2259cfdae62f9853f84298aaf20c999391b1c6a3",
"0x9789e98e28cbc7f6ff2d6a0f71586e1c10cf829a",
"0xc346de6bd0f3f75d852f481f9f35e3a6452a977e",
"0xabd8ec30f8f896844f01ecb9e7ddb418354d90e5"
]
}
[2018-12-25 13:07:12.852365] [klay_blockNumber]
["ws://10.10.1.168:8552"]
{"jsonrpc": "2.0", "method": "klay_blockNumber", "params": [], "id": 77}
{
"id": 77,
"jsonrpc": "2.0",
"result": "0x6e8498"
}
------------ Testing Finish (Account_RPC) ------------
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

여기까지 blockchain 테스트에 사용한 함수 설명이었습니다.