async def serial_port(session): """ Serial port scenario """ experiments = molotov.get_var('exp') if experiments.empty(): print("No experiments ...") assert False # exp = (exp_id, login) exp = experiments.get() auth = get_auth(exp[1], 'Monkey-{}'.format(exp[1])) nodes = await asyncio.wait_for(get_experiment_nodes( session, molotov.get_var('url'), auth, exp[0]), timeout=120) # Get one node node = nodes.pop() config = molotov.get_var('config') firmware = 'iotlabmonkey/firmwares/{}'.format(config['firmware']) # Flash firmware await asyncio.wait_for(flash_firmware(session, molotov.get_var('url'), auth, exp[0], firmware, [node['network_address']]), timeout=120) # Launch ifconfig command on the serial port #serial_cmd = '{} | socat - tcp:{}:20000'.format(config['cmd'], # node['network_address']) serial_cmd = '{} | nc -q 3 {} 20000'.format(config['cmd'], node['network_address']) output = await asyncio.wait_for(send_ssh_command(node['network_address'], exp[1], molotov.get_var('sshkey'), serial_cmd), timeout=120) print(output)
async def get_experiments_running(session): """ Get experiments scenario """ async with session.get( urljoin(molotov.get_var('url'), 'experiments/running'), auth=molotov.get_var('auth'), ) as resp: res = await resp.json() assert res['items'] is not None assert resp.status == 200
async def get_nodes(session): """ Get nodes scenario """ async with session.get( urljoin(molotov.get_var('url'), 'nodes'), auth=molotov.get_var('auth'), ) as resp: res = await resp.json() assert res['items'] is not None assert resp.status == 200
async def get_experiments_total(session): """ Scenario get total experiments """ async with session.get( urljoin(molotov.get_var('url'), 'experiments/total'), auth=molotov.get_var('auth'), ) as resp: res = await resp.json() assert res['running'] is not None assert res['terminated'] is not None assert res['upcoming'] is not None assert resp.status == 200
async def delete_user(session): """ Delete user scenario """ users = molotov.get_var('users') if users.empty(): print("No users ...") assert False user = users.get() async with session.delete(urljoin(molotov.get_var('url'), 'users/{}'.format(user)), auth=molotov.get_var('auth'), params={'mailing-list': 'off'}) as resp: assert resp.status == 204
async def scenario_get_gc_me_calendar_calendarView_3_days(session): calendarID = molotov.get_var('calendar')['id'] now = molotov.get_var('now') startDateTime = now + dateutil.relativedelta.relativedelta(hour=0, minute=0, second=0, microsecond=0, days=-1) endDateTime = now + dateutil.relativedelta.relativedelta(hour=23, minute=59, second=50, microsecond=999, days=1) async with session.get("%s/me/calendars/%s/calendarView?startDateTime=%s&endDateTime=%s&$select=subject,isAllDay,start,end" % (_GCAPI, calendarID, startDateTime.isoformat(), endDateTime.isoformat())) as resp: assert resp.status == 200, "HTTP response status: %d" % resp.status res = await resp.json() assert res.get('@odata.context', '').endswith('/me/calendars/%s/calendarView' % calendarID) value = res.get('value') if value: await sub_scenario_get_gc_me_calendar_events_all(session, calendarValues=value)
async def init_worker(worker_num, args): headers = {} content_type = molotov.get_var("content_type") if content_type: headers["Content-Type"] = content_type auth = molotov.get_var("auth") if auth is not None: basic = base64.b64encode(auth.encode()) headers["Authorization"] = "Basic %s" % basic.decode() return {"headers": headers}
async def flash_firmware_test(session): """ Flash firmware scenario """ experiments = molotov.get_var('exp') if experiments.empty(): print("No experiments ...") assert False # exp = (exp_id, login) exp = experiments.get() config = molotov.get_var('config') firm_path = 'iotlabmonkey/firmwares/{}'.format(config['firmware']) await asyncio.wait_for(flash_firmware( session, molotov.get_var('url'), get_auth(exp[1], 'Monkey-{}'.format(exp[1])), exp[0], firm_path), timeout=120)
async def stop_experiment(session): """ Stop experiment scenario """ experiments = molotov.get_var('exp') if experiments.empty(): print("No experiments ...") assert False # exp = (exp_id, login) exp = experiments.get() # password = Monkey-<login> async with session.delete( urljoin(molotov.get_var('url'), 'experiments/{}'.format(exp[0])), auth=get_auth(exp[1], 'Monkey-{}'.format(exp[1])), ) as resp: res = await resp.json() assert res['id'] is not None assert resp.status == 200
async def scenario_get_gc_me_calendar(session): calendarID = molotov.get_var('calendar')['id'] async with session.get("%s/me/calendar" % _GCAPI) as resp: assert resp.status == 200, "HTTP response status: %d" % resp.status res = await resp.json() assert res.get('@odata.context', '').endswith('/api/gc/v1/me/calendar') assert res.get('id') == calendarID
async def scenario_delete_gc_me_calendar_calendarView_3_weeks_molotov_prefix(session): calendarID = molotov.get_var('calendar')['id'] now = molotov.get_var('now') startDateTime = now + dateutil.relativedelta.relativedelta(day=1, hour=0, minute=0, second=0, microsecond=0, months=-1) endDateTime = last_day_of_month(now.replace(day=28, hour=23, minute=59, second=50, microsecond=999) + timedelta(days=4)) async with session.get("%s/me/calendars/%s/calendarView?startDateTime=%s&endDateTime=%s&$select=subject,isAllDay,start,end" % (_GCAPI, calendarID, startDateTime.isoformat(), endDateTime.isoformat())) as resp: assert resp.status == 200, "HTTP response status: %d" % resp.status res = await resp.json() assert res.get('@odata.context', '').endswith('/me/calendars/%s/calendarView' % calendarID) value = res.get('value') if value: for entry in value: subject = entry.get('subject') if subject.startswith('Molotov '): if secrets.randbelow(100) < 10: await sub_scenario_delete_gc_me_calendar_events_by_id(session, eventID=entry.get('id'))
async def _test_delete_todo(session): base_url= molotov.get_var('base_url') # list all todos async with session.get(base_url + '/todos') as resp: res = await resp.json() assert resp.status == 200, resp.status # choose random todo and delete it with DELETE request todo_id = random.choice(res)['id'] async with session.delete(base_url + '/todos/' + todo_id) as resp: assert resp.status == 200
async def init_worker(worker_num, args): headers = {} content_type = molotov.get_var("content_type") if content_type: headers["Content-Type"] = content_type auth = molotov.get_var("auth") if auth is not None: basic = base64.b64encode(auth.encode()) headers["Authorization"] = "Basic %s" % basic.decode() data = molotov.get_var("data") if data and data.startswith("py:"): method = molotov.get_var("method") url = molotov.get_var("url") func = resolve(data.split(":")[1]) molotov.set_var("data", func(method, url, args)) return {"headers": headers}
async def _test_update_todo(session): base_url= molotov.get_var('base_url') # list all todos async with session.get(base_url + '/todos') as resp: res = await resp.json() assert resp.status == 200, resp.status # choose random todo and update it with PUT request todo_id = random.choice(res)['id'] todo_data = json.dumps({'text': 'Updated existing todo during Taurus/molotov load test'}) async with session.put(base_url + '/todos/' + todo_id, data=todo_data) as resp: assert resp.status == 200
async def publish(session, data_size): """Publishes a profile with the passed data size """ files = get_var('files') if data_size not in files: raise ValueError( f"The data size {data_size} isn't part of the " f"precomputed files. Available sizes are {list(files)}.") data = get_var('files')[data_size] data = payload_from_raw_data(data) async with session.post(_API + '/compressed-store', data=data) as resp: assert resp.status == 200 # when you read the body, don't forget to use await jwt_token = await resp.text() assert jwt_token != '' return jwt_token
async def http_test(session): url = molotov.get_var("url") res = molotov.get_var("results") meth = molotov.get_var("method") options = {} pre_hook = molotov.get_var("pre_hook") if pre_hook is not None: meth, url, options = pre_hook(meth, url, options) post_hook = molotov.get_var("post_hook") data = molotov.get_var("data") if data: if callable(data): options["data"] = data(meth, url, options) else: options["data"] = data meth = getattr(session, meth.lower()) start = time.time() try: # XXX we should implement raise_for_status globally in # the session in Molotov async with meth(url, raise_for_status=True, **options) as resp: if post_hook is not None: resp = await post_hook(resp) res.incr(resp.status, time.time() - start) except ClientResponseError as exc: res.incr(exc.status, time.time() - start) res.errors[exc.status] += 1 if exc.message not in res.errors_desc: res.errors_desc[exc.message] = exc
async def http_test(session): url = molotov.get_var("url") res = molotov.get_var("results") meth = molotov.get_var("method") options = {} data = molotov.get_var("data") if data: options["data"] = data pre_hook = molotov.get_var("pre_hook") if pre_hook is not None: meth, url, options = pre_hook(meth, url, options) post_hook = molotov.get_var("post_hook") meth = getattr(session, meth.lower()) start = time.time() try: async with meth(url, **options) as resp: if post_hook is not None: resp = await post_hook(resp) res.incr(resp.status, time.time() - start) except Exception as exc: res.errors[exc.errno] += 1 if exc.errno not in res.errors_desc: res.errors_desc[exc.errno] = exc
async def init_worker(worker_num, args): """ Called once per worker startup Caution: The decorated function should be a coroutine :param worker_num: worker_id the worker number :param args: args arguments used to start Molotov :return: """ headers = { 'AnotherHeader': '1', 'User-Agent': molotov.get_var('User-Agent') } return {'headers': headers}
async def scenario_request_stack(session): api_url = get_var("api_url") payload_id = int(random.uniform(0, len(PAYLOADS))) payload_path, payload = PAYLOADS[payload_id] async with session.post(api_url, json=payload) as resp: assert resp.status == 200, f"failed with {resp.status}: {payload_path}" json_data = await resp.json() try: jsonschema.validate(json_data, SCHEMA) except jsonschema.exceptions.ValidationError: raise AssertionError("response didn't validate")
async def submit_experiment(session): """ Submit experiment scenario """ users = molotov.get_var('users') if users.empty(): print("No users ...") assert False user = users.get() config = molotov.get_var('config')['experiments'] exp = _Experiment(name=generate_exp_name(), duration=config['duration']) alias = AliasNodes(config['nb_nodes'], molotov.get_var('site'), 'm3:at86rf231', False) exp.set_alias_nodes(alias) form = FormData() form.add_field("exp", json_dumps(exp), content_type="application/json") async with session.post( urljoin(molotov.get_var('url'), 'experiments'), # password = Monkey-<login> auth=get_auth(user, 'Monkey-{}'.format(user)), data=form, ) as resp: res = await resp.json() assert res['id'] is not None assert resp.status == 200
async def test_basic(session): """Basic test Connect to websocket Register Send a Notification Check notification matches Disconnect """ URLS = get_var("config") encrypted_data = "aLongStringOfEncryptedThings" headers = {"TTL": "60", "Content-Encoding": "aes128gcm"} channel_id = str(uuid.uuid4()) async with session.ws_connect( f'{URLS["push_server"]}:443', headers={"Origin": "http://localhost:1337"}, ssl=False, ) as ws: await ws.send_json(dict(messageType="hello", use_webpush=True)) hello_msg = await ws.receive_json() assert hello_msg["messageType"] == "hello" await ws.send_json(dict(messageType="register", channelID=channel_id)) msg1 = await ws.receive_json() # switch to rust endpoint if os.getenv("AUTOPUSH_RUST_SERVER") and (os.getenv("AUTOPUSH_ENV") != "dev"): path = urlparse(msg1["pushEndpoint"]).path endpoint_url = urljoin(URLS["rs_server_url"], path) else: endpoint_url = msg1["pushEndpoint"] # Send a notification async with session.post( endpoint_url, headers=headers, data=base64.urlsafe_b64decode(encrypted_data), ssl=False, ) as conn: assert conn.status == 201, f'connection returned code {conn.status}' # Receive notification msg2 = await ws.receive_json() assert msg2["data"] == encrypted_data # Acknowledge notification await ws.send_json( dict(messageType="ack", updates=dict(channelID=channel_id))) assert ws.exception() == None await ws.close()
async def ipv6_ping(session): """ IPv6 ping scenario """ experiments = molotov.get_var('exp') if experiments.empty(): print("No experiments ...") assert False # exp = (exp_id, login) exp = experiments.get() firmwares = molotov.get_var('firmwares') if firmwares.empty(): print("No firmwares ...") assert False # firmware = {"firm1_name": "firm1_path", # "firm2_name": "firm2_path"} firmware = firmwares.get() auth = get_auth(exp[1], 'Monkey-{}'.format(exp[1])) # Get nodes nodes = await asyncio.wait_for(get_experiment_nodes( session, molotov.get_var('url'), auth, exp[0]), timeout=120) # Flash nodes firm = firmware['gnrc_networking'] flash_info = 'exp_id: {}, user: {}, firmware: {}' print(flash_info.format(exp[0], exp[1], os.path.basename(firm))) await asyncio.wait_for(flash_firmware(session, molotov.get_var('url'), auth, exp[0], firm), timeout=120) # Get one node node = nodes.pop() # Launch ifconfig command on the serial port ifconfig_cmd = '{} | nc -q 3 {} 20000'.format('echo ifconfig', node['network_address']) output = await asyncio.wait_for(send_ssh_command(node['network_address'], exp[1], molotov.get_var('sshkey'), ifconfig_cmd), timeout=120) if output: #inet6 addr: fe80::14b5:f765:106b:1115 scope: link VAL ipv6_link_local = re.compile(r'fe80:(:[0-9a-f]{0,4}){0,4}') for line in output.splitlines(): if 'scope: link' in line: ipv6_address = (re.search(ipv6_link_local, line)).group() # Get another node node = nodes.pop() cmd = 'echo ping6 {}'.format(ipv6_address) ping_cmd = '{} | nc -q 3 {} 20000'.format(cmd, node['network_address']) output = await asyncio.wait_for(send_ssh_command( node['network_address'], exp[1], molotov.get_var('sshkey'), ping_cmd), timeout=120) print(output)
async def test_notification_bad_token_and_endpoint(session): """Connects and sends a notification with a bad token. Repeasts for 16 times. """ URLS = get_var("config") headers = {"TTL": "60", "Content-Encoding": "aes128gcm"} channel_id = str(uuid.uuid4()) random_endpoint = ''.join( random.choice(string.ascii_lowercase + string.digits) for _ in range(random.randint(1, 1000))) async with session.ws_connect( f'{URLS["push_server"]}:443', headers={"Origin": "http://localhost:1337"}, ssl=False, ) as ws: await ws.send_json(dict(messageType="hello", use_webpush=True)) hello_msg = await ws.receive_json() assert hello_msg["messageType"] == "hello" await ws.send_json(dict(messageType="register", channelID=channel_id)) msg1 = await ws.receive_json() for _ in range(16): # switch to rust endpoint if os.getenv("AUTOPUSH_RUST_SERVER") and (os.getenv("AUTOPUSH_ENV") != "dev"): path = urlparse(msg1["pushEndpoint"]).path endpoint_url = urljoin(URLS["rs_server_url"], path) else: endpoint_url = msg1["pushEndpoint"] parts = endpoint_url.split('/') parts.pop() create_random_url = "/".join(parts) + '/' + random_endpoint # Send a notification random_data = os.urandom(random.randrange(2048, 4096, 2)) async with session.post( create_random_url, headers=headers, data=base64.urlsafe_b64encode(random_data), ssl=False, ) as conn: assert conn.status == 404, f'Connection status code was {conn.status}' await asyncio.sleep(5) else: assert True
async def test_connect_and_hold(session): """Connects and waits for 60 seconds Connect Wait for 60 seconds Disconnect """ URLS = get_var("config") headers = {"TTL": "60", "Content-Encoding": "aes128gcm"} channel_id = str(uuid.uuid4()) async with session.ws_connect( f'{URLS["push_server"]}:443', headers={"Origin": "http://localhost:1337"}, ssl=False, ) as ws: await ws.send_json(dict(messageType="hello", use_webpush=True)) hello_msg = await ws.receive_json() assert hello_msg["messageType"] == "hello" await asyncio.sleep(60) await ws.close()
async def scenario_gc_me_sendMail(session): me = molotov.get_var('me') now = datetime.now() data = { 'message': { 'subject': 'Sent from Molotov (%s)' % now, 'toRecipients': [ { 'emailAddress': { 'name': me['userPrincipalName'], 'address': me['mail'] } } ], 'body': { 'contentType': 'text', 'content': 'Lorem ipsum dolor sit amet, \n\nconsectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. \nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. \n\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nGenerated by your trusted Molotov :)\n\n%s\n' % now } } } async with session.post("%s/me/sendMail" % _GCAPI, data=json.dumps(data)) as resp: assert resp.status == 202, "HTTP response status: %d" % resp.status
async def scenario_post_me_calendar_events(session): now = molotov.get_var('now') startOffset = secrets.randbelow(1440) - 720 # Hours offset from now. minute = secrets.choice((0, 10, 15, 20, 30, 40, 45, 50)) duration = secrets.choice((10, 30, 45, 60, 90, 120)) startDateTime = now + dateutil.relativedelta.relativedelta(hours=startOffset, minute=minute, second=0, microsecond=0) endDateTime = startDateTime + dateutil.relativedelta.relativedelta(minutes=duration) data = { "subject": "Molotov %s-%d" % (startDateTime.isoformat(), duration), "start": { "dateTime": startDateTime.isoformat(), "timeZone": _LOCAL_TZ }, "end": { "dateTime": endDateTime.isoformat(), "timeZone": _LOCAL_TZ } } async with session.post("%s/me/calendar/events" % (_GCAPI), json=data) as resp: assert resp.status == 200, "HTTP response status: %d" % resp.status res = await resp.json() assert res.get('@odata.context', '').endswith('/api/gc/v1/me/calendar/events')
async def test_basic_topic(session): """Basic test with a topic Connect to websocket Register Send a Notification Send another Notification Check 2nd notification matches Disconnect """ URLS = get_var("config") encrypted_data = [ "aLongStringOfEncryptedThings", "aDiffferentStringFullOfStuff" ] topic_one = "aaaa" headers = { "TTL": "60", "Content-Encoding": "aes128gcm", "Topic": topic_one } channel_id = str(uuid.uuid4()) async with session.ws_connect( f'{URLS["push_server"]}:443', headers={"Origin": "http://localhost:1337"}, ssl=False, ) as ws: await ws.send_json(dict(messageType="hello", use_webpush=True)) uaid = await ws.receive_json() await ws.send_json(dict(messageType="register", channelID=channel_id)) msg1 = await ws.receive_json() await ws.close() # switch to rust endpoint if os.getenv("AUTOPUSH_RUST_SERVER"): path = urlparse(msg1["pushEndpoint"]).path endpoint_url = urljoin(URLS["rs_server_url"], path) else: endpoint_url = msg1["pushEndpoint"] # Send Notification async with session.post( endpoint_url, headers=headers, data=base64.urlsafe_b64decode(encrypted_data[0]), ssl=False, ) as conn: assert conn.status == 201 or 202, f'connection returned code {conn.status}' # Send a second Notification with different data async with session.post( endpoint_url, headers=headers, data=base64.urlsafe_b64decode(encrypted_data[1]), ssl=False, ) as conn: assert conn.status == 201 or 202, f'connection returned code {conn.status}' # Connect and check notifications async with session.ws_connect( f'{URLS["push_server"]}:443', headers={"Origin": "http://localhost:1337"}, ssl=False, ) as ws: await ws.send_json( dict(messageType="hello", use_webpush=True, uaid=uaid["uaid"])) await ws.receive_json() # Wait for notification msg = await ws.receive_json() # Check data matches assert msg["data"] == encrypted_data[1] await ws.send_json( dict(messageType="ack", updates=dict(channelID=channel_id))) assert ws.exception() == None await ws.close()
async def _test_create_todo(session): base_url= molotov.get_var('base_url') todo_data = json.dumps({'text': 'Created new todo during Taurus/molotov load test'}) async with session.post(base_url + '/todos', data=todo_data) as resp: assert resp.status == 200
async def _test_list_todos(session): base_url= molotov.get_var('base_url') async with session.get(base_url + '/todos') as resp: assert resp.status == 200, resp.status
async def scenario_one(session): endpoint = molotov.get_var('endpoint') async with session.get(endpoint) as resp: # res = await resp.json() # assert res['result'] == 'OK' assert resp.status == 200
async def init_worker(worker_num, args): headers = {'AnotherHeader': '1', 'SomeHeader': molotov.get_var('SomeHeader')} return {'headers': headers}
async def scenario_one(session): endpoint = molotov.get_var('endpoint') async with session.get(endpoint) as resp: res = await resp.json() assert res['result'] == 'OK' assert resp.status == 200