Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion framework/python/src/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,10 @@ async def get_sys_config(self):
return self._session.get_config()

async def get_devices(self):
return self._session.get_device_repository()
devices = []
for device in self._session.get_device_repository():
devices.append(device.to_dict())
return devices

async def start_test_run(self, request: Request, response: Response):

Expand Down
12 changes: 12 additions & 0 deletions framework/python/src/common/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@
class Device():
"""Represents a physical device and it's configuration."""

status: str = 'Valid'
folder_url: str = None
mac_addr: str = None
manufacturer: str = None
model: str = None
type: str = None
technology: str = None
test_pack: str = 'Device Qualification'
test_modules: Dict = field(default_factory=dict)
ip_addr: str = None
firmware: str = None
Expand Down Expand Up @@ -54,9 +58,13 @@ def to_dict(self):
"""Returns the device as a python dictionary. This is used for the
system status API endpoint and in the report."""
device_json = {}
device_json['status'] = self.status
device_json['mac_addr'] = self.mac_addr
device_json['manufacturer'] = self.manufacturer
device_json['model'] = self.model
device_json['type'] = self.type
device_json['technology'] = self.technology
device_json['test_pack'] = self.test_pack
if self.firmware is not None:
device_json['firmware'] = self.firmware
device_json['test_modules'] = self.test_modules
Expand All @@ -66,8 +74,12 @@ def to_config_json(self):
"""Returns the device as a python dictionary. Fields relevant to the device
config json file are exported."""
device_json = {}
device_json['status'] = self.status
device_json['mac_addr'] = self.mac_addr
device_json['manufacturer'] = self.manufacturer
device_json['model'] = self.model
device_json['type'] = self.type
device_json['technology'] = self.technology
device_json['test_pack'] = self.test_pack
device_json['test_modules'] = self.test_modules
return device_json
9 changes: 8 additions & 1 deletion framework/python/src/common/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
API_URL_KEY = 'api_url'
API_PORT_KEY = 'api_port'
MAX_DEVICE_REPORTS_KEY = 'max_device_reports'
ORG_NAME_KEY = 'org_name'
CERTS_PATH = 'local/root_certs'
CONFIG_FILE_PATH = 'local/system.json'
STATUS_TOPIC = 'status'
Expand Down Expand Up @@ -184,7 +185,8 @@ def _get_default_config(self):
'monitor_period': 30,
'max_device_reports': 0,
'api_url': 'http://localhost',
'api_port': 8000
'api_port': 8000,
'org_name': ''
}

def get_config(self):
Expand Down Expand Up @@ -231,6 +233,11 @@ def _load_config(self):
self._config[MAX_DEVICE_REPORTS_KEY] = config_file_json.get(
MAX_DEVICE_REPORTS_KEY)

if ORG_NAME_KEY in config_file_json:
self._config[ORG_NAME_KEY] = config_file_json.get(
ORG_NAME_KEY
)

LOGGER.debug(self._config)

def _load_version(self):
Expand Down
23 changes: 22 additions & 1 deletion framework/python/src/core/testrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
DEVICE_MODEL = 'model'
DEVICE_MAC_ADDR = 'mac_addr'
DEVICE_TEST_MODULES = 'test_modules'
DEVICE_TYPE_KEY = 'type'
DEVICE_TECHNOLOGY_KEY = 'technology'
DEVICE_TEST_PACK_KEY = 'test_pack'

MAX_DEVICE_REPORTS_KEY = 'max_device_reports'

class Testrun: # pylint: disable=too-few-public-methods
Expand Down Expand Up @@ -166,7 +170,7 @@ def _load_devices(self, device_dir):
# Check if device config file exists before loading
if not os.path.exists(device_config_file_path):
LOGGER.error('Device configuration file missing ' +
f'from device {device_folder}')
f'for device {device_folder}')
continue

# Open device config file
Expand All @@ -178,6 +182,8 @@ def _load_devices(self, device_dir):
device_model = device_config_json.get(DEVICE_MODEL)
mac_addr = device_config_json.get(DEVICE_MAC_ADDR)
test_modules = device_config_json.get(DEVICE_TEST_MODULES)

# Load max device reports
max_device_reports = None
if 'max_device_reports' in device_config_json:
max_device_reports = device_config_json.get(MAX_DEVICE_REPORTS_KEY)
Expand All @@ -192,6 +198,21 @@ def _load_devices(self, device_dir):
max_device_reports=max_device_reports,
device_folder=device_folder)

# Load in the additional fields
if DEVICE_TYPE_KEY in device_config_json:
device.type = device_config_json.get(DEVICE_TYPE_KEY)

if DEVICE_TECHNOLOGY_KEY in device_config_json:
device.technology = device_config_json.get(DEVICE_TECHNOLOGY_KEY)

if DEVICE_TEST_PACK_KEY in device_config_json:
device.test_pack = device_config_json.get(DEVICE_TEST_PACK_KEY)

if None in [device.type, device.technology, device.test_pack]:
LOGGER.warning(
'Device is outdated and requires further configuration')
device.status = 'Invalid'

self._load_test_reports(device)

# Add device to device repository
Expand Down
22 changes: 12 additions & 10 deletions framework/python/src/test_orc/test_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ def __init__(self, session, net_orc):
str(self._session.get_api_port()))
self._net_orc = net_orc
self._test_in_progress = False
self._path = os.path.dirname(
os.path.dirname(
os.path.dirname(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))))))

self._root_path = os.path.dirname(
os.path.dirname(
Expand Down Expand Up @@ -89,18 +85,23 @@ def run_test_modules(self):

device = self._session.get_target_device()
self._test_in_progress = True

LOGGER.info(
f"Running test modules on device with mac addr {device.mac_addr}")

test_modules = []

for module in self._test_modules:

# Ignore test modules that are just base images etc
if module is None or not module.enable_container:
continue

# Ignore test modules that are disabled for this device
if not self._is_module_enabled(module, device):
continue

# Add module to list of modules to run
test_modules.append(module)

for test in module.tests:
Expand Down Expand Up @@ -490,13 +491,14 @@ def _run_test_module(self, module):

LOGGER.info(f"Test module {module.name} has finished")

# Resolve all current log data in the containers log_stream
# this method is blocking so should be called in
# a thread or within a proper blocking context
def _get_container_logs(self, log_stream):
"""Resolve all current log data in the containers log_stream
this method is blocking so should be called in
a thread or within a proper blocking context"""
self._container_logs = []
for log_chunk in log_stream:
lines = log_chunk.decode("utf-8").splitlines()

# Process each line and strip blank space
processed_lines = [line.strip() for line in lines if line.strip()]
self._container_logs.extend(processed_lines)
Expand Down Expand Up @@ -535,7 +537,7 @@ def _load_test_modules(self):
LOGGER.debug("Loading test modules from /" + TEST_MODULES_DIR)

loaded_modules = "Loaded the following test modules: "
test_modules_dir = os.path.join(self._path, TEST_MODULES_DIR)
test_modules_dir = os.path.join(self._root_path, TEST_MODULES_DIR)

module_dirs = os.listdir(test_modules_dir)
# Check if the directory protocol exists and move it to the beginning
Expand Down Expand Up @@ -570,9 +572,9 @@ def _load_test_module(self, module_dir):
if not any(m.dir_name == module_dir for m in self._test_modules):
LOGGER.debug(f"Loading test module {module_dir}")

modules_dir = os.path.join(self._path, TEST_MODULES_DIR)
modules_dir = os.path.join(self._root_path, TEST_MODULES_DIR)

module_conf_file = os.path.join(self._path, modules_dir, module_dir,
module_conf_file = os.path.join(self._root_path, modules_dir, module_dir,
MODULE_CONFIG)

module = TestModule(module_conf_file, self._session, extra_hosts)
Expand Down
2 changes: 1 addition & 1 deletion make/DEBIAN/control
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Package: Testrun
Version: 1.4.1-a
Version: 2.0-a
Architecture: amd64
Maintainer: Google <boddey@google.com>
Homepage: https://github.com/google/testrun
Expand Down
35 changes: 27 additions & 8 deletions modules/ui/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,7 @@
</ng-container>
<app-version
[consentShown]="vm.consentShown"
[hasRiskProfiles]="vm.hasRiskProfiles"
(consentShownEvent)="consentShown()"
(navigateToRiskAssessmentEvent)="
navigateToRiskAssessment()
"></app-version>
(consentShownEvent)="consentShown()"></app-version>
</div>
</mat-drawer>

Expand Down Expand Up @@ -179,9 +175,9 @@ <h1 class="main-heading">Testrun</h1>
*ngIf="vm.hasConnectionSettings === true && vm.hasDevices === false">
Step 2: To perform a device test please
<a
(click)="navigateToDeviceRepository()"
(keydown.enter)="navigateToDeviceRepository()"
(keydown.space)="navigateToDeviceRepository()"
(click)="navigateToAddDevice()"
(keydown.enter)="navigateToAddDevice()"
(keydown.space)="navigateToAddDevice()"
aria-label="The Create a Device link redirects to the Devices page and opens the dialogue there."
tabindex="0"
role="link"
Expand Down Expand Up @@ -235,6 +231,29 @@ <h1 class="main-heading">Testrun</h1>
>Risk Assessment questionnaire</a
>?
</app-callout>
<app-callout
id="outdated_devices_callout"
role="alert"
aria-live="assertive"
[closed]="!!vm.calloutState.get('outdated_devices_callout')"
[closable]="true"
[type]="CalloutType.Error"
(calloutClosed)="calloutClosed($event)"
*ngIf="vm.hasExpiredDevices">
Further information is required in your device configurations. Please
update your
<a
(click)="navigateToDeviceRepository()"
(keydown.enter)="navigateToDeviceRepository()"
(keydown.space)="navigateToDeviceRepository()"
aria-label="The Devices link redirects to the device repository page."
tabindex="0"
role="link"
class="message-link"
>Devices</a
>
to continue testing.
</app-callout>
<router-outlet></router-outlet>
</div>
</mat-drawer-content>
Expand Down
29 changes: 27 additions & 2 deletions modules/ui/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
selectError,
selectHasConnectionSettings,
selectHasDevices,
selectHasExpiredDevices,
selectHasRiskProfiles,
selectInterfaces,
selectInternetConnection,
Expand Down Expand Up @@ -168,6 +169,7 @@ describe('AppComponent', () => {
{ selector: selectError, value: null },
{ selector: selectMenuOpened, value: false },
{ selector: selectHasDevices, value: false },
{ selector: selectHasExpiredDevices, value: false },
{ selector: selectHasRiskProfiles, value: false },
{ selector: selectStatus, value: null },
{ selector: selectSystemStatus, value: null },
Expand Down Expand Up @@ -768,6 +770,31 @@ describe('AppComponent', () => {
});
});
});

describe('with expired devices', () => {
beforeEach(() => {
store.overrideSelector(selectHasExpiredDevices, true);
fixture.detectChanges();
});

it('should have callout component', () => {
const callouts = compiled.querySelectorAll('app-callout');
let hasExpiredDeviceCallout = false;
callouts.forEach(callout => {
if (
callout?.innerHTML
.trim()
.includes(
'Further information is required in your device configurations.'
)
) {
hasExpiredDeviceCallout = true;
}
});

expect(hasExpiredDeviceCallout).toBeTrue();
});
});
});

it('should not call toggleSettingsBtn focus on closeSetting when device length is 0', async () => {
Expand Down Expand Up @@ -836,7 +863,5 @@ class FakeShutdownAppComponent {
})
class FakeVersionComponent {
@Input() consentShown!: boolean;
@Input() hasRiskProfiles!: boolean;
@Output() consentShownEvent = new EventEmitter<void>();
@Output() navigateToRiskAssessmentEvent = new EventEmitter<void>();
}
9 changes: 9 additions & 0 deletions modules/ui/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ export class AppComponent {

navigateToDeviceRepository(): void {
this.route.navigate([Routes.Devices]);
}
navigateToAddDevice(): void {
this.route.navigate([Routes.Devices]);
this.store.dispatch(setIsOpenAddDevice({ isOpenAddDevice: true }));
}

Expand Down Expand Up @@ -207,4 +210,10 @@ export class AppComponent {
this.appStore.setFocusOnPage();
});
}

calloutClosed(id: string | null) {
if (id) {
this.appStore.setCloseCallout(id);
}
}
}
Loading