|
|
@@ -7,11 +7,13 @@ from httpx import AsyncClient, Auth |
|
|
|
from starlette.status import HTTP_200_OK, HTTP_404_NOT_FOUND, HTTP_401_UNAUTHORIZED |
|
|
|
|
|
|
|
from . import config |
|
|
|
from . import data |
|
|
|
|
|
|
|
import asyncio |
|
|
|
import gc |
|
|
|
import socket |
|
|
|
import sys |
|
|
|
import tempfile |
|
|
|
import unittest |
|
|
|
|
|
|
|
# fix up parse_socket_addr for hypercorn |
|
|
@@ -26,13 +28,26 @@ def new_parse_socket_addr(domain, addr): |
|
|
|
tcp_server.parse_socket_addr = new_parse_socket_addr |
|
|
|
|
|
|
|
class BoardManager(object): |
|
|
|
board_classes = [ 'cora-z7s' ] |
|
|
|
board_class_info = { |
|
|
|
'cora-z7s': { |
|
|
|
'arch': 'arm64-aarch64', |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
# Naming scheme: |
|
|
|
# <abbreviated class>-<num> |
|
|
|
# |
|
|
|
boards = { |
|
|
|
'cora-1': { |
|
|
|
'class': 'cora-z7s', |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
def __init__(self, settings): |
|
|
|
self._settings = settings |
|
|
|
|
|
|
|
def classes(self): |
|
|
|
return self.board_classes |
|
|
|
return self.board_class_info |
|
|
|
|
|
|
|
def unhashable_lru(): |
|
|
|
def newwrapper(fun): |
|
|
@@ -72,15 +87,22 @@ class BiteAuth(Auth): |
|
|
|
def get_settings(): |
|
|
|
return config.Settings() |
|
|
|
|
|
|
|
@unhashable_lru() |
|
|
|
def get_data(settings: config.Settings = Depends(get_settings)): |
|
|
|
print(repr(settings)) |
|
|
|
database = data.databases.Database('sqlite:///' + settings.db_file) |
|
|
|
d = data.make_orm(self.database) |
|
|
|
return d |
|
|
|
|
|
|
|
@unhashable_lru() |
|
|
|
def get_boardmanager(settings: config.Settings = Depends(get_settings)): |
|
|
|
return BoardManager(settings) |
|
|
|
|
|
|
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='/nonexistent') |
|
|
|
|
|
|
|
def lookup_user(token: str = Depends(oauth2_scheme), settings: config.Settings = Depends(get_settings)): |
|
|
|
async def lookup_user(token: str = Depends(oauth2_scheme), data: data.DataWrapper = Depends(get_data)): |
|
|
|
try: |
|
|
|
return settings.apikeytouser(token) |
|
|
|
return (await data.APIKey.objects.get(key=token)).user |
|
|
|
except KeyError: |
|
|
|
raise HTTPException( |
|
|
|
status_code=status.HTTP_401_UNAUTHORIZED, |
|
|
@@ -101,7 +123,7 @@ async def foo(user: str = Depends(lookup_user), brdmgr: BoardManager = Depends(g |
|
|
|
|
|
|
|
@router.get('/board_info') |
|
|
|
async def foo(user: str = Depends(lookup_user), brdmgr: BoardManager = Depends(get_boardmanager)): |
|
|
|
return brdmgr.classes() |
|
|
|
return brdmgr.boards |
|
|
|
|
|
|
|
@router.get('/') |
|
|
|
async def foo(board_prio: dict = Depends(board_priority), settings: config.Settings = Depends(get_settings)): |
|
|
@@ -141,18 +163,37 @@ class TestUnhashLRU(unittest.TestCase): |
|
|
|
# does not return the same object as the first cache |
|
|
|
self.assertIsNot(cachefun(lsta), cachefun2(lsta)) |
|
|
|
|
|
|
|
async def _setup_data(data): |
|
|
|
await data.APIKey.objects.create(user='foo', key='thisisanapikey') |
|
|
|
await data.APIKey.objects.create(user='bar', key='anotherlongapikey') |
|
|
|
|
|
|
|
# Note: this will not work under python before 3.8 before |
|
|
|
# IsolatedAsyncioTestCase was added. The tearDown has to happen |
|
|
|
# with the event loop running, otherwise the task and other things |
|
|
|
# do not get cleaned up properly. |
|
|
|
class TestBiteLab(unittest.IsolatedAsyncioTestCase): |
|
|
|
async def get_settings_override(self): |
|
|
|
# Note: this gets run on each request. |
|
|
|
return config.Settings(apikeyfile="fixtures/api_keys") |
|
|
|
def get_settings_override(self): |
|
|
|
return self.settings |
|
|
|
|
|
|
|
def setUp(self): |
|
|
|
def get_data_override(self): |
|
|
|
return self.data |
|
|
|
|
|
|
|
async def asyncSetUp(self): |
|
|
|
self.app = getApp() |
|
|
|
|
|
|
|
# setup test database |
|
|
|
self.dbtempfile = tempfile.NamedTemporaryFile() |
|
|
|
self.database = data.databases.Database('sqlite:///' + self.dbtempfile.name) |
|
|
|
self.data = data.make_orm(self.database) |
|
|
|
|
|
|
|
await _setup_data(self.data) |
|
|
|
|
|
|
|
# setup settings |
|
|
|
self.settings = config.Settings(db_file=self.dbtempfile.name) |
|
|
|
|
|
|
|
self.app.dependency_overrides[get_settings] = self.get_settings_override |
|
|
|
self.app.dependency_overrides[get_data] = self.get_data_override |
|
|
|
|
|
|
|
self.client = AsyncClient(app=self.app, base_url='http://testserver') |
|
|
|
|
|
|
|
def tearDown(self): |
|
|
@@ -160,11 +201,6 @@ class TestBiteLab(unittest.IsolatedAsyncioTestCase): |
|
|
|
asyncio.run(self.client.aclose()) |
|
|
|
self.client = None |
|
|
|
|
|
|
|
async def test_config(self): |
|
|
|
settings = await self.get_settings_override() |
|
|
|
self.assertEqual(settings.apikeytouser('thisisanapikey'), 'foo') |
|
|
|
self.assertEqual(settings.apikeytouser('anotherlongapikey'), 'bar') |
|
|
|
|
|
|
|
async def test_basic(self): |
|
|
|
res = await self.client.get('/') |
|
|
|
self.assertNotEqual(res.status_code, HTTP_404_NOT_FOUND) |
|
|
@@ -180,4 +216,34 @@ class TestBiteLab(unittest.IsolatedAsyncioTestCase): |
|
|
|
async def test_classes(self): |
|
|
|
res = await self.client.get('/board_classes', auth=BiteAuth('thisisanapikey')) |
|
|
|
self.assertEqual(res.status_code, HTTP_200_OK) |
|
|
|
self.assertEqual(res.json(), [ 'cora-z7s' ]) |
|
|
|
self.assertEqual(res.json(), { 'cora-z7s': { 'arch': 'arm64-aarch64', } }) |
|
|
|
|
|
|
|
async def test_board_info(self): |
|
|
|
res = await self.client.get('/board_info', auth=BiteAuth('thisisanapikey')) |
|
|
|
self.assertEqual(res.status_code, HTTP_200_OK) |
|
|
|
info = { |
|
|
|
'cora-1': { |
|
|
|
'class': 'cora-z7s', |
|
|
|
}, |
|
|
|
} |
|
|
|
self.assertEqual(res.json(), info) |
|
|
|
|
|
|
|
class TestData(unittest.IsolatedAsyncioTestCase): |
|
|
|
def setUp(self): |
|
|
|
# setup temporary directory |
|
|
|
self.dbtempfile = tempfile.NamedTemporaryFile() |
|
|
|
|
|
|
|
self.database = data.databases.Database('sqlite:///' + self.dbtempfile.name) |
|
|
|
self.data = data.make_orm(self.database) |
|
|
|
|
|
|
|
def tearDown(self): |
|
|
|
self.data = None |
|
|
|
self.database = None |
|
|
|
self.dbtempfile = None |
|
|
|
|
|
|
|
async def test_apikey(self): |
|
|
|
data = self.data |
|
|
|
self.assertEqual(await data.APIKey.objects.all(), []) |
|
|
|
await _setup_data(data) |
|
|
|
self.assertEqual((await data.APIKey.objects.get(key='thisisanapikey')).user, 'foo') |
|
|
|
self.assertEqual((await data.APIKey.objects.get(key='anotherlongapikey')).user, 'bar') |