blob: 6dbbba225a26a5eb6eaa6a46a483f1772ea64856 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2021 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Ignore indention messages, since legacy scripts use 2 spaces instead of 4.
# pylint: disable=bad-indentation,docstring-section-indent
# pylint: disable=docstring-trailing-quotes
# Ignore line too long errors as many lines are large byte-arrays over 80 char
# pylint: disable=line-too-long
# Ignore protected member access as these are unit tests explicitly accessing
# pylint: disable=protected-access
"""Unit tests for generate_gtest_metadata.py script"""
from unittest import TestCase, main, mock
import collections
import yaml
import jsonschema
from chromiumos.test.api import test_case_metadata_pb2 as tc_metadata_pb
from chromiumos.test.api import test_harness_pb2 as th_pb
from chromiumos.test.api import test_case_pb2 as tc_pb
import gtest_unittest_const as gtc
import generate_gtest_metadata
class Generate_Gtest_Metadata_Test(TestCase):
"""Main test class for these unit tests"""
@classmethod
def setUpClass(cls) -> None:
"""Setup our YAML/parse json as it only needs to be done once"""
Yaml_Proto = collections.namedtuple('Yaml_Proto', ['yaml', 'proto'])
cls._yaml_proto_data = [
Yaml_Proto(gtc.VALID_YAML_SINGLE_CASE_NO_TAG,
gtc.VALID_YAML_SINGLE_CASE_NO_TAG_PROTOBUF),
Yaml_Proto(gtc.VALID_YAML_SINGLE_CASE_ONE_TAG,
gtc.VALID_YAML_SINGLE_CASE_ONE_TAG_PROTOBUF),
Yaml_Proto(gtc.VALID_YAML_SINGLE_CASE_MULTIPLE_TAGS,
gtc.VALID_YAML_SINGLE_CASE_MULTIPLE_TAGS_PROTOBUF),
Yaml_Proto(gtc.VALID_YAML_MULTIPLE_CASE_NO_TAG,
gtc.VALID_YAML_MULTIPLE_CASE_NO_TAG_PROTOBUF),
Yaml_Proto(gtc.VALID_YAML_MULTIPLE_CASE_ONE_TAG,
gtc.VALID_YAML_MULTIPLE_CASE_ONE_TAG_PROTOBUF),
Yaml_Proto(gtc.VALID_YAML_MULTIPLE_CASE_MULTIPLE_TAGS,
gtc.VALID_YAML_MULTIPLE_CASE_MULTIPLE_TAGS_PROTOBUF)
]
with open('gtest_schema.yaml', 'r') as f:
cls._yaml_schema = f.read()
Bad_Yaml = collections.namedtuple('Bad_Yaml', ['yaml', 'msg'])
cls._bad_yaml_data = [
Bad_Yaml(gtc.INVALID_YAML_NO_AUTHOR,
'Expected a failure, no "author" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_NAME,
'Expected a failure, no "name" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_HARNESS,
'Expected a failure, no "harness" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_CATEGORY,
'Expected a failure, no "category" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_OWNERS,
'Expected a failure, no "owners" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_EMAIL,
'Expected a failure, no "owners/email" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_CASES,
'Expected a failure, no "cases" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_CASE_ID,
'Expected a failure, no "cases/id" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_CASE_TAGS,
'Expected a failure, no "cases/tags" field in yaml!'),
Bad_Yaml(gtc.INVALID_YAML_NO_CASE_CRITERIA,
'Expected a failure, no "cases/criteria" field in yaml!'),
Bad_Yaml(
gtc.INVALID_YAML_NO_CASE_TARGET_LOC,
'Expected a failure, no "cases/target_bin_location" field in yaml!'
)
]
def _get_protobuf_bytes(self, input_files: mock.MagicMock,
schema_file: mock.MagicMock,
output_file: mock.MagicMock) -> bytearray:
generate_gtest_metadata.main(input_files=input_files,
output_file=output_file,
yaml_schema_file=schema_file)
return output_file.write_bytes.call_args[0][0]
def test_single_file_protobuf_generation(self) -> None:
"""Test that the protobuf generated bytes match expected for a given file"""
for yp in self._yaml_proto_data:
schema_file = mock.MagicMock()
schema_file.read_text.return_value = self._yaml_schema
input_file = mock.MagicMock()
input_file.read_text.return_value = yp.yaml
output_file = mock.MagicMock()
bytes_from_main = self._get_protobuf_bytes([input_file],
schema_file,
output_file)
self.assertEqual(yp.proto, bytes_from_main)
def test_multi_file_protobuf_generation(self) -> None:
"""Test that protobuf generated bytes match expected for a given file"""
schema_file = mock.MagicMock()
schema_file.read_text.return_value = self._yaml_schema
input_files = []
for yp in self._yaml_proto_data:
input_file = mock.MagicMock()
input_file.read_text.return_value = yp.yaml
input_files.append(input_file)
output_file = mock.MagicMock()
bytes_from_main = self._get_protobuf_bytes(input_files, schema_file,
output_file)
self.assertEqual(gtc.VALID_YAML_ALL_FILES_PROTOBUF, bytes_from_main)
def test_invalid_yaml(self) -> None:
"""Test yaml schema validation"""
for ym in self._bad_yaml_data:
schema_file = mock.MagicMock()
schema_file.read_text.return_value = self._yaml_schema
input_file = mock.MagicMock()
input_file.read_text.return_value = ym.yaml
output_file = mock.MagicMock()
with self.assertRaises(jsonschema.exceptions.ValidationError,
msg=ym.msg):
self._get_protobuf_bytes([input_file], schema_file,
output_file)
def _build_testcase_metadata_objects(
self, input_data: list) -> tc_metadata_pb.TestCaseMetadataList:
cases = []
for f in input_data:
s_name = f['name']
tce = tc_metadata_pb.TestCaseExec(test_harness=th_pb.TestHarness(
gtest=th_pb.TestHarness.Gtest()))
tci = tc_metadata_pb.TestCaseInfo(owners=[
tc_metadata_pb.Contact(email=x['email']) for x in f['owners']
])
for c in f['cases']:
tags = [tc_pb.TestCase.Tag(value=t) for t in c['tags']]
tc_id = tc_pb.TestCase.Id(value=f'gtest.{s_name}.{c["id"]}')
c_name = f'{s_name}.{c["id"]}'
case = tc_pb.TestCase(id=tc_id, name=c_name, tags=tags)
cases.append(
tc_metadata_pb.TestCaseMetadata(test_case=case,
test_case_exec=tce,
test_case_info=tci))
return tc_metadata_pb.TestCaseMetadataList(values=cases)
def test_proto_objects_single_file(self) -> None:
"""Test proto object building prior to serialization"""
input_yaml = yaml.safe_load(gtc.VALID_YAML_MULTIPLE_CASE_MULTIPLE_TAGS)
actual_test_case_list = generate_gtest_metadata._test_case_list_factory(
input_data=input_yaml)
actual_testcase_metadata_list = tc_metadata_pb.TestCaseMetadataList(
values=actual_test_case_list)
# Make sure we got our 3 cases
self.assertEqual(len(input_yaml['cases']),
len(actual_testcase_metadata_list.values))
# Check the object values to make sure they match
for i, tc in enumerate(actual_testcase_metadata_list.values):
# Check test harness
self.assertIsInstance(tc.test_case_exec.test_harness.gtest,
th_pb.TestHarness.Gtest)
# Check owner/email
actual_owner_emails = [c.email for c in tc.test_case_info.owners]
expected_owner_emails = [e['email'] for e in input_yaml['owners']]
self.assertListEqual(expected_owner_emails, actual_owner_emails)
# Check case tags, id, name
actual_tags = [t.value for t in tc.test_case.tags]
expected_tags = [t for t in input_yaml['cases'][i]['tags']]
self.assertListEqual(expected_tags, actual_tags)
actual_id = tc.test_case.id.value
expected_id = f'gtest.{input_yaml["name"]}.{input_yaml["cases"][i]["id"]}'
self.assertEqual(expected_id, actual_id)
actual_name = tc.test_case.name
expected_name = f'{input_yaml["name"]}.{input_yaml["cases"][i]["id"]}'
self.assertEqual(expected_name, actual_name)
# Check it all for good measure
expected_testcase_metadata_list = self._build_testcase_metadata_objects(
[input_yaml])
self.assertEqual(expected_testcase_metadata_list,
actual_testcase_metadata_list)
def test_proto_objects_multiple_file(self) -> None:
"""Test multiple proto object building prior to serialization"""
input_yaml = [yaml.safe_load(x.yaml) for x in self._yaml_proto_data]
actual_test_case_list = []
for y in input_yaml:
actual_test_case_list.extend(
generate_gtest_metadata._test_case_list_factory(input_data=y))
actual_testcase_metadata_list = tc_metadata_pb.TestCaseMetadataList(
values=actual_test_case_list)
# Check it all for good measure
expected_testcase_metadata_list = self._build_testcase_metadata_objects(
input_yaml)
self.assertEqual(expected_testcase_metadata_list,
actual_testcase_metadata_list)
if __name__ == '__main__':
main(verbosity=2)