mbed-os/tools/python/mbed_os_tools/test/tests_spec.py

359 lines
9.5 KiB
Python

# Copyright (c) 2018, Arm Limited and affiliates.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module contains classes to represent Test Specification interface that
defines the data to be generated by/from a build system to give enough information
to Greentea.
"""
import json
class TestBinary(object):
"""
Class representing a Test Binary.
"""
KW_BIN_TYPE = "binary_type"
KW_BIN_PATH = "path"
KW_COMP_LOG = "compare_log"
BIN_TYPE_BOOTABLE = "bootable"
BIN_TYPE_DEFAULT = BIN_TYPE_BOOTABLE
SUPPORTED_BIN_TYPES = [BIN_TYPE_BOOTABLE]
def __init__(self, path, binary_type, compare_log):
"""
ctor.
:param path:
:param binary_type:
:return:
"""
assert binary_type in TestBinary.SUPPORTED_BIN_TYPES, (
"Binary type %s not supported. Supported types [%s]"
% (binary_type, ", ".join(TestBinary.SUPPORTED_BIN_TYPES))
)
self.__path = path
self.__flash_method = binary_type
self.__comp_log = compare_log
def get_path(self):
"""
Gives binary path.
:return:
"""
return self.__path
def get_compare_log(self):
"""
Gives compare log file.
:return:
"""
return self.__comp_log
class Test(object):
"""
class representing a Test artifact that may contain more than one test binaries.
"""
KW_TEST_NAME = "name"
KW_TEST_BINS = "binaries"
def __init__(self, name, default_flash_method=None):
"""
ctor.
:param name:
:param default_flash_method:
:return:
"""
self.__name = name
self.__default_flash_method = default_flash_method
self.__binaries_by_flash_method = {}
def get_name(self):
"""
Gives test name.
:return:
"""
return self.__name
def get_binary(self, binary_type=TestBinary.BIN_TYPE_DEFAULT):
"""
Gives a test binary of specific flash type.
:param binary_type:
:return:
"""
return self.__binaries_by_flash_method.get(binary_type, None)
def parse(self, test_json):
"""
Parse json contents into object.
:param test_json:
:return:
"""
assert Test.KW_TEST_BINS in test_json, "Test spec should contain key `binaries`"
for binary in test_json[Test.KW_TEST_BINS]:
mandatory_keys = [TestBinary.KW_BIN_PATH]
assert set(mandatory_keys).issubset(
set(binary.keys())
), "Binary spec should contain key [%s]" % ",".join(mandatory_keys)
fm = binary.get(TestBinary.KW_BIN_TYPE, self.__default_flash_method)
assert fm is not None, "Binary type not specified in build and binary spec."
tb = TestBinary(binary[TestBinary.KW_BIN_PATH],
fm,
binary.get(TestBinary.KW_COMP_LOG))
self.__binaries_by_flash_method[fm] = tb
def add_binary(self, path, binary_type, compare_log=None):
"""
Add binary to the test.
:param path:
:param binary_type:
:return:
"""
self.__binaries_by_flash_method[binary_type] = TestBinary(path,
binary_type,
compare_log)
class TestBuild(object):
"""
class for Test build.
"""
KW_TEST_BUILD_NAME = "name"
KW_PLATFORM = "platform"
KW_TOOLCHAIN = "toolchain"
KW_BAUD_RATE = "baud_rate"
KW_BUILD_BASE_PATH = "base_path"
KW_TESTS = "tests"
KW_BIN_TYPE = "binary_type"
def __init__(
self, name, platform, toolchain, baud_rate, base_path, default_flash_method=None
):
"""
ctor.
:param name:
:param platform:
:param toolchain:
:param baud_rate:
:param base_path:
:param default_flash_method:
:return:
"""
self.__name = name
self.__platform = platform
self.__toolchain = toolchain
self.__baud_rate = baud_rate
self.__base_path = base_path
self.__default_flash_method = default_flash_method
self.__tests = {}
def get_name(self):
"""
Gives build name.
:return:
"""
return self.__name
def get_platform(self):
"""
Gives mbed classic platform name.
:return:
"""
return self.__platform
def get_toolchain(self):
"""
Gives toolchain
:return:
"""
return self.__toolchain
def get_baudrate(self):
"""
Gives baud rate.
:return:
"""
return self.__baud_rate
def get_path(self):
"""
Gives path.
:return:
"""
return self.__base_path
def get_tests(self):
"""
Gives tests dict keyed by test name.
:return:
"""
return self.__tests
def parse(self, build_spec):
"""
Parse Test build json.
:param build_spec:
:return:
"""
assert TestBuild.KW_TESTS in build_spec, (
"Build spec should contain key '%s'" % TestBuild.KW_TESTS
)
for name, test_json in build_spec[TestBuild.KW_TESTS].items():
test = Test(name, default_flash_method=self.__default_flash_method)
test.parse(test_json)
self.__tests[name] = test
def add_test(self, name, test):
"""
Add test.
:param name:
:param test:
:return:
"""
self.__tests[name] = test
class TestSpec(object):
"""
Test specification. Contains Builds.
"""
KW_BUILDS = "builds"
test_spec_filename = "runtime_load"
def __init__(self, test_spec_filename=None):
"""
ctor.
:return:
"""
self.__target_test_spec = {}
if test_spec_filename:
self.test_spec_filename = test_spec_filename
self.load(self.test_spec_filename)
def load(self, test_spec_filename):
"""
Load test spec directly from file
:param test_spec_filename: Name of JSON file with TestSpec to load
:return: Treu if load was successful
"""
try:
with open(test_spec_filename, "r") as f:
self.parse(json.load(f))
except Exception as e:
print("TestSpec::load('%s') %s" % (test_spec_filename, str(e)))
return False
self.test_spec_filename = test_spec_filename
return True
def parse(self, spec):
"""
Parse test spec json.
:param spec:
:return:
"""
assert TestSpec.KW_BUILDS, (
"Test spec should contain key '%s'" % TestSpec.KW_BUILDS
)
for build_name, build in spec[TestSpec.KW_BUILDS].items():
mandatory_keys = [
TestBuild.KW_PLATFORM,
TestBuild.KW_TOOLCHAIN,
TestBuild.KW_BAUD_RATE,
TestBuild.KW_BUILD_BASE_PATH,
]
assert set(mandatory_keys).issubset(set(build.keys())), (
"Build spec should contain keys [%s]. It has [%s]"
% (",".join(mandatory_keys), ",".join(build.keys()))
)
platform = build[TestBuild.KW_PLATFORM]
toolchain = build[TestBuild.KW_TOOLCHAIN]
# If there is no 'name' property in build, we will use build key
# as build name
name = build.get(TestBuild.KW_TEST_BUILD_NAME, build_name)
tb = TestBuild(
name,
platform,
toolchain,
build[TestBuild.KW_BAUD_RATE],
build[TestBuild.KW_BUILD_BASE_PATH],
build.get(TestBuild.KW_BIN_TYPE, None),
)
tb.parse(build)
self.__target_test_spec[name] = tb
def get_test_builds(self, filter_by_names=None):
"""
Gives test builds.
:param filter_by_names: List of names of builds you want to filter
in your result
:return:
"""
result = []
if filter_by_names:
assert type(filter_by_names) is list
for tb in self.__target_test_spec.values():
if tb.get_name() in filter_by_names:
result.append(tb)
else:
# When filtering by name is not defined we will return all builds objects
result = list(self.__target_test_spec.values())
return result
def get_test_build(self, build_name):
"""
Gives test build with given name.
:param build_name:
:return:
"""
return self.__target_test_spec.get(build_name, None)
def add_test_builds(self, name, test_build):
"""
Add test build.
:param name:
:param test_build:
:return:
"""
self.__target_test_spec[name] = test_build