#!/usr/bin/env python3 # # Copyright 2019, The Android Open Source Project # # 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. """Unittest for atest_execution_info.""" import os import pathlib import time import unittest from unittest.mock import patch from atest import arg_parser from atest import atest_execution_info as aei from atest import constants from atest import result_reporter from atest.metrics import metrics from atest.test_runners import test_runner_base from pyfakefs import fake_filesystem_unittest RESULT_TEST_TEMPLATE = test_runner_base.TestResult( runner_name='someRunner', group_name='someModule', test_name='someClassName#sostName', status=test_runner_base.PASSED_STATUS, details=None, test_count=1, test_time='(10ms)', runner_total=None, group_total=2, additional_info={}, test_run_name='com.android.UnitTests', ) class CopyBuildTraceToLogsTests(fake_filesystem_unittest.TestCase): def setUp(self): super().setUp() self.setUpPyfakefs() self.fs.create_dir(constants.ATEST_RESULT_ROOT) def test_copy_build_artifacts_to_log_dir_new_trace_copy(self): start_time = 10 log_path = pathlib.Path('/logs') self.fs.create_dir(log_path) out_path = pathlib.Path('/out') build_trace_path = out_path / 'build.trace' self.fs.create_file(build_trace_path) # Set the trace file's mtime greater than start time os.utime(build_trace_path, (20, 20)) end_time = 30 aei.AtestExecutionInfo._copy_build_artifacts_to_log_dir( start_time, end_time, out_path, log_path, 'build.trace' ) self.assertTrue( self._is_dir_contains_files_with_prefix(log_path, 'build.trace') ) def test_copy_build_artifacts_to_log_dir_old_trace_does_not_copy(self): start_time = 10 log_path = pathlib.Path('/logs') self.fs.create_dir(log_path) out_path = pathlib.Path('/out') build_trace_path = out_path / 'build.trace' self.fs.create_file(build_trace_path) # Set the trace file's mtime smaller than start time os.utime(build_trace_path, (5, 5)) end_time = 30 aei.AtestExecutionInfo._copy_build_artifacts_to_log_dir( start_time, end_time, out_path, log_path, 'build.trace' ) self.assertFalse( self._is_dir_contains_files_with_prefix(log_path, 'build.trace') ) def test_copy_multiple_build_trace_to_log_dir(self): start_time = 10 log_path = pathlib.Path('/logs') self.fs.create_dir(log_path) out_path = pathlib.Path('/out') build_trace_path1 = out_path / 'build.trace.1.gz' build_trace_path2 = out_path / 'build.trace.2.gz' self.fs.create_file(build_trace_path1) self.fs.create_file(build_trace_path2) # Set the trace file's mtime greater than start time os.utime(build_trace_path1, (20, 20)) os.utime(build_trace_path2, (20, 20)) end_time = 30 aei.AtestExecutionInfo._copy_build_artifacts_to_log_dir( start_time, end_time, out_path, log_path, 'build.trace' ) self.assertTrue( self._is_dir_contains_files_with_prefix(log_path, 'build.trace.1.gz') ) self.assertTrue( self._is_dir_contains_files_with_prefix(log_path, 'build.trace.2.gz') ) def _is_dir_contains_files_with_prefix( self, dir: pathlib.Path, prefix: str ) -> bool: for file in dir.iterdir(): if file.is_file() and file.name.startswith(prefix): return True return False # pylint: disable=protected-access class AtestExecutionInfoUnittests(unittest.TestCase): """Unit tests for atest_execution_info.py""" @patch('atest.metrics.metrics.is_internal_user', return_value=False) def test_create_bug_report_url_is_external_user_return_empty(self, _): url = aei.AtestExecutionInfo._create_bug_report_url() self.assertFalse(url) @patch('atest.metrics.metrics.is_internal_user', return_value=True) def test_create_bug_report_url_is_internal_user_return_url(self, _): url = aei.AtestExecutionInfo._create_bug_report_url() self.assertTrue(url) @patch('atest.metrics.metrics.is_internal_user', return_value=True) @patch('atest.logstorage.log_uploader.is_uploading_logs', return_value=True) def test_create_bug_report_url_is_uploading_logs_use_contains_run_id( self, _, __ ): url = aei.AtestExecutionInfo._create_bug_report_url() self.assertIn(metrics.get_run_id(), url) @patch('atest.metrics.metrics.is_internal_user', return_value=True) @patch('atest.logstorage.log_uploader.is_uploading_logs', return_value=False) def test_create_bug_report_url_is_not_uploading_logs_use_contains_run_id( self, _, __ ): url = aei.AtestExecutionInfo._create_bug_report_url() self.assertNotIn(metrics.get_run_id(), url) def test_arrange_test_result_one_module(self): """Test _arrange_test_result method with only one module.""" pass_1 = self._create_test_result(status=test_runner_base.PASSED_STATUS) pass_2 = self._create_test_result(status=test_runner_base.PASSED_STATUS) pass_3 = self._create_test_result(status=test_runner_base.PASSED_STATUS) fail_1 = self._create_test_result(status=test_runner_base.FAILED_STATUS) fail_2 = self._create_test_result(status=test_runner_base.FAILED_STATUS) ignore_1 = self._create_test_result(status=test_runner_base.IGNORED_STATUS) reporter_1 = result_reporter.ResultReporter() reporter_1.all_test_results.extend([pass_1, pass_2, pass_3]) reporter_2 = result_reporter.ResultReporter() reporter_2.all_test_results.extend([fail_1, fail_2, ignore_1]) info_dict = {} aei.AtestExecutionInfo._arrange_test_result( info_dict, [reporter_1, reporter_2] ) expect_summary = { aei._STATUS_IGNORED_KEY: 1, aei._STATUS_FAILED_KEY: 2, aei._STATUS_PASSED_KEY: 3, } self.assertEqual(expect_summary, info_dict[aei._TOTAL_SUMMARY_KEY]) def test_arrange_test_result_multi_module(self): """Test _arrange_test_result method with multi module.""" group_a_pass_1 = self._create_test_result( group_name='grpup_a', status=test_runner_base.PASSED_STATUS ) group_b_pass_1 = self._create_test_result( group_name='grpup_b', status=test_runner_base.PASSED_STATUS ) group_c_pass_1 = self._create_test_result( group_name='grpup_c', status=test_runner_base.PASSED_STATUS ) group_b_fail_1 = self._create_test_result( group_name='grpup_b', status=test_runner_base.FAILED_STATUS ) group_c_fail_1 = self._create_test_result( group_name='grpup_c', status=test_runner_base.FAILED_STATUS ) group_c_ignore_1 = self._create_test_result( group_name='grpup_c', status=test_runner_base.IGNORED_STATUS ) reporter_1 = result_reporter.ResultReporter() reporter_1.all_test_results.extend( [group_a_pass_1, group_b_pass_1, group_c_pass_1] ) reporter_2 = result_reporter.ResultReporter() reporter_2.all_test_results.extend( [group_b_fail_1, group_c_fail_1, group_c_ignore_1] ) info_dict = {} aei.AtestExecutionInfo._arrange_test_result( info_dict, [reporter_1, reporter_2] ) expect_group_a_summary = { aei._STATUS_IGNORED_KEY: 0, aei._STATUS_FAILED_KEY: 0, aei._STATUS_PASSED_KEY: 1, } self.assertEqual( expect_group_a_summary, info_dict[aei._TEST_RUNNER_KEY]['someRunner']['grpup_a'][ aei._SUMMARY_KEY ], ) expect_group_b_summary = { aei._STATUS_IGNORED_KEY: 0, aei._STATUS_FAILED_KEY: 1, aei._STATUS_PASSED_KEY: 1, } self.assertEqual( expect_group_b_summary, info_dict[aei._TEST_RUNNER_KEY]['someRunner']['grpup_b'][ aei._SUMMARY_KEY ], ) expect_group_c_summary = { aei._STATUS_IGNORED_KEY: 1, aei._STATUS_FAILED_KEY: 1, aei._STATUS_PASSED_KEY: 1, } self.assertEqual( expect_group_c_summary, info_dict[aei._TEST_RUNNER_KEY]['someRunner']['grpup_c'][ aei._SUMMARY_KEY ], ) expect_total_summary = { aei._STATUS_IGNORED_KEY: 1, aei._STATUS_FAILED_KEY: 2, aei._STATUS_PASSED_KEY: 3, } self.assertEqual(expect_total_summary, info_dict[aei._TOTAL_SUMMARY_KEY]) def test_preparation_time(self): """Test preparation_time method.""" start_time = time.time() aei.PREPARE_END_TIME = None self.assertTrue(aei.preparation_time(start_time) is None) aei.PREPARE_END_TIME = time.time() self.assertFalse(aei.preparation_time(start_time) is None) def test_arrange_test_result_multi_runner(self): """Test _arrange_test_result method with multi runner.""" runner_a_pass_1 = self._create_test_result( runner_name='runner_a', status=test_runner_base.PASSED_STATUS ) runner_a_pass_2 = self._create_test_result( runner_name='runner_a', status=test_runner_base.PASSED_STATUS ) runner_a_pass_3 = self._create_test_result( runner_name='runner_a', status=test_runner_base.PASSED_STATUS ) runner_b_fail_1 = self._create_test_result( runner_name='runner_b', status=test_runner_base.FAILED_STATUS ) runner_b_fail_2 = self._create_test_result( runner_name='runner_b', status=test_runner_base.FAILED_STATUS ) runner_b_ignore_1 = self._create_test_result( runner_name='runner_b', status=test_runner_base.IGNORED_STATUS ) reporter_1 = result_reporter.ResultReporter() reporter_1.all_test_results.extend( [runner_a_pass_1, runner_a_pass_2, runner_a_pass_3] ) reporter_2 = result_reporter.ResultReporter() reporter_2.all_test_results.extend( [runner_b_fail_1, runner_b_fail_2, runner_b_ignore_1] ) info_dict = {} aei.AtestExecutionInfo._arrange_test_result( info_dict, [reporter_1, reporter_2] ) expect_group_a_summary = { aei._STATUS_IGNORED_KEY: 0, aei._STATUS_FAILED_KEY: 0, aei._STATUS_PASSED_KEY: 3, } self.assertEqual( expect_group_a_summary, info_dict[aei._TEST_RUNNER_KEY]['runner_a']['someModule'][ aei._SUMMARY_KEY ], ) expect_group_b_summary = { aei._STATUS_IGNORED_KEY: 1, aei._STATUS_FAILED_KEY: 2, aei._STATUS_PASSED_KEY: 0, } self.assertEqual( expect_group_b_summary, info_dict[aei._TEST_RUNNER_KEY]['runner_b']['someModule'][ aei._SUMMARY_KEY ], ) expect_total_summary = { aei._STATUS_IGNORED_KEY: 1, aei._STATUS_FAILED_KEY: 2, aei._STATUS_PASSED_KEY: 3, } self.assertEqual(expect_total_summary, info_dict[aei._TOTAL_SUMMARY_KEY]) def _create_test_result(self, **kwargs): """A Helper to create TestResult""" test_info = test_runner_base.TestResult(**RESULT_TEST_TEMPLATE._asdict()) return test_info._replace(**kwargs) if __name__ == '__main__': unittest.main()