blob: cfe8438dcabc271fea522aa2301c397e96d5c2f6 [file] [log] [blame]
Alex Kleinf4dc4f52018-12-05 13:55:12 -07001# -*- coding: utf-8 -*-
2# Copyright 2018 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Alex Klein2bfacb22019-02-04 11:42:17 -07006"""Tests for the build_api script covering the base Build API functionality."""
7
Alex Kleinf4dc4f52018-12-05 13:55:12 -07008from __future__ import print_function
9
Alex Klein5bcb4d22019-03-21 13:51:54 -060010import os
11
Alex Kleinbd6edf82019-07-18 10:30:49 -060012from google.protobuf import json_format
13
Alex Klein146d4772019-06-20 13:48:25 -060014from chromite.api import router
Alex Klein7107bdd2019-03-14 17:14:31 -060015from chromite.api.gen.chromite.api import build_api_test_pb2
Alex Klein2bfacb22019-02-04 11:42:17 -070016from chromite.lib import cros_build_lib
Alex Kleinf4dc4f52018-12-05 13:55:12 -070017from chromite.lib import cros_test_lib
Alex Klein5bcb4d22019-03-21 13:51:54 -060018from chromite.lib import osutils
Alex Kleinf4dc4f52018-12-05 13:55:12 -070019
20
Alex Klein00aa8072019-04-15 16:36:00 -060021class RouterTest(cros_test_lib.RunCommandTempDirTestCase):
Alex Kleinf4dc4f52018-12-05 13:55:12 -070022 """Test Router functionality."""
Alex Klein00aa8072019-04-15 16:36:00 -060023 _INPUT_JSON_TEMPLATE = '{"id":"Input ID", "chroot":{"path": "%s"}}'
Alex Kleinf4dc4f52018-12-05 13:55:12 -070024
25 def setUp(self):
Alex Klein146d4772019-06-20 13:48:25 -060026 self.router = router.Router()
Alex Kleinf4dc4f52018-12-05 13:55:12 -070027 self.router.Register(build_api_test_pb2)
28
Alex Klein5bcb4d22019-03-21 13:51:54 -060029 self.input_file = os.path.join(self.tempdir, 'input.json')
30 self.output_file = os.path.join(self.tempdir, 'output.json')
31
Alex Klein00aa8072019-04-15 16:36:00 -060032 self.chroot_dir = os.path.join(self.tempdir, 'chroot')
33 chroot_tmp = os.path.join(self.chroot_dir, 'tmp')
34 # Make the tmp dir for the re-exec inside chroot input/output files.
35 osutils.SafeMakedirs(chroot_tmp)
36
37 osutils.WriteFile(self.input_file,
38 self._INPUT_JSON_TEMPLATE % self.chroot_dir)
Alex Kleinbd6edf82019-07-18 10:30:49 -060039 osutils.WriteFile(self.output_file, '{}')
40
41 self.subprocess_tempdir = os.path.join(self.chroot_dir, 'tempdir')
42 osutils.SafeMakedirs(self.subprocess_tempdir)
43 self.PatchObject(osutils.TempDir, '__enter__',
44 return_value=self.subprocess_tempdir)
Alex Klein5bcb4d22019-03-21 13:51:54 -060045
Alex Kleinf4dc4f52018-12-05 13:55:12 -070046 def testInputOutputMethod(self):
47 """Test input/output handling."""
48 def impl(input_msg, output_msg):
49 self.assertIsInstance(input_msg, build_api_test_pb2.TestRequestMessage)
50 self.assertIsInstance(output_msg, build_api_test_pb2.TestResultMessage)
51
52 self.PatchObject(self.router, '_GetMethod', return_value=impl)
53
54 self.router.Route('chromite.api.TestApiService', 'InputOutputMethod',
Alex Klein5bcb4d22019-03-21 13:51:54 -060055 self.input_file, self.output_file)
Alex Kleinf4dc4f52018-12-05 13:55:12 -070056
Alex Klein2bfacb22019-02-04 11:42:17 -070057 def testRenameMethod(self):
58 """Test implementation name config."""
59 def _GetMethod(_, method_name):
60 self.assertEqual('CorrectName', method_name)
Alex Klein7a115172019-02-08 14:14:20 -070061 return lambda x, y: None
Alex Klein2bfacb22019-02-04 11:42:17 -070062
63 self.PatchObject(self.router, '_GetMethod', side_effect=_GetMethod)
64
65 self.router.Route('chromite.api.TestApiService', 'RenamedMethod',
Alex Klein5bcb4d22019-03-21 13:51:54 -060066 self.input_file, self.output_file)
Alex Klein2bfacb22019-02-04 11:42:17 -070067
Alex Klein00aa8072019-04-15 16:36:00 -060068 def _mock_callable(self, expect_called):
69 """Helper to create the implementation mock to test chroot assertions.
70
71 Args:
72 expect_called (bool): Whether the implementation should be called.
73 When False, an assertion will fail if it is called.
74
75 Returns:
76 callable - The implementation.
77 """
Alex Klein7a115172019-02-08 14:14:20 -070078 def impl(_input_msg, _output_msg):
Alex Klein00aa8072019-04-15 16:36:00 -060079 self.assertTrue(expect_called,
Alex Klein2bfacb22019-02-04 11:42:17 -070080 'The implementation should not have been called.')
Alex Klein2bfacb22019-02-04 11:42:17 -070081
Alex Klein00aa8072019-04-15 16:36:00 -060082 return impl
Alex Klein2bfacb22019-02-04 11:42:17 -070083
Alex Kleinbd6edf82019-07-18 10:30:49 -060084 def _writeChrootCallOutput(self, content='{}'):
85 def impl(*_args, **_kwargs):
86 """Side effect for inside-chroot calls to the API."""
87 osutils.WriteFile(
88 os.path.join(self.subprocess_tempdir,
89 router.Router.REEXEC_OUTPUT_FILE),
90 content)
91
92 return impl
93
Alex Klein00aa8072019-04-15 16:36:00 -060094 def testInsideServiceInsideMethodInsideChroot(self):
95 """Test inside/inside/inside works correctly."""
96 self.PatchObject(self.router, '_GetMethod',
97 return_value=self._mock_callable(expect_called=True))
98 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Klein2bfacb22019-02-04 11:42:17 -070099 self.router.Route('chromite.api.InsideChrootApiService',
Alex Klein5bcb4d22019-03-21 13:51:54 -0600100 'InsideServiceInsideMethod', self.input_file,
101 self.output_file)
Alex Klein2bfacb22019-02-04 11:42:17 -0700102
Alex Klein00aa8072019-04-15 16:36:00 -0600103 def testInsideServiceOutsideMethodOutsideChroot(self):
104 """Test the outside method override works as expected."""
105 self.PatchObject(self.router, '_GetMethod',
106 return_value=self._mock_callable(expect_called=True))
107 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=False)
108 self.router.Route('chromite.api.InsideChrootApiService',
109 'InsideServiceOutsideMethod', self.input_file,
110 self.output_file)
111
112 def testInsideServiceInsideMethodOutsideChroot(self):
113 """Test calling an inside method from outside the chroot."""
114 self.PatchObject(self.router, '_GetMethod',
115 return_value=self._mock_callable(expect_called=False))
116 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=False)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600117 self.rc.SetDefaultCmdResult(side_effect=self._writeChrootCallOutput())
Alex Klein00aa8072019-04-15 16:36:00 -0600118
119 service = 'chromite.api.InsideChrootApiService'
120 method = 'InsideServiceInsideMethod'
121 service_method = '%s/%s' % (service, method)
122 self.router.Route(service, method, self.input_file, self.output_file)
123
Alex Kleinc05f3d12019-05-29 14:16:21 -0600124 self.assertCommandContains(['build_api', service_method], enter_chroot=True)
Alex Klein00aa8072019-04-15 16:36:00 -0600125
126 def testInsideServiceOutsideMethodInsideChroot(self):
127 """Test inside chroot for outside method raises an error."""
128 self.PatchObject(self.router, '_GetMethod',
129 return_value=self._mock_callable(expect_called=False))
130 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Klein2bfacb22019-02-04 11:42:17 -0700131 with self.assertRaises(cros_build_lib.DieSystemExit):
132 self.router.Route('chromite.api.InsideChrootApiService',
Alex Klein5bcb4d22019-03-21 13:51:54 -0600133 'InsideServiceOutsideMethod', self.input_file,
134 self.output_file)
Alex Klein2bfacb22019-02-04 11:42:17 -0700135
Alex Klein00aa8072019-04-15 16:36:00 -0600136 def testOutsideServiceOutsideMethodOutsideChroot(self):
137 """Test outside/outside/outside works correctly."""
138 self.PatchObject(self.router, '_GetMethod',
139 return_value=self._mock_callable(expect_called=True))
140 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=False)
Alex Klein2bfacb22019-02-04 11:42:17 -0700141 self.router.Route('chromite.api.OutsideChrootApiService',
Alex Klein5bcb4d22019-03-21 13:51:54 -0600142 'OutsideServiceOutsideMethod', self.input_file,
143 self.output_file)
Alex Klein2bfacb22019-02-04 11:42:17 -0700144
Alex Klein00aa8072019-04-15 16:36:00 -0600145 def testOutsideServiceInsideMethodInsideChroot(self):
146 """Test the inside method assertion override works properly."""
147 self.PatchObject(self.router, '_GetMethod',
148 return_value=self._mock_callable(expect_called=True))
149 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=True)
Alex Klein2bfacb22019-02-04 11:42:17 -0700150 self.router.Route('chromite.api.OutsideChrootApiService',
Alex Klein5bcb4d22019-03-21 13:51:54 -0600151 'OutsideServiceInsideMethod', self.input_file,
152 self.output_file)
Alex Klein00aa8072019-04-15 16:36:00 -0600153
154 def testOutsideServiceInsideMethodOutsideChroot(self):
155 """Test calling an inside override method from outside the chroot."""
156 self.PatchObject(self.router, '_GetMethod',
157 return_value=self._mock_callable(expect_called=False))
158 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=False)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600159 self.rc.SetDefaultCmdResult(side_effect=self._writeChrootCallOutput())
Alex Klein00aa8072019-04-15 16:36:00 -0600160
161 service = 'chromite.api.OutsideChrootApiService'
162 method = 'OutsideServiceInsideMethod'
163 service_method = '%s/%s' % (service, method)
164 self.router.Route(service, method, self.input_file, self.output_file)
165
Alex Kleinc05f3d12019-05-29 14:16:21 -0600166 self.assertCommandContains(['build_api', service_method], enter_chroot=True)
Alex Kleinbd6edf82019-07-18 10:30:49 -0600167
168 def testReexecNonemptyOutput(self):
169 """Test calling an inside chroot method that produced output."""
170 osutils.WriteFile(self.output_file, '')
171 self.PatchObject(self.router, '_GetMethod',
172 return_value=self._mock_callable(expect_called=False))
173 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=False)
174 self.rc.SetDefaultCmdResult(
175 side_effect=self._writeChrootCallOutput(content='{"result": "foo"}'))
176
177 service = 'chromite.api.OutsideChrootApiService'
178 method = 'OutsideServiceInsideMethod'
179 service_method = '%s/%s' % (service, method)
180 self.router.Route(service, method, self.input_file, self.output_file)
181
182 self.assertCommandContains(['build_api', service_method], enter_chroot=True)
183
184 # It should be writing the result out to our output file.
185 expected = build_api_test_pb2.TestResultMessage()
186 json_format.Parse('{"result": "foo"}', expected)
187 result = build_api_test_pb2.TestResultMessage()
188 json_format.Parse(osutils.ReadFile(self.output_file), result)
189 self.assertEqual(expected, result)
190
191 def testReexecEmptyOutput(self):
192 """Test calling an inside chroot method that produced no output."""
193 osutils.WriteFile(self.output_file, '')
194 self.PatchObject(self.router, '_GetMethod',
195 return_value=self._mock_callable(expect_called=False))
196 self.PatchObject(cros_build_lib, 'IsInsideChroot', return_value=False)
197 self.rc.SetDefaultCmdResult(returncode=1)
198
199 service = 'chromite.api.OutsideChrootApiService'
200 method = 'OutsideServiceInsideMethod'
201 service_method = '%s/%s' % (service, method)
202 self.router.Route(service, method, self.input_file, self.output_file)
203
204 self.assertCommandContains(['build_api', service_method], enter_chroot=True)
205 # It should be writing the empty message out.
206 self.assertFileContents(self.output_file, '{}')