|
|
@@ -39,7 +39,7 @@ from starlette.status import HTTP_200_OK |
|
|
|
from starlette.status import HTTP_400_BAD_REQUEST, HTTP_401_UNAUTHORIZED, \ |
|
|
|
HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND, HTTP_409_CONFLICT |
|
|
|
from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR |
|
|
|
from unittest.mock import patch, AsyncMock, Mock, PropertyMock |
|
|
|
from unittest.mock import create_autospec, patch, AsyncMock, Mock, PropertyMock |
|
|
|
|
|
|
|
from . import config |
|
|
|
from .data import * |
|
|
@@ -76,6 +76,18 @@ tcp_server.parse_socket_addr = new_parse_socket_addr |
|
|
|
class SerialConsole(DefROAttribute): |
|
|
|
defattrname = 'console' |
|
|
|
|
|
|
|
async def activate(self, brd): |
|
|
|
cmd = ('devfs', '-m', brd.attrs['devfspath'], 'rule', 'apply', |
|
|
|
'path', os.path.basename(self._value), 'unhide', ) |
|
|
|
sub = await asyncio.create_subprocess_exec(*cmd, |
|
|
|
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, |
|
|
|
stderr=subprocess.DEVNULL) |
|
|
|
|
|
|
|
ret = await sub.wait() |
|
|
|
|
|
|
|
if ret: |
|
|
|
raise RuntimeError('activate failed: %d' % ret) |
|
|
|
|
|
|
|
class BoardImpl: |
|
|
|
def __init__(self, name, brdclass, options): |
|
|
|
self.name = name |
|
|
@@ -110,6 +122,14 @@ class BoardImpl: |
|
|
|
for i in self.attrmap: |
|
|
|
self.attrcache[i] = await self.attrmap[i].getvalue() |
|
|
|
|
|
|
|
async def activate(self): |
|
|
|
for i in self.options: |
|
|
|
await i.activate(self) |
|
|
|
|
|
|
|
async def deactivate(self): |
|
|
|
for i in self.options: |
|
|
|
await i.deactivate(self) |
|
|
|
|
|
|
|
def add_info(self, d): |
|
|
|
self.attrcache.update(d) |
|
|
|
|
|
|
@@ -353,8 +373,6 @@ async def reserve_board(board_id_or_class, |
|
|
|
stdout, stderr = await sub.communicate() |
|
|
|
if sub.returncode: |
|
|
|
raise RuntimeError(sub.returncode, stderr) |
|
|
|
|
|
|
|
brd.add_info(json.loads(stdout)) |
|
|
|
except Exception as e: |
|
|
|
await brdreq.delete() |
|
|
|
await brd.release() |
|
|
@@ -369,6 +387,10 @@ async def reserve_board(board_id_or_class, |
|
|
|
) |
|
|
|
raise |
|
|
|
|
|
|
|
brd.add_info(json.loads(stdout)) |
|
|
|
|
|
|
|
await brd.activate() |
|
|
|
|
|
|
|
await brd.update() |
|
|
|
|
|
|
|
return brd |
|
|
@@ -615,9 +637,10 @@ class TestBiteLab(unittest.IsolatedAsyncioTestCase): |
|
|
|
# and that the error got logged |
|
|
|
le.assert_called_with('release script failure: board: \'cora-1\', ret: 1, stderr: b\'error\'') |
|
|
|
|
|
|
|
@patch('bitelab.BoardImpl.activate') |
|
|
|
@patch('asyncio.create_subprocess_exec') |
|
|
|
@patch('bitelab.snmp.snmpget') |
|
|
|
async def test_board_reserve_release(self, sg, cse): |
|
|
|
async def test_board_reserve_release(self, sg, cse, biact): |
|
|
|
# that when releasing a board that is not yet reserved |
|
|
|
res = await self.client.post('/board/cora-1/release', |
|
|
|
auth=BiteAuth('anotherlongapikey')) |
|
|
@@ -685,6 +708,9 @@ class TestBiteLab(unittest.IsolatedAsyncioTestCase): |
|
|
|
cse.assert_called_with(self.settings.setup_script, 'reserve', |
|
|
|
'cora-1', 'foo', 'pubsshkey', stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
|
|
|
|
|
|
|
# and that the board was activated |
|
|
|
biact.assert_called() |
|
|
|
|
|
|
|
# that another user reserving the board |
|
|
|
res = await self.client.post('/board/cora-1/reserve', |
|
|
|
auth=BiteAuth('anotherlongapikey')) |
|
|
@@ -875,8 +901,28 @@ class TestBiteLab(unittest.IsolatedAsyncioTestCase): |
|
|
|
} |
|
|
|
self.assertEqual(res.json(), info) |
|
|
|
|
|
|
|
class TestBoardImpl(unittest.IsolatedAsyncioTestCase): |
|
|
|
async def test_activate(self): |
|
|
|
# that a board impl |
|
|
|
opt = create_autospec(Attribute) |
|
|
|
brd = BoardImpl('foo', 'bar', [ opt ]) |
|
|
|
|
|
|
|
await brd.activate() |
|
|
|
|
|
|
|
opt.activate.assert_called_with(brd) |
|
|
|
|
|
|
|
async def test_deactivate(self): |
|
|
|
# that a board impl |
|
|
|
opt = create_autospec(Attribute) |
|
|
|
brd = BoardImpl('foo', 'bar', [ opt ]) |
|
|
|
|
|
|
|
await brd.deactivate() |
|
|
|
|
|
|
|
opt.deactivate.assert_called_with(brd) |
|
|
|
|
|
|
|
class TestAttrs(unittest.IsolatedAsyncioTestCase): |
|
|
|
async def test_serialconsole(self): |
|
|
|
@patch('asyncio.create_subprocess_exec') |
|
|
|
async def test_serialconsole(self, cse): |
|
|
|
data = 'somepath' |
|
|
|
sc = SerialConsole(data) |
|
|
|
|
|
|
@@ -886,3 +932,22 @@ class TestAttrs(unittest.IsolatedAsyncioTestCase): |
|
|
|
|
|
|
|
with self.assertRaises(TypeError): |
|
|
|
await sc.setvalue(data) |
|
|
|
|
|
|
|
devfspath = 'eifd' |
|
|
|
|
|
|
|
brd = BoardImpl('foo', 'bar', [ sc ]) |
|
|
|
brd.add_info(dict(devfspath=devfspath)) |
|
|
|
|
|
|
|
wrap_subprocess_exec(cse, retcode=0) |
|
|
|
|
|
|
|
await sc.activate(brd) |
|
|
|
|
|
|
|
cse.assert_called_with('devfs', '-m', devfspath, 'rule', |
|
|
|
'apply', 'path', os.path.basename(await sc.getvalue()), |
|
|
|
'unhide', |
|
|
|
stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, |
|
|
|
stderr=subprocess.DEVNULL) |
|
|
|
|
|
|
|
wrap_subprocess_exec(cse, retcode=1) |
|
|
|
with self.assertRaises(RuntimeError): |
|
|
|
await sc.activate(brd) |