You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					425 lines
				
				15 KiB
			
		
		
			
		
	
	
					425 lines
				
				15 KiB
			| 
								 
											6 years ago
										 
									 | 
							
								#!/usr/bin/env python3
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								import pytest
							 | 
						||
| 
								 | 
							
								from functools import wraps
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								import json
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								import multiprocessing
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import requests
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								import shutil
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								import time
							 | 
						||
| 
								 | 
							
								import threading
							 | 
						||
| 
								 | 
							
								import queue
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								from dataclasses import asdict, replace
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								from datetime import datetime, timedelta
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								from websocket import ABNF
							 | 
						||
| 
								 | 
							
								from websocket._exceptions import WebSocketConnectionClosedException
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								from cereal import messaging
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								from openpilot.common.params import Params
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								from openpilot.common.timeout import Timeout
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								from openpilot.system.athena import athenad
							 | 
						||
| 
								 | 
							
								from openpilot.system.athena.athenad import MAX_RETRY_COUNT, dispatcher
							 | 
						||
| 
								 | 
							
								from openpilot.system.athena.tests.helpers import HTTPRequestHandler, MockWebsocket, MockApi, EchoSocket
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								from openpilot.selfdrive.test.helpers import http_server_context
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								from openpilot.system.hardware.hw import Paths
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def seed_athena_server(host, port):
							 | 
						||
| 
								 | 
							
								  with Timeout(2, 'HTTP Server seeding failed'):
							 | 
						||
| 
								 | 
							
								    while True:
							 | 
						||
| 
								 | 
							
								      try:
							 | 
						||
| 
								 | 
							
								        requests.put(f'http://{host}:{port}/qlog.bz2', data='', timeout=10)
							 | 
						||
| 
								 | 
							
								        break
							 | 
						||
| 
								 | 
							
								      except requests.exceptions.ConnectionError:
							 | 
						||
| 
								 | 
							
								        time.sleep(0.1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								def with_upload_handler(func):
							 | 
						||
| 
								 | 
							
								  @wraps(func)
							 | 
						||
| 
								 | 
							
								  def wrapper(*args, **kwargs):
							 | 
						||
| 
								 | 
							
								    end_event = threading.Event()
							 | 
						||
| 
								 | 
							
								    thread = threading.Thread(target=athenad.upload_handler, args=(end_event,))
							 | 
						||
| 
								 | 
							
								    thread.start()
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								      return func(*args, **kwargs)
							 | 
						||
| 
								 | 
							
								    finally:
							 | 
						||
| 
								 | 
							
								      end_event.set()
							 | 
						||
| 
								 | 
							
								      thread.join()
							 | 
						||
| 
								 | 
							
								  return wrapper
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								@pytest.fixture
							 | 
						||
| 
								 | 
							
								def mock_create_connection(mocker):
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    return mocker.patch('openpilot.system.athena.athenad.create_connection')
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								@pytest.fixture
							 | 
						||
| 
								 | 
							
								def host():
							 | 
						||
| 
								 | 
							
								  with http_server_context(handler=HTTPRequestHandler, setup=seed_athena_server) as (host, port):
							 | 
						||
| 
								 | 
							
								    yield f"http://{host}:{port}"
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								class TestAthenadMethods:
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								  @classmethod
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def setup_class(cls):
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    cls.SOCKET_PORT = 45454
							 | 
						||
| 
								 | 
							
								    athenad.Api = MockApi
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    athenad.LOCAL_PORT_WHITELIST = {cls.SOCKET_PORT}
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def setup_method(self):
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    self.default_params = {
							 | 
						||
| 
								 | 
							
								      "DongleId": "0000000000000000",
							 | 
						||
| 
								 | 
							
								      "GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # noqa: E501
							 | 
						||
| 
								 | 
							
								      "GithubUsername": b"commaci",
							 | 
						||
| 
								 | 
							
								      "AthenadUploadQueue": '[]',
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    self.params = Params()
							 | 
						||
| 
								 | 
							
								    for k, v in self.default_params.items():
							 | 
						||
| 
								 | 
							
								      self.params.put(k, v)
							 | 
						||
| 
								 | 
							
								    self.params.put_bool("GsmMetered", True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    athenad.upload_queue = queue.Queue()
							 | 
						||
| 
								 | 
							
								    athenad.cur_upload_items.clear()
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    athenad.cancelled_uploads.clear()
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    for i in os.listdir(Paths.log_root()):
							 | 
						||
| 
								 | 
							
								      p = os.path.join(Paths.log_root(), i)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								      if os.path.isdir(p):
							 | 
						||
| 
								 | 
							
								        shutil.rmtree(p)
							 | 
						||
| 
								 | 
							
								      else:
							 | 
						||
| 
								 | 
							
								        os.unlink(p)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								  # *** test helpers ***
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  @staticmethod
							 | 
						||
| 
								 | 
							
								  def _wait_for_upload():
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    now = time.time()
							 | 
						||
| 
								 | 
							
								    while time.time() - now < 5:
							 | 
						||
| 
								 | 
							
								      if athenad.upload_queue.qsize() == 0:
							 | 
						||
| 
								 | 
							
								        break
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								  @staticmethod
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								  def _create_file(file: str, parent: str = None, data: bytes = b'') -> str:
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    fn = os.path.join(Paths.log_root() if parent is None else parent, file)
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    os.makedirs(os.path.dirname(fn), exist_ok=True)
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    with open(fn, 'wb') as f:
							 | 
						||
| 
								 | 
							
								      f.write(data)
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    return fn
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # *** test cases ***
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								  def test_echo(self):
							 | 
						||
| 
								 | 
							
								    assert dispatcher["echo"]("bob") == "bob"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_get_message(self):
							 | 
						||
| 
								 | 
							
								    with pytest.raises(TimeoutError) as _:
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								      dispatcher["getMessage"]("controlsState")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    end_event = multiprocessing.Event()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    pub_sock = messaging.pub_sock("deviceState")
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    def send_deviceState():
							 | 
						||
| 
								 | 
							
								      while not end_event.is_set():
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								        msg = messaging.new_message('deviceState')
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								        pub_sock.send(msg.to_bytes())
							 | 
						||
| 
								 | 
							
								        time.sleep(0.01)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    p = multiprocessing.Process(target=send_deviceState)
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    p.start()
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    time.sleep(0.1)
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    try:
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								      deviceState = dispatcher["getMessage"]("deviceState")
							 | 
						||
| 
								 | 
							
								      assert deviceState['deviceState']
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    finally:
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								      end_event.set()
							 | 
						||
| 
								 | 
							
								      p.join()
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_list_data_directory(self):
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    route = '2021-03-29--13-32-47'
							 | 
						||
| 
								 | 
							
								    segments = [0, 1, 2, 3, 11]
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    filenames = ['qlog', 'qcamera.ts', 'rlog', 'fcamera.hevc', 'ecamera.hevc', 'dcamera.hevc']
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    files = [f'{route}--{s}/{f}' for s in segments for f in filenames]
							 | 
						||
| 
								 | 
							
								    for file in files:
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								      self._create_file(file)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    resp = dispatcher["listDataDirectory"]()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp, 'list empty!'
							 | 
						||
| 
								 | 
							
								    assert len(resp) == len(files)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    resp = dispatcher["listDataDirectory"](f'{route}--123')
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert len(resp) == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    prefix = f'{route}'
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    expected = list(filter(lambda f: f.startswith(prefix), files))
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    resp = dispatcher["listDataDirectory"](prefix)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp, 'list empty!'
							 | 
						||
| 
								 | 
							
								    assert len(resp) == len(expected)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    prefix = f'{route}--1'
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    expected = list(filter(lambda f: f.startswith(prefix), files))
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    resp = dispatcher["listDataDirectory"](prefix)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp, 'list empty!'
							 | 
						||
| 
								 | 
							
								    assert len(resp) == len(expected)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    prefix = f'{route}--1/'
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    expected = list(filter(lambda f: f.startswith(prefix), files))
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    resp = dispatcher["listDataDirectory"](prefix)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp, 'list empty!'
							 | 
						||
| 
								 | 
							
								    assert len(resp) == len(expected)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    prefix = f'{route}--1/q'
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    expected = list(filter(lambda f: f.startswith(prefix), files))
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    resp = dispatcher["listDataDirectory"](prefix)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp, 'list empty!'
							 | 
						||
| 
								 | 
							
								    assert len(resp) == len(expected)
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								  def test_strip_bz2_extension(self):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    fn = self._create_file('qlog.bz2')
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    if fn.endswith('.bz2'):
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert athenad.strip_bz2_extension(fn) == fn[:-4]
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  @pytest.mark.parametrize("compress", [True, False])
							 | 
						||
| 
								 | 
							
								  def test_do_upload(self, host, compress):
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    # random bytes to ensure rather large object post-compression
							 | 
						||
| 
								 | 
							
								    fn = self._create_file('qlog', data=os.urandom(10000 * 1024))
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    upload_fn = fn + ('.bz2' if compress else '')
							 | 
						||
| 
								 | 
							
								    item = athenad.UploadItem(path=upload_fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='')
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    with pytest.raises(requests.exceptions.ConnectionError):
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								      athenad._do_upload(item)
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    item = athenad.UploadItem(path=upload_fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='')
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    resp = athenad._do_upload(item)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp.status_code == 201
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_upload_file_to_url(self, host):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    fn = self._create_file('qlog.bz2')
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {})
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp['enqueued'] == 1
							 | 
						||
| 
								 | 
							
								    assert 'failed' not in resp
							 | 
						||
| 
								 | 
							
								    assert {"path": fn, "url": f"{host}/qlog.bz2", "headers": {}}.items() <= resp['items'][0].items()
							 | 
						||
| 
								 | 
							
								    assert resp['items'][0].get('id') is not None
							 | 
						||
| 
								 | 
							
								    assert athenad.upload_queue.qsize() == 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  def test_upload_file_to_url_duplicate(self, host):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    self._create_file('qlog.bz2')
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    url1 = f"{host}/qlog.bz2?sig=sig1"
							 | 
						||
| 
								 | 
							
								    dispatcher["uploadFileToUrl"]("qlog.bz2", url1, {})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Upload same file again, but with different signature
							 | 
						||
| 
								 | 
							
								    url2 = f"{host}/qlog.bz2?sig=sig2"
							 | 
						||
| 
								 | 
							
								    resp = dispatcher["uploadFileToUrl"]("qlog.bz2", url2, {})
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert resp == {'enqueued': 0, 'items': []}
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_upload_file_to_url_does_not_exist(self, host):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    not_exists_resp = dispatcher["uploadFileToUrl"]("does_not_exist.bz2", "http://localhost:1238", {})
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert not_exists_resp == {'enqueued': 0, 'items': [], 'failed': ['does_not_exist.bz2']}
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								  @with_upload_handler
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								  def test_upload_handler(self, host):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    fn = self._create_file('qlog.bz2')
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    athenad.upload_queue.put_nowait(item)
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    self._wait_for_upload()
							 | 
						||
| 
								 | 
							
								    time.sleep(0.1)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    # TODO: verify that upload actually succeeded
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    # TODO: also check that end_event and metered network raises AbortTransferException
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert athenad.upload_queue.qsize() == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  @pytest.mark.parametrize("status,retry", [(500,True), (412,False)])
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								  @with_upload_handler
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_upload_handler_retry(self, mocker, host, status, retry):
							 | 
						||
| 
								 | 
							
								    mock_put = mocker.patch('requests.put')
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    mock_put.return_value.status_code = status
							 | 
						||
| 
								 | 
							
								    fn = self._create_file('qlog.bz2')
							 | 
						||
| 
								 | 
							
								    item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    athenad.upload_queue.put_nowait(item)
							 | 
						||
| 
								 | 
							
								    self._wait_for_upload()
							 | 
						||
| 
								 | 
							
								    time.sleep(0.1)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert athenad.upload_queue.qsize() == (1 if retry else 0)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    if retry:
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert athenad.upload_queue.get().retry_count == 1
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								  @with_upload_handler
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								  def test_upload_handler_timeout(self):
							 | 
						||
| 
								 | 
							
								    """When an upload times out or fails to connect it should be placed back in the queue"""
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    fn = self._create_file('qlog.bz2')
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    item_no_retry = replace(item, retry_count=MAX_RETRY_COUNT)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    athenad.upload_queue.put_nowait(item_no_retry)
							 | 
						||
| 
								 | 
							
								    self._wait_for_upload()
							 | 
						||
| 
								 | 
							
								    time.sleep(0.1)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    # Check that upload with retry count exceeded is not put back
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert athenad.upload_queue.qsize() == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    athenad.upload_queue.put_nowait(item)
							 | 
						||
| 
								 | 
							
								    self._wait_for_upload()
							 | 
						||
| 
								 | 
							
								    time.sleep(0.1)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    # Check that upload item was put back in the queue with incremented retry count
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert athenad.upload_queue.qsize() == 1
							 | 
						||
| 
								 | 
							
								    assert athenad.upload_queue.get().retry_count == 1
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								  @with_upload_handler
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_cancel_upload(self):
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    item = athenad.UploadItem(path="qlog.bz2", url="http://localhost:44444/qlog.bz2", headers={},
							 | 
						||
| 
								 | 
							
								                              created_at=int(time.time()*1000), id='id', allow_cellular=True)
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    athenad.upload_queue.put_nowait(item)
							 | 
						||
| 
								 | 
							
								    dispatcher["cancelUpload"](item.id)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert item.id in athenad.cancelled_uploads
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    self._wait_for_upload()
							 | 
						||
| 
								 | 
							
								    time.sleep(0.1)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert athenad.upload_queue.qsize() == 0
							 | 
						||
| 
								 | 
							
								    assert len(athenad.cancelled_uploads) == 0
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								  @with_upload_handler
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_cancel_expiry(self):
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    t_future = datetime.now() - timedelta(days=40)
							 | 
						||
| 
								 | 
							
								    ts = int(t_future.strftime("%s")) * 1000
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Item that would time out if actually uploaded
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    fn = self._create_file('qlog.bz2')
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=ts, id='', allow_cellular=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    athenad.upload_queue.put_nowait(item)
							 | 
						||
| 
								 | 
							
								    self._wait_for_upload()
							 | 
						||
| 
								 | 
							
								    time.sleep(0.1)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert athenad.upload_queue.qsize() == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_list_upload_queue_empty(self):
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    items = dispatcher["listUploadQueue"]()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert len(items) == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								  @with_upload_handler
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_list_upload_queue_current(self, host: str):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    fn = self._create_file('qlog.bz2')
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    athenad.upload_queue.put_nowait(item)
							 | 
						||
| 
								 | 
							
								    self._wait_for_upload()
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    items = dispatcher["listUploadQueue"]()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert len(items) == 1
							 | 
						||
| 
								 | 
							
								    assert items[0]['current']
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_list_upload_queue(self):
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								    item = athenad.UploadItem(path="qlog.bz2", url="http://localhost:44444/qlog.bz2", headers={},
							 | 
						||
| 
								 | 
							
								                              created_at=int(time.time()*1000), id='id', allow_cellular=True)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    athenad.upload_queue.put_nowait(item)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    items = dispatcher["listUploadQueue"]()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert len(items) == 1
							 | 
						||
| 
								 | 
							
								    assert items[0] == asdict(item)
							 | 
						||
| 
								 | 
							
								    assert not items[0]['current']
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								    athenad.cancelled_uploads.add(item.id)
							 | 
						||
| 
								 | 
							
								    items = dispatcher["listUploadQueue"]()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert len(items) == 0
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								  def test_upload_queue_persistence(self):
							 | 
						||
| 
								 | 
							
								    item1 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id1')
							 | 
						||
| 
								 | 
							
								    item2 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id2')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    athenad.upload_queue.put_nowait(item1)
							 | 
						||
| 
								 | 
							
								    athenad.upload_queue.put_nowait(item2)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Ensure cancelled items are not persisted
							 | 
						||
| 
								 | 
							
								    athenad.cancelled_uploads.add(item2.id)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # serialize item
							 | 
						||
| 
								 | 
							
								    athenad.UploadQueueCache.cache(athenad.upload_queue)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # deserialize item
							 | 
						||
| 
								 | 
							
								    athenad.upload_queue.queue.clear()
							 | 
						||
| 
								 | 
							
								    athenad.UploadQueueCache.initialize(athenad.upload_queue)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert athenad.upload_queue.qsize() == 1
							 | 
						||
| 
								 | 
							
								    assert asdict(athenad.upload_queue.queue[-1]) == asdict(item1)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_start_local_proxy(self, mock_create_connection):
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    end_event = threading.Event()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ws_recv = queue.Queue()
							 | 
						||
| 
								 | 
							
								    ws_send = queue.Queue()
							 | 
						||
| 
								 | 
							
								    mock_ws = MockWebsocket(ws_recv, ws_send)
							 | 
						||
| 
								 | 
							
								    mock_create_connection.return_value = mock_ws
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    echo_socket = EchoSocket(self.SOCKET_PORT)
							 | 
						||
| 
								 | 
							
								    socket_thread = threading.Thread(target=echo_socket.run)
							 | 
						||
| 
								 | 
							
								    socket_thread.start()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    athenad.startLocalProxy(end_event, 'ws://localhost:1234', self.SOCKET_PORT)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    ws_recv.put_nowait(b'ping')
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								      recv = ws_send.get(timeout=5)
							 | 
						||
| 
								 | 
							
								      assert recv == (b'ping', ABNF.OPCODE_BINARY), recv
							 | 
						||
| 
								 | 
							
								    finally:
							 | 
						||
| 
								 | 
							
								      # signal websocket close to athenad.ws_proxy_recv
							 | 
						||
| 
								 | 
							
								      ws_recv.put_nowait(WebSocketConnectionClosedException())
							 | 
						||
| 
								 | 
							
								      socket_thread.join()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_get_ssh_authorized_keys(self):
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    keys = dispatcher["getSshAuthorizedKeys"]()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert keys == self.default_params["GithubSshKeys"].decode('utf-8')
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_get_github_username(self):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								    keys = dispatcher["getGithubUsername"]()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert keys == self.default_params["GithubUsername"].decode('utf-8')
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								  def test_get_version(self):
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								    resp = dispatcher["getVersion"]()
							 | 
						||
| 
								 | 
							
								    keys = ["version", "remote", "branch", "commit"]
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert list(resp.keys()) == keys
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								    for k in keys:
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert isinstance(resp[k], str), f"{k} is not a string"
							 | 
						||
| 
								 | 
							
								      assert len(resp[k]) > 0, f"{k} has no value"
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								  def test_jsonrpc_handler(self):
							 | 
						||
| 
								 | 
							
								    end_event = threading.Event()
							 | 
						||
| 
								 | 
							
								    thread = threading.Thread(target=athenad.jsonrpc_handler, args=(end_event,))
							 | 
						||
| 
								 | 
							
								    thread.daemon = True
							 | 
						||
| 
								 | 
							
								    thread.start()
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								      # with params
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								      athenad.recv_queue.put_nowait(json.dumps({"method": "echo", "params": ["hello"], "jsonrpc": "2.0", "id": 0}))
							 | 
						||
| 
								 | 
							
								      resp = athenad.send_queue.get(timeout=3)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert json.loads(resp) == {'result': 'hello', 'id': 0, 'jsonrpc': '2.0'}
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								      # without params
							 | 
						||
| 
								 | 
							
								      athenad.recv_queue.put_nowait(json.dumps({"method": "getNetworkType", "jsonrpc": "2.0", "id": 0}))
							 | 
						||
| 
								 | 
							
								      resp = athenad.send_queue.get(timeout=3)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert json.loads(resp) == {'result': 1, 'id': 0, 'jsonrpc': '2.0'}
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								      # log forwarding
							 | 
						||
| 
								 
											5 years ago
										 
									 | 
							
								      athenad.recv_queue.put_nowait(json.dumps({'result': {'success': 1}, 'id': 0, 'jsonrpc': '2.0'}))
							 | 
						||
| 
								 | 
							
								      resp = athenad.log_recv_queue.get(timeout=3)
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								      assert json.loads(resp) == {'result': {'success': 1}, 'id': 0, 'jsonrpc': '2.0'}
							 | 
						||
| 
								 
											6 years ago
										 
									 | 
							
								    finally:
							 | 
						||
| 
								 | 
							
								      end_event.set()
							 | 
						||
| 
								 | 
							
								      thread.join()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								  def test_get_logs_to_send_sorted(self):
							 | 
						||
| 
								 | 
							
								    fl = list()
							 | 
						||
| 
								 | 
							
								    for i in range(10):
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								      file = f'swaglog.{i:010}'
							 | 
						||
| 
								 
											2 years ago
										 
									 | 
							
								      self._create_file(file, Paths.swaglog_root())
							 | 
						||
| 
								 
											3 years ago
										 
									 | 
							
								      fl.append(file)
							 | 
						||
| 
								 
											4 years ago
										 
									 | 
							
								
							 | 
						||
| 
								 | 
							
								    # ensure the list is all logs except most recent
							 | 
						||
| 
								 | 
							
								    sl = athenad.get_logs_to_send_sorted()
							 | 
						||
| 
								 
											1 year ago
										 
									 | 
							
								    assert sl == fl[:-1]
							 |