1#!/usr/bin/env python3
2#
3# Copyright 2024, The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Tests to check if adevice commands were executed with success exit codes."""
18
19import atest_integration_test
20
21
22class AdeviceCommandSuccessTests(atest_integration_test.AtestTestCase):
23  """Test whether the adevice commands run with success exit codes."""
24
25  def setUp(self):
26    super().setUp()
27    self._default_snapshot_include_paths += [
28        '$OUT_DIR/combined-*.ninja',
29        '$OUT_DIR/build-*.ninja',
30        '$OUT_DIR/soong/*.ninja',
31        '$OUT_DIR/target/',
32    ]
33
34    self._default_snapshot_env_keys += ['TARGET_PRODUCT', 'ANDROID_BUILD_TOP']
35    self._default_snapshot_exclude_paths = []
36
37  def test_status(self):
38    """Test if status command runs successfully on latest repo sync."""
39    self._verify_adevice_command_success('adevice status'.split())
40
41  def test_update(self):
42    """Test if update command runs successfully on latest repo sync."""
43    self._verify_adevice_command_success(
44        'adevice update --max-allowed-changes=6000'.split()
45    )
46
47  def test_system_server_change_expect_soft_restart(self):
48    """Test if adevice update on system server update results in a soft restart."""
49    log_string_to_find = 'Entered the Android system server'
50    filename = (
51        'frameworks/base/services/java/com/android/server/SystemServer.java'
52    )
53    build_pre_cmd = [
54        'sed',
55        '-i',
56        f's#{log_string_to_find}#{log_string_to_find}ADEVICE_TEST#g',
57        filename,
58    ]
59    build_clean_up_cmd = f'sed -i s#ADEVICE_TEST##g {filename}'.split()
60
61    self._verify_adevice_command(
62        build_pre_cmd=build_pre_cmd,
63        build_clean_up_cmd=build_clean_up_cmd,
64        test_cmd='adevice update'.split(),
65        expected_in_log=['push', 'systemserver', 'restart'],
66        expected_not_in_log=['reboot'],
67    )
68
69  def _verify_adevice_command_success(self, test_cmd: list[str]):
70    """Verifies whether an adevice command run completed with exit code 0."""
71    self._verify_adevice_command(
72        build_pre_cmd=[],
73        build_clean_up_cmd=[],
74        test_cmd=test_cmd,
75        expected_in_log=[],
76        expected_not_in_log=[],
77    )
78
79  def _verify_adevice_command(
80      self,
81      build_pre_cmd: list[str],
82      build_clean_up_cmd: list[str],
83      test_cmd: list[str],
84      expected_in_log: list[str],
85      expected_not_in_log: list[str],
86  ):
87    """Verifies whether an adevice command run completed with exit code 0."""
88    script = self.create_atest_script()
89
90    def build_step(
91        step_in: atest_integration_test.StepInput,
92    ) -> atest_integration_test.StepOutput:
93
94      try:
95        if build_pre_cmd:
96          self._run_shell_command(
97              build_pre_cmd,
98              env=step_in.get_env(),
99              cwd=step_in.get_repo_root(),
100              print_output=True,
101          ).check_returncode()
102        self._run_shell_command(
103            'build/soong/soong_ui.bash --make-mode'.split(),
104            env=step_in.get_env(),
105            cwd=step_in.get_repo_root(),
106            print_output=True,
107        ).check_returncode()
108        return self.create_step_output()
109      except Exception as e:
110        raise e
111      finally:
112        # Always attempt to clean up
113        if build_clean_up_cmd:
114          self._run_shell_command(
115              build_clean_up_cmd,
116              env=step_in.get_env(),
117              cwd=step_in.get_repo_root(),
118              print_output=True,
119          ).check_returncode()
120
121    def test_step(step_in: atest_integration_test.StepInput) -> None:
122      self._run_shell_command(
123          test_cmd,
124          env=step_in.get_env(),
125          cwd=step_in.get_repo_root(),
126          print_output=True,
127      ).check_returncode()
128
129      check_log_process = self._run_shell_command(
130          'cat $ANDROID_BUILD_TOP/out/adevice.log'.split(),
131          env=step_in.get_env(),
132      )
133      for s in expected_in_log:
134        if s not in check_log_process.stdout:
135          raise f'Expected {s} in adevice log. Got {check_log_process.stdout}'
136      for s in expected_not_in_log:
137        if s in check_log_process.stdout:
138          raise f'Expected {s} to be NOT in adevice log. Got {check_log_process.stdout}'
139
140    script.add_build_step(build_step)
141    script.add_test_step(test_step)
142    script.run()
143
144
145if __name__ == '__main__':
146  atest_integration_test.main()
147