Loading system/gd/cert/cert_self_test.py +68 −81 Original line number Diff line number Diff line Loading @@ -20,13 +20,14 @@ import time from mobly import asserts from acts import signals from acts.base_test import BaseTestClass from bluetooth_packets_python3 import hci_packets from bluetooth_packets_python3 import l2cap_packets from cert.event_stream import EventStream, FilteringEventStream from cert.truth import assertThat from cert.metadata import metadata, MetadataKey from cert.metadata import metadata class BogusProto: Loading Loading @@ -397,103 +398,89 @@ class CertSelfTest(BaseTestClass): .then(lambda data: data.value_ == 3) def test_metadata_empty(self): my_content = [{}] class TestClass: def record_data(self, content): my_content[0] = content @metadata() def sample_pass_test(self): def simple_pass_test(arg): pass @metadata() def sample_skipped_test(self): asserts.skip("SKIP") try: simple_pass_test(1) except signals.TestFailure: pass except Exception as e: asserts.fail("@metadata() should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("@metadata() should not work") @metadata() def sample_failed_test(self): asserts.fail("FAIL") def test_metadata_empty_no_function_call(self): test_class = TestClass() @metadata def simple_pass_test(arg): pass try: test_class.sample_pass_test() except Exception: asserts.fail("Should not raise exception") finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_pass_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") simple_pass_test(1) except signals.TestFailure: pass except Exception as e: asserts.fail("@metadata should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("@metadata should not work") try: test_class.sample_skipped_test() except Exception: def test_metadata_pts_missing_id(self): @metadata(pts_test_name="Hello world") def simple_pass_test(arg): pass finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_skipped_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") try: test_class.sample_failed_test() except Exception: simple_pass_test(1) except signals.TestFailure: pass finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_failed_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") def test_metadata_empty_no_function_call(self): my_content = [{}] class TestClass: except Exception as e: asserts.fail("should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("missing pts_test_id should not work") def record_data(self, content): my_content[0] = content def test_metadata_pts_missing_name(self): @metadata() def sample_pass_test(self): @metadata(pts_test_id="A/B/C") def simple_pass_test(arg): pass test_class = TestClass() try: test_class.sample_pass_test() except Exception: asserts.fail("Should not raise exception") finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_pass_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") def test_metadata_pts_test_id(self): my_content = [{}] class TestClass: simple_pass_test(1) except signals.TestFailure: pass except Exception as e: asserts.fail("should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("missing pts_test_name should not work") def record_data(self, content): my_content[0] = content def test_metadata_pts_test_id_and_description(self): @metadata(pts_test_id="Hello World") def sample_pass_test(self): @metadata(pts_test_id="A/B/C", pts_test_name="Hello world") def simple_pass_test(arg): pass test_class = TestClass() try: test_class.sample_pass_test() except Exception: asserts.fail("Should not raise exception") finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_pass_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") asserts.assert_equal(my_content[0][str(MetadataKey.PTS_TEST_ID)], "Hello World") simple_pass_test(1) except signals.TestPass as e: asserts.assert_true( "pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras))) asserts.assert_equal(e.extras["pts_test_id"], "A/B/C") asserts.assert_true( "pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras))) asserts.assert_equal(e.extras["pts_test_name"], "Hello world") else: asserts.fail("Must throw an exception using @metadata decorator") system/gd/cert/metadata.py +41 −56 Original line number Diff line number Diff line Loading @@ -13,83 +13,68 @@ # 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. import enum import functools import inspect from mobly import asserts from acts.base_test import BaseTestClass from acts.test_decorators import test_info @enum.unique class MetadataKey(enum.Enum): """Enums used for recording UserData section for Gd Cert Tests""" # TEST_CLASS + TEST_NAME should uniquely define a test TEST_NAME = 'Test Name' TEST_CLASS = 'Test Class' # A fully qualified PTS test ID such as L2CAP/COS/IEX/BV-01-C PTS_TEST_ID = 'PTS Test ID' def _fail_decorator(msg): def __str__(self): """ :return: str representation of |value| instead of "Class.Enum" """ return repr(self) def fail_decorator(func): def __repr__(self): """ :return: the same str representation since |value| is unique """ return str(self.value) @functools.wraps(func) def fail(*args, **kwargs): asserts.fail(msg) return fail return fail_decorator def metadata(_do_not_use=None, pts_test_id=None): def metadata(_do_not_use=None, pts_test_id=None, pts_test_name=None): """ Record a piece of test metadata in the UserData section of the test summary file. The metadata will come with a timestamp, but there is no guarantee on the order of when the metadata will be written Record a piece of test metadata in the Extra section of the test Record in the test summary file. The metadata will come with a timestamp, but there is no guarantee on the order of when the metadata will be written Note: - Metadata is recorded per test case as key-value pairs. - TEST_CLASS and TEST_NAME combination can be used to correlate a piece of metadata with the ACTS or Mobly generated test run record in the same YAML file - Metadata is only guaranteed to be written when the test result is PASS, FAIL or SKIPPED. When there are test infrastructural errors, metadata might not be written successfully :param _do_not_use: a positional argument with default value. This argument is only used when @metadata is used instead of @metadata() is to ensure that @metadata(key=value) is used in a functional form instead of @metadata or @metadata(a) :param pts_test_id: A fully qualified PTS test ID such as L2CAP/COS/IEX/BV-01-C, see MetadataKey.PTS_TEST_ID :return: decorated test case function L2CAP/COS/IEX/BV-01-C :param pts_test_name: A human readable test name such as "Request Connection" for the above example :return: decorated test case function object """ if _do_not_use is not None: def real_decorator(test_case_function): def fail(*args, **kwargs): asserts.fail("@metadata must be used in functional form such " "as @metadta(key=value)") @functools.wraps(test_case_function) def wrapper(self: BaseTestClass): try: test_case_function(self) finally: content = { str(MetadataKey.TEST_NAME): test_case_function.__name__, str(MetadataKey.TEST_CLASS): self.__class__.__name__ } if pts_test_id: content[str(MetadataKey.PTS_TEST_ID)] = str(pts_test_id) self.record_data(content) return fail return wrapper # Create a dictionary of optional parameters values = locals() args = {arg: values[arg] for arg in inspect.getfullargspec(metadata).args} del args["_do_not_use"] if _do_not_use is not None: asserts.assert_true( callable(_do_not_use), "No real positional argument is allowed for" " @metadata") asserts.assert_true( pts_test_id is None, "No additional positional argument is allowed for" " @metadata") return real_decorator(_do_not_use) return real_decorator # Check if at least one optional parameter is valid if not any(args): return _fail_decorator("at least one optional argument should be valid") # Validate pts_test_id and pts_test_name if (pts_test_id or pts_test_name) and \ (not pts_test_id or not pts_test_name): return _fail_decorator("pts_test_id and pts_test_name must both " "be valid if one of them is valid") return test_info(**args) Loading
system/gd/cert/cert_self_test.py +68 −81 Original line number Diff line number Diff line Loading @@ -20,13 +20,14 @@ import time from mobly import asserts from acts import signals from acts.base_test import BaseTestClass from bluetooth_packets_python3 import hci_packets from bluetooth_packets_python3 import l2cap_packets from cert.event_stream import EventStream, FilteringEventStream from cert.truth import assertThat from cert.metadata import metadata, MetadataKey from cert.metadata import metadata class BogusProto: Loading Loading @@ -397,103 +398,89 @@ class CertSelfTest(BaseTestClass): .then(lambda data: data.value_ == 3) def test_metadata_empty(self): my_content = [{}] class TestClass: def record_data(self, content): my_content[0] = content @metadata() def sample_pass_test(self): def simple_pass_test(arg): pass @metadata() def sample_skipped_test(self): asserts.skip("SKIP") try: simple_pass_test(1) except signals.TestFailure: pass except Exception as e: asserts.fail("@metadata() should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("@metadata() should not work") @metadata() def sample_failed_test(self): asserts.fail("FAIL") def test_metadata_empty_no_function_call(self): test_class = TestClass() @metadata def simple_pass_test(arg): pass try: test_class.sample_pass_test() except Exception: asserts.fail("Should not raise exception") finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_pass_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") simple_pass_test(1) except signals.TestFailure: pass except Exception as e: asserts.fail("@metadata should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("@metadata should not work") try: test_class.sample_skipped_test() except Exception: def test_metadata_pts_missing_id(self): @metadata(pts_test_name="Hello world") def simple_pass_test(arg): pass finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_skipped_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") try: test_class.sample_failed_test() except Exception: simple_pass_test(1) except signals.TestFailure: pass finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_failed_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") def test_metadata_empty_no_function_call(self): my_content = [{}] class TestClass: except Exception as e: asserts.fail("should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("missing pts_test_id should not work") def record_data(self, content): my_content[0] = content def test_metadata_pts_missing_name(self): @metadata() def sample_pass_test(self): @metadata(pts_test_id="A/B/C") def simple_pass_test(arg): pass test_class = TestClass() try: test_class.sample_pass_test() except Exception: asserts.fail("Should not raise exception") finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_pass_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") def test_metadata_pts_test_id(self): my_content = [{}] class TestClass: simple_pass_test(1) except signals.TestFailure: pass except Exception as e: asserts.fail("should only raise signals.TestFailure, " "but raised %s with msg %s instead" % (e.__class__.__name__, str(e))) else: asserts.fail("missing pts_test_name should not work") def record_data(self, content): my_content[0] = content def test_metadata_pts_test_id_and_description(self): @metadata(pts_test_id="Hello World") def sample_pass_test(self): @metadata(pts_test_id="A/B/C", pts_test_name="Hello world") def simple_pass_test(arg): pass test_class = TestClass() try: test_class.sample_pass_test() except Exception: asserts.fail("Should not raise exception") finally: asserts.assert_equal(my_content[0][str(MetadataKey.TEST_NAME)], "sample_pass_test") asserts.assert_equal(my_content[0][str(MetadataKey.TEST_CLASS)], "TestClass") asserts.assert_equal(my_content[0][str(MetadataKey.PTS_TEST_ID)], "Hello World") simple_pass_test(1) except signals.TestPass as e: asserts.assert_true( "pts_test_id" in e.extras, msg=("pts_test_id not in extra: %s" % str(e.extras))) asserts.assert_equal(e.extras["pts_test_id"], "A/B/C") asserts.assert_true( "pts_test_name" in e.extras, msg=("pts_test_name not in extra: %s" % str(e.extras))) asserts.assert_equal(e.extras["pts_test_name"], "Hello world") else: asserts.fail("Must throw an exception using @metadata decorator")
system/gd/cert/metadata.py +41 −56 Original line number Diff line number Diff line Loading @@ -13,83 +13,68 @@ # 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. import enum import functools import inspect from mobly import asserts from acts.base_test import BaseTestClass from acts.test_decorators import test_info @enum.unique class MetadataKey(enum.Enum): """Enums used for recording UserData section for Gd Cert Tests""" # TEST_CLASS + TEST_NAME should uniquely define a test TEST_NAME = 'Test Name' TEST_CLASS = 'Test Class' # A fully qualified PTS test ID such as L2CAP/COS/IEX/BV-01-C PTS_TEST_ID = 'PTS Test ID' def _fail_decorator(msg): def __str__(self): """ :return: str representation of |value| instead of "Class.Enum" """ return repr(self) def fail_decorator(func): def __repr__(self): """ :return: the same str representation since |value| is unique """ return str(self.value) @functools.wraps(func) def fail(*args, **kwargs): asserts.fail(msg) return fail return fail_decorator def metadata(_do_not_use=None, pts_test_id=None): def metadata(_do_not_use=None, pts_test_id=None, pts_test_name=None): """ Record a piece of test metadata in the UserData section of the test summary file. The metadata will come with a timestamp, but there is no guarantee on the order of when the metadata will be written Record a piece of test metadata in the Extra section of the test Record in the test summary file. The metadata will come with a timestamp, but there is no guarantee on the order of when the metadata will be written Note: - Metadata is recorded per test case as key-value pairs. - TEST_CLASS and TEST_NAME combination can be used to correlate a piece of metadata with the ACTS or Mobly generated test run record in the same YAML file - Metadata is only guaranteed to be written when the test result is PASS, FAIL or SKIPPED. When there are test infrastructural errors, metadata might not be written successfully :param _do_not_use: a positional argument with default value. This argument is only used when @metadata is used instead of @metadata() is to ensure that @metadata(key=value) is used in a functional form instead of @metadata or @metadata(a) :param pts_test_id: A fully qualified PTS test ID such as L2CAP/COS/IEX/BV-01-C, see MetadataKey.PTS_TEST_ID :return: decorated test case function L2CAP/COS/IEX/BV-01-C :param pts_test_name: A human readable test name such as "Request Connection" for the above example :return: decorated test case function object """ if _do_not_use is not None: def real_decorator(test_case_function): def fail(*args, **kwargs): asserts.fail("@metadata must be used in functional form such " "as @metadta(key=value)") @functools.wraps(test_case_function) def wrapper(self: BaseTestClass): try: test_case_function(self) finally: content = { str(MetadataKey.TEST_NAME): test_case_function.__name__, str(MetadataKey.TEST_CLASS): self.__class__.__name__ } if pts_test_id: content[str(MetadataKey.PTS_TEST_ID)] = str(pts_test_id) self.record_data(content) return fail return wrapper # Create a dictionary of optional parameters values = locals() args = {arg: values[arg] for arg in inspect.getfullargspec(metadata).args} del args["_do_not_use"] if _do_not_use is not None: asserts.assert_true( callable(_do_not_use), "No real positional argument is allowed for" " @metadata") asserts.assert_true( pts_test_id is None, "No additional positional argument is allowed for" " @metadata") return real_decorator(_do_not_use) return real_decorator # Check if at least one optional parameter is valid if not any(args): return _fail_decorator("at least one optional argument should be valid") # Validate pts_test_id and pts_test_name if (pts_test_id or pts_test_name) and \ (not pts_test_id or not pts_test_name): return _fail_decorator("pts_test_id and pts_test_name must both " "be valid if one of them is valid") return test_info(**args)