1
1
import io
2
2
import json
3
3
import logging
4
+ import string
4
5
import tarfile
5
6
import tempfile
6
7
import time
10
11
import docker
11
12
import docker .errors
12
13
import os
13
-
14
- from tenacity import retry , stop_after_delay , wait_fixed
15
- from clients .signals import SignalClient
14
+ from clients .services .wallet import WalletService
15
+ from clients .services .wakuext import WakuextService
16
+ from clients .services .accounts import AccountService
17
+ from clients .services .settings import SettingsService
18
+ from clients .signals import SignalClient , SignalType
16
19
from clients .rpc import RpcClient
17
20
from conftest import option
18
21
from resources .constants import user_1 , DEFAULT_DISPLAY_NAME , USER_DIR
22
+ from docker .errors import APIError
19
23
20
24
NANOSECONDS_PER_SECOND = 1_000_000_000
21
25
@@ -24,22 +28,23 @@ class StatusBackend(RpcClient, SignalClient):
24
28
25
29
container = None
26
30
27
- def __init__ (self , await_signals = []):
31
+ def __init__ (self , await_signals = [], privileged = False ):
28
32
29
33
if option .status_backend_url :
30
34
url = option .status_backend_url
31
35
else :
32
36
self .docker_client = docker .from_env ()
33
37
host_port = random .choice (option .status_backend_port_range )
34
38
35
- self .container = self ._start_container (host_port )
39
+ self .container = self ._start_container (host_port , privileged )
36
40
url = f"http://127.0.0.1:{ host_port } "
37
41
option .status_backend_port_range .remove (host_port )
38
42
39
43
self .base_url = url
40
44
self .api_url = f"{ url } /statusgo"
41
45
self .ws_url = f"{ url } " .replace ("http" , "ws" )
42
46
self .rpc_url = f"{ url } /statusgo/CallRPC"
47
+ self .public_key = ""
43
48
44
49
RpcClient .__init__ (self , self .rpc_url )
45
50
SignalClient .__init__ (self , self .ws_url , await_signals )
@@ -50,7 +55,12 @@ def __init__(self, await_signals=[]):
50
55
websocket_thread .daemon = True
51
56
websocket_thread .start ()
52
57
53
- def _start_container (self , host_port ):
58
+ self .wallet_service = WalletService (self )
59
+ self .wakuext_service = WakuextService (self )
60
+ self .accounts_service = AccountService (self )
61
+ self .settings_service = SettingsService (self )
62
+
63
+ def _start_container (self , host_port , privileged ):
54
64
docker_project_name = option .docker_project_name
55
65
56
66
timestamp = int (time .time () * 1000 ) # Keep in sync with run_functional_tests.sh
@@ -62,6 +72,7 @@ def _start_container(self, host_port):
62
72
container_args = {
63
73
"image" : image_name ,
64
74
"detach" : True ,
75
+ "privileged" : privileged ,
65
76
"name" : container_name ,
66
77
"labels" : {"com.docker.compose.project" : docker_project_name },
67
78
"entrypoint" : [
@@ -182,21 +193,26 @@ def extract_data(self, path: str):
182
193
def create_account_and_login (
183
194
self ,
184
195
data_dir = USER_DIR ,
185
- display_name = DEFAULT_DISPLAY_NAME ,
196
+ display_name = None ,
186
197
password = user_1 .password ,
187
198
):
199
+ self .display_name = (
200
+ display_name if display_name else f"DISP_NAME_{ '' .join (random .choices (string .ascii_letters + string .digits + '_-' , k = 10 ))} "
201
+ )
188
202
method = "CreateAccountAndLogin"
189
203
data = {
190
204
"rootDataDir" : data_dir ,
191
205
"kdfIterations" : 256000 ,
192
- "displayName" : display_name ,
206
+ "displayName" : self . display_name ,
193
207
"password" : password ,
194
208
"customizationColor" : "primary" ,
195
209
"logEnabled" : True ,
196
210
"logLevel" : "DEBUG" ,
197
211
}
198
212
data = self ._set_proxy_credentials (data )
199
- return self .api_valid_request (method , data )
213
+ resp = self .api_valid_request (method , data )
214
+ self .node_login_event = self .find_signal_containing_pattern (SignalType .NODE_LOGIN .value , event_pattern = self .display_name )
215
+ return resp
200
216
201
217
def restore_account_and_login (
202
218
self ,
@@ -256,72 +272,34 @@ def restore_account_and_wait_for_rpc_client_to_start(self, timeout=60):
256
272
# ToDo: change this part for waiting for `node.login` signal when websockets are migrated to StatusBackend
257
273
while time .time () - start_time <= timeout :
258
274
try :
259
- self .rpc_valid_request ( method = "accounts_getKeypairs" )
275
+ self .accounts_service . get_account_keypairs ( )
260
276
return
261
277
except AssertionError :
262
278
time .sleep (3 )
263
279
raise TimeoutError (f"RPC client was not started after { timeout } seconds" )
264
280
265
- @retry (stop = stop_after_delay (10 ), wait = wait_fixed (0.5 ), reraise = True )
266
- def start_messenger (self , params = []):
267
- method = "wakuext_startMessenger"
268
- response = self .rpc_request (method , params )
269
- json_response = response .json ()
270
-
271
- if "error" in json_response :
272
- assert json_response ["error" ]["code" ] == - 32000
273
- assert json_response ["error" ]["message" ] == "messenger already started"
274
- return
275
-
276
- self .verify_is_valid_json_rpc_response (response )
277
-
278
- def start_wallet (self , params = []):
279
- method = "wallet_startWallet"
280
- response = self .rpc_request (method , params )
281
- self .verify_is_valid_json_rpc_response (response )
282
-
283
- def get_settings (self , params = []):
284
- method = "settings_getSettings"
285
- response = self .rpc_request (method , params )
286
- self .verify_is_valid_json_rpc_response (response )
287
-
288
- def get_accounts (self , params = []):
289
- method = "accounts_getAccounts"
290
- response = self .rpc_request (method , params )
291
- self .verify_is_valid_json_rpc_response (response )
292
- return response .json ()
293
-
294
- def get_pubkey (self , display_name ):
295
- response = self .get_accounts ()
296
- accounts = response .get ("result" , [])
297
- for account in accounts :
298
- if account .get ("name" ) == display_name :
299
- return account .get ("public-key" )
300
- raise ValueError (f"Public key not found for display name: { display_name } " )
301
-
302
- def send_contact_request (self , contact_id : str , message : str ):
303
- method = "wakuext_sendContactRequest"
304
- params = [{"id" : contact_id , "message" : message }]
305
- response = self .rpc_request (method , params )
306
- self .verify_is_valid_json_rpc_response (response )
307
- return response .json ()
308
-
309
- def accept_contact_request (self , chat_id : str ):
310
- method = "wakuext_acceptContactRequest"
311
- params = [{"id" : chat_id }]
312
- response = self .rpc_request (method , params )
313
- self .verify_is_valid_json_rpc_response (response )
314
- return response .json ()
315
-
316
- def get_contacts (self ):
317
- method = "wakuext_contacts"
318
- response = self .rpc_request (method )
319
- self .verify_is_valid_json_rpc_response (response )
320
- return response .json ()
321
-
322
- def send_message (self , contact_id : str , message : str ):
323
- method = "wakuext_sendOneToOneMessage"
324
- params = [{"id" : contact_id , "message" : message }]
325
- response = self .rpc_request (method , params )
326
- self .verify_is_valid_json_rpc_response (response )
327
- return response .json ()
281
+ def container_pause (self ):
282
+ if not self .container :
283
+ raise RuntimeError ("Container is not initialized." )
284
+ self .container .pause ()
285
+ logging .info (f"Container { self .container .name } paused." )
286
+
287
+ def container_unpause (self ):
288
+ if not self .container :
289
+ raise RuntimeError ("Container is not initialized." )
290
+ self .container .unpause ()
291
+ logging .info (f"Container { self .container .name } unpaused." )
292
+
293
+ def container_exec (self , command ):
294
+ if not self .container :
295
+ raise RuntimeError ("Container is not initialized." )
296
+ try :
297
+ exec_result = self .container .exec_run (cmd = ["sh" , "-c" , command ], stdout = True , stderr = True , tty = False )
298
+ if exec_result .exit_code != 0 :
299
+ raise RuntimeError (f"Failed to execute command in container { self .container .id } :\n " f"OUTPUT: { exec_result .output .decode ().strip ()} " )
300
+ return exec_result .output .decode ().strip ()
301
+ except APIError as e :
302
+ raise RuntimeError (f"API error during container execution: { str (e )} " ) from e
303
+
304
+ def find_public_key (self ):
305
+ self .public_key = self .node_login_event .get ("event" , {}).get ("settings" , {}).get ("public-key" )
0 commit comments