# 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