blob: 89c5d1958f37ac6d5cecaa2070ceaee9489d1bd6 [file] [log] [blame]
Luis Hector Chaveza1518052018-06-14 08:19:34 -07001#!/usr/bin/env python2
2# -*- coding: utf-8 -*-
Chris Sosa7cd23202013-10-15 17:22:57 -07003# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""Integration tests for the devserver.
8
9This module is responsible for testing the actual devserver APIs and should be
10run whenever changes are made to the devserver.
11
xixuan52c2fba2016-05-20 17:02:48 -070012To run the integration test for devserver:
13 python ./devserver_integration_test.py
Chris Sosa7cd23202013-10-15 17:22:57 -070014"""
15
Gabe Black3b567202015-09-23 14:07:59 -070016from __future__ import print_function
17
Chris Sosa7cd23202013-10-15 17:22:57 -070018import os
Chris Sosa7cd23202013-10-15 17:22:57 -070019import shutil
Gilad Arnold7de05f72014-02-14 13:14:20 -080020import socket
Chris Sosa7cd23202013-10-15 17:22:57 -070021import subprocess
Amin Hassaniba847c82019-12-06 16:30:56 -080022import sys
Chris Sosa7cd23202013-10-15 17:22:57 -070023import tempfile
24import time
25import unittest
Chris Sosa7cd23202013-10-15 17:22:57 -070026
Amin Hassani0b4843b2019-09-25 16:38:56 -070027from string import Template
28
Amin Hassani6eec8792020-01-09 14:06:48 -080029import requests
30
Amin Hassani469f5702019-10-21 15:35:06 -070031import psutil # pylint: disable=import-error
32
Amin Hassani469f5702019-10-21 15:35:06 -070033import setup_chromite # pylint: disable=unused-import
Luis Hector Chaveza1518052018-06-14 08:19:34 -070034from chromite.lib import cros_logging as logging
Achuith Bhandarkar662fb722019-10-31 16:12:49 -070035from chromite.lib.xbuddy import devserver_constants
Luis Hector Chaveza1518052018-06-14 08:19:34 -070036
Chris Sosa7cd23202013-10-15 17:22:57 -070037
38# Paths are relative to this script's base directory.
39LABEL = 'devserver'
40TEST_IMAGE_PATH = 'testdata/devserver'
Amin Hassani0b4843b2019-09-25 16:38:56 -070041TEST_UPDATE_PAYLOAD_NAME = 'update.gz'
42TEST_UPDATE_PAYLOAD_METADATA_NAME = 'update.gz.json'
Chris Sosa7cd23202013-10-15 17:22:57 -070043
44# Update request based on Omaha v3 protocol format.
Amin Hassani0b4843b2019-09-25 16:38:56 -070045UPDATE_REQUEST = Template("""<?xml version="1.0" encoding="UTF-8"?>
Amin Hassani495f1de2019-02-26 11:13:39 -080046<request protocol="3.0" updater="ChromeOSUpdateEngine" updaterversion="0.1.0.0" ismachine="1">
Chris Sosa7cd23202013-10-15 17:22:57 -070047 <os version="Indy" platform="Chrome OS" sp="0.11.254.2011_03_09_1814_i686"></os>
Amin Hassani0b4843b2019-09-25 16:38:56 -070048 <app appid="$appid" version="11.254.2011_03_09_1814" lang="en-US" track="developer-build" board="x86-generic" hardware_class="BETA DVT" delta_okay="true">
Chris Sosa7cd23202013-10-15 17:22:57 -070049 <updatecheck></updatecheck>
50 </app>
51</request>
Amin Hassani0b4843b2019-09-25 16:38:56 -070052""")
Chris Sosa7cd23202013-10-15 17:22:57 -070053
54# RPC constants.
55STAGE = 'stage'
56IS_STAGED = 'is_staged'
57STATIC = 'static'
58UPDATE = 'update'
59CHECK_HEALTH = 'check_health'
60CONTROL_FILES = 'controlfiles'
61XBUDDY = 'xbuddy'
Prashanth Ba06d2d22014-03-07 15:35:19 -080062LIST_IMAGE_DIR = 'list_image_dir'
Chris Sosa7cd23202013-10-15 17:22:57 -070063
64# API rpcs and constants.
Chris Sosa7cd23202013-10-15 17:22:57 -070065API_SET_UPDATE_REQUEST = 'new_update-test/the-new-update'
66API_TEST_IP_ADDR = '127.0.0.1'
67
68DEVSERVER_START_TIMEOUT = 15
Gilad Arnold08516112014-02-14 13:14:03 -080069DEVSERVER_START_SLEEP = 1
Gilad Arnold7de05f72014-02-14 13:14:20 -080070MAX_START_ATTEMPTS = 5
Chris Sosa7cd23202013-10-15 17:22:57 -070071
72
73class DevserverFailedToStart(Exception):
74 """Raised if we could not start the devserver."""
75
76
Gilad Arnold08516112014-02-14 13:14:03 -080077class DevserverTestBase(unittest.TestCase):
Chris Sosa7cd23202013-10-15 17:22:57 -070078 """Class containing common logic between devserver test classes."""
79
80 def setUp(self):
Gilad Arnold08516112014-02-14 13:14:03 -080081 """Creates and populates a test directory, temporary files."""
Chris Sosa7cd23202013-10-15 17:22:57 -070082 self.test_data_path = tempfile.mkdtemp()
83 self.src_dir = os.path.dirname(__file__)
84
Gilad Arnold08516112014-02-14 13:14:03 -080085 # Copy the payload to the location of the update label.
Amin Hassani0b4843b2019-09-25 16:38:56 -070086 self._CreateLabelAndCopyUpdatePayloadFiles(LABEL)
Chris Sosa7cd23202013-10-15 17:22:57 -070087
88 # Copy the payload to the location of forced label.
Amin Hassani0b4843b2019-09-25 16:38:56 -070089 self._CreateLabelAndCopyUpdatePayloadFiles(API_SET_UPDATE_REQUEST)
Chris Sosa7cd23202013-10-15 17:22:57 -070090
Gilad Arnold08516112014-02-14 13:14:03 -080091 # Allocate temporary files for various devserver outputs.
92 self.pidfile = self._MakeTempFile('pid')
93 self.portfile = self._MakeTempFile('port')
94 self.logfile = self._MakeTempFile('log')
Chris Sosa7cd23202013-10-15 17:22:57 -070095
Gilad Arnold08516112014-02-14 13:14:03 -080096 # Initialize various runtime values.
97 self.devserver_url = self.port = self.pid = None
Amin Hassaniba847c82019-12-06 16:30:56 -080098 self.devserver = None
Chris Sosa7cd23202013-10-15 17:22:57 -070099
100 def tearDown(self):
Gilad Arnold08516112014-02-14 13:14:03 -0800101 """Kill the server, remove the test directory and temporary files."""
Amin Hassaniba847c82019-12-06 16:30:56 -0800102
103 self._StopServer()
Chris Sosa7cd23202013-10-15 17:22:57 -0700104
Gilad Arnold08516112014-02-14 13:14:03 -0800105 self._RemoveFile(self.pidfile)
106 self._RemoveFile(self.portfile)
Amin Hassaniba847c82019-12-06 16:30:56 -0800107 # If the unittest did not succeed, print out the devserver log.
108 if sys.exc_info() != (None, None, None):
109 with open(self.logfile, 'r') as f:
110 logging.info('--- BEGINNING OF DEVSERVER LOG ---')
111 logging.info(f.read())
112 logging.info('--- ENDING OF DEVSERVER LOG ---')
Gilad Arnold08516112014-02-14 13:14:03 -0800113 self._RemoveFile(self.logfile)
114 shutil.rmtree(self.test_data_path)
Chris Sosa7cd23202013-10-15 17:22:57 -0700115
116 # Helper methods begin here.
117
Amin Hassani0b4843b2019-09-25 16:38:56 -0700118 def _CreateLabelAndCopyUpdatePayloadFiles(self, label):
Gilad Arnold08516112014-02-14 13:14:03 -0800119 """Creates a label location and copies an image to it."""
Amin Hassani0b4843b2019-09-25 16:38:56 -0700120 update_dir = os.path.join(self.src_dir, TEST_IMAGE_PATH)
Gilad Arnold08516112014-02-14 13:14:03 -0800121 label_dir = os.path.join(self.test_data_path, label)
122 os.makedirs(label_dir)
Amin Hassani0b4843b2019-09-25 16:38:56 -0700123 for name in (TEST_UPDATE_PAYLOAD_NAME, TEST_UPDATE_PAYLOAD_METADATA_NAME):
124 shutil.copy(os.path.join(update_dir, name), label_dir)
Gilad Arnold08516112014-02-14 13:14:03 -0800125
126 def _MakeTempFile(self, suffix):
127 """Return path of a newly created temporary file."""
128 with tempfile.NamedTemporaryFile(suffix='-devserver-%s' % suffix) as f:
129 name = f.name
130 f.close()
131
132 return name
133
134 def _RemoveFile(self, filename):
135 """Removes a file if it is present."""
136 if os.path.isfile(filename):
137 os.remove(filename)
138
139 def _ReadIntValueFromFile(self, path, desc):
140 """Reads a string from file and returns its conversion into an integer."""
141 if not os.path.isfile(path):
142 raise DevserverFailedToStart('Devserver did not drop %s (%r).' %
143 (desc, path))
144
145 with open(path) as f:
146 value_str = f.read()
147
148 try:
149 return int(value_str)
150 except ValueError:
151 raise DevserverFailedToStart('Devserver did not drop a valid value '
152 'in %s (%r).' % (desc, value_str))
153
154 def _StartServer(self, port=0):
Chris Sosa7cd23202013-10-15 17:22:57 -0700155 """Attempts to start devserver on |port|.
156
Gilad Arnold08516112014-02-14 13:14:03 -0800157 In the default case where port == 0, the server will bind to an arbitrary
Dan Shi2f136862016-02-11 15:38:38 -0800158 available port. If successful, this method will set the devserver's pid
Gilad Arnold08516112014-02-14 13:14:03 -0800159 (self.pid), actual listening port (self.port) and URL (self.devserver_url).
Chris Sosa7cd23202013-10-15 17:22:57 -0700160
161 Raises:
162 DevserverFailedToStart: If the devserver could not be started.
163 """
164 cmd = [
Chris Sosa7cd23202013-10-15 17:22:57 -0700165 os.path.join(self.src_dir, 'devserver.py'),
Chris Sosa7cd23202013-10-15 17:22:57 -0700166 '--static_dir', self.test_data_path,
167 '--pidfile', self.pidfile,
Gilad Arnold08516112014-02-14 13:14:03 -0800168 '--portfile', self.portfile,
Chris Sosa7cd23202013-10-15 17:22:57 -0700169 '--port', str(port),
Amin Hassaniba847c82019-12-06 16:30:56 -0800170 '--logfile', self.logfile,
171 ]
Chris Sosa7cd23202013-10-15 17:22:57 -0700172
173 # Pipe all output. Use logfile to get devserver log.
Amin Hassaniba847c82019-12-06 16:30:56 -0800174 self.devserver = subprocess.Popen(cmd, stderr=subprocess.PIPE,
175 stdout=subprocess.PIPE)
Chris Sosa7cd23202013-10-15 17:22:57 -0700176
Gilad Arnold08516112014-02-14 13:14:03 -0800177 # Wait for devserver to start, determining its actual serving port and URL.
Chris Sosa7cd23202013-10-15 17:22:57 -0700178 current_time = time.time()
179 deadline = current_time + DEVSERVER_START_TIMEOUT
Amin Hassaniba847c82019-12-06 16:30:56 -0800180 error = None
Chris Sosa7cd23202013-10-15 17:22:57 -0700181 while current_time < deadline:
Chris Sosa7cd23202013-10-15 17:22:57 -0700182 try:
Gilad Arnold08516112014-02-14 13:14:03 -0800183 self.port = self._ReadIntValueFromFile(self.portfile, 'portfile')
184 self.devserver_url = 'http://127.0.0.1:%d' % self.port
Gabe Black3b567202015-09-23 14:07:59 -0700185 self._MakeRPC(CHECK_HEALTH, timeout=1)
Chris Sosa7cd23202013-10-15 17:22:57 -0700186 break
Amin Hassaniba847c82019-12-06 16:30:56 -0800187 except Exception as e:
188 error = e
Gilad Arnold08516112014-02-14 13:14:03 -0800189 time.sleep(DEVSERVER_START_SLEEP)
190 current_time = time.time()
Chris Sosa7cd23202013-10-15 17:22:57 -0700191 else:
Amin Hassaniba847c82019-12-06 16:30:56 -0800192 raise DevserverFailedToStart(
193 'Devserver failed to start within timeout with error: %s' % error)
Chris Sosa7cd23202013-10-15 17:22:57 -0700194
Gilad Arnold08516112014-02-14 13:14:03 -0800195 # Retrieve PID.
196 self.pid = self._ReadIntValueFromFile(self.pidfile, 'pidfile')
Chris Sosa7cd23202013-10-15 17:22:57 -0700197
Amin Hassaniba847c82019-12-06 16:30:56 -0800198 def _StopServer(self):
199 """Stops the current running devserver."""
200 if not self.pid:
201 return
202
203 self.devserver.terminate()
204
205 # Just to flush the stdout/stderr so python3 doesn't complain about the
206 # unclosed file.
207 self.devserver.communicate()
208
209 self.devserver.wait()
210
211 self.pid = None
212 self.devserver = None
213
Chris Sosa7cd23202013-10-15 17:22:57 -0700214 def _MakeRPC(self, rpc, data=None, timeout=None, **kwargs):
Gilad Arnold08516112014-02-14 13:14:03 -0800215 """Makes an RPC call to the devserver.
Chris Sosa7cd23202013-10-15 17:22:57 -0700216
217 Args:
Gilad Arnold08516112014-02-14 13:14:03 -0800218 rpc: The function to run on the devserver, e.g. 'stage'.
Chris Sosa7cd23202013-10-15 17:22:57 -0700219 data: Optional post data to send.
220 timeout: Optional timeout to pass to urlopen.
Gilad Arnold08516112014-02-14 13:14:03 -0800221 kwargs: Optional arguments to the function, e.g. artifact_url='foo/bar'.
Chris Sosa7cd23202013-10-15 17:22:57 -0700222
Gilad Arnold08516112014-02-14 13:14:03 -0800223 Returns:
224 The function output.
Chris Sosa7cd23202013-10-15 17:22:57 -0700225 """
226 request = '/'.join([self.devserver_url, rpc])
227 if kwargs:
228 # Join the kwargs to the URL.
Amin Hassani6eec8792020-01-09 14:06:48 -0800229 request += '?' + '&'.join('%s=%s' % (k, v) for k, v in kwargs.items())
Chris Sosa7cd23202013-10-15 17:22:57 -0700230
Amin Hassani6eec8792020-01-09 14:06:48 -0800231 response = (requests.post(request, data=data, timeout=timeout) if data
232 else requests.get(request, timeout=timeout))
233 response.raise_for_status()
234 return response.text
Chris Sosa7cd23202013-10-15 17:22:57 -0700235
236
Gilad Arnold08516112014-02-14 13:14:03 -0800237class AutoStartDevserverTestBase(DevserverTestBase):
238 """Test base class that automatically starts the devserver."""
239
240 def setUp(self):
241 """Initialize everything, then start the server."""
242 super(AutoStartDevserverTestBase, self).setUp()
243 self._StartServer()
244
245
Gilad Arnold7de05f72014-02-14 13:14:20 -0800246class DevserverStartTests(DevserverTestBase):
247 """Test that devserver starts up correctly."""
248
249 def testStartAnyPort(self):
250 """Starts the devserver, have it bind to an arbitrary available port."""
251 self._StartServer()
252
253 def testStartSpecificPort(self):
254 """Starts the devserver with a specific port."""
255 for _ in range(MAX_START_ATTEMPTS):
256 # This is a cheap hack to find an arbitrary unused port: we open a socket
257 # and bind it to port zero, then pull out the actual port number and
258 # close the socket. In all likelihood, this will leave us with an
259 # available port number that we can use for starting the devserver.
260 # However, this heuristic is susceptible to race conditions, hence the
261 # retry loop.
262 s = socket.socket()
263 s.bind(('', 0))
Gilad Arnold7de05f72014-02-14 13:14:20 -0800264 _, port = s.getsockname()
265 s.close()
266
267 self._StartServer(port=port)
Amin Hassaniba847c82019-12-06 16:30:56 -0800268 self._StopServer()
Gilad Arnold7de05f72014-02-14 13:14:20 -0800269
270
Gilad Arnold08516112014-02-14 13:14:03 -0800271class DevserverBasicTests(AutoStartDevserverTestBase):
272 """Short running tests for the devserver (no remote deps).
Chris Sosa7cd23202013-10-15 17:22:57 -0700273
274 These are technically not unittests because they depend on being able to
275 start a devserver locally which technically requires external resources so
276 they are lumped with the remote tests here.
277 """
278
Chris Sosa7cd23202013-10-15 17:22:57 -0700279 def testXBuddyLocalAlias(self):
280 """Extensive local image xbuddy unittest.
281
282 This test verifies all the local xbuddy logic by creating a new local folder
283 with the necessary update items and verifies we can use all of them.
284 """
Chris Sosa7cd23202013-10-15 17:22:57 -0700285 build_id = 'x86-generic/R32-9999.0.0-a1'
286 xbuddy_path = 'x86-generic/R32-9999.0.0-a1/test'
287 build_dir = os.path.join(self.test_data_path, build_id)
288 os.makedirs(build_dir)
Amin Hassani0b4843b2019-09-25 16:38:56 -0700289
290 # Writing dummy files.
291 image_data = 'TEST IMAGE'
Chris Sosa7cd23202013-10-15 17:22:57 -0700292 test_image_file = os.path.join(build_dir,
293 devserver_constants.TEST_IMAGE_FILE)
Amin Hassani0b4843b2019-09-25 16:38:56 -0700294 with open(test_image_file, 'w') as f:
295 f.write(image_data)
296
297 stateful_data = 'STATEFUL STUFFS'
Chris Sosa7cd23202013-10-15 17:22:57 -0700298 stateful_file = os.path.join(build_dir, devserver_constants.STATEFUL_FILE)
Amin Hassani0b4843b2019-09-25 16:38:56 -0700299 with open(stateful_file, 'w') as f:
300 f.write(stateful_data)
Chris Sosa7cd23202013-10-15 17:22:57 -0700301
Amin Hassani0b4843b2019-09-25 16:38:56 -0700302 update_dir = os.path.join(self.src_dir, TEST_IMAGE_PATH)
303 for name in (TEST_UPDATE_PAYLOAD_NAME, TEST_UPDATE_PAYLOAD_METADATA_NAME):
304 shutil.copy(os.path.join(update_dir, name), build_dir)
305 with open(os.path.join(build_dir, TEST_UPDATE_PAYLOAD_NAME), 'r') as f:
306 update_data = f.read()
Chris Sosa7cd23202013-10-15 17:22:57 -0700307
Amin Hassani0b4843b2019-09-25 16:38:56 -0700308 for item, data in zip(['full_payload', 'test', 'stateful'],
309 [update_data, image_data, stateful_data]):
Chris Sosa7cd23202013-10-15 17:22:57 -0700310
311 xbuddy_path = '/'.join([build_id, item])
312 logging.info('Testing xbuddy path %s', xbuddy_path)
Amin Hassani3de3e2b2020-10-19 13:34:10 -0700313 response = self._MakeRPC('/'.join([XBUDDY, xbuddy_path]), timeout=3)
Chris Sosa7cd23202013-10-15 17:22:57 -0700314 self.assertEqual(response, data)
315
316 expected_dir = '/'.join([self.devserver_url, STATIC, build_id])
317 response = self._MakeRPC('/'.join([XBUDDY, xbuddy_path]), return_dir=True)
318 self.assertEqual(response, expected_dir)
319
Yu-Ju Hong51495eb2013-12-12 17:08:43 -0800320 response = self._MakeRPC('/'.join([XBUDDY, xbuddy_path]),
321 relative_path=True)
322 self.assertEqual(response, build_id)
323
Chris Sosa7cd23202013-10-15 17:22:57 -0700324 def testPidFile(self):
325 """Test that using a pidfile works correctly."""
326 with open(self.pidfile, 'r') as f:
327 pid = f.read()
Chris Sosa7cd23202013-10-15 17:22:57 -0700328 # Let's assert some process information about the devserver.
Dan Shi2f136862016-02-11 15:38:38 -0800329 self.assertTrue(pid.strip().isdigit())
Chris Sosa7cd23202013-10-15 17:22:57 -0700330 process = psutil.Process(int(pid))
331 self.assertTrue(process.is_running())
Amin Hassaniba847c82019-12-06 16:30:56 -0800332 self.assertIn('./devserver.py', process.cmdline())
Chris Sosa7cd23202013-10-15 17:22:57 -0700333
Gilad Arnold08516112014-02-14 13:14:03 -0800334class DevserverExtendedTests(AutoStartDevserverTestBase):
Chris Sosa7cd23202013-10-15 17:22:57 -0700335 """Longer running integration tests that test interaction with Google Storage.
336
337 Note: due to the interaction with Google Storage, these tests both require
338 1) runner has access to the Google Storage bucket where builders store builds.
339 2) time. These tests actually download the artifacts needed.
340 """
341
Luis Hector Chaveza1518052018-06-14 08:19:34 -0700342 @unittest.skip('crbug.com/640063 Broken test.')
Chris Sosa7cd23202013-10-15 17:22:57 -0700343 def testStageAutotestAndGetPackages(self):
Luis Hector Chaveza1518052018-06-14 08:19:34 -0700344 """Another stage/update autotest workflow test with a test payload."""
345 build_id = 'eve-release/R69-10782.0.0'
Chris Sosa7cd23202013-10-15 17:22:57 -0700346 archive_url = 'gs://chromeos-image-archive/%s' % build_id
347 autotest_artifacts = 'autotest,test_suites,au_suite'
348 logging.info('Staging autotest artifacts (may take a while).')
349 self._MakeRPC(STAGE, archive_url=archive_url, artifacts=autotest_artifacts)
350
351 response = self._MakeRPC(IS_STAGED, archive_url=archive_url,
352 artifacts=autotest_artifacts)
353 self.assertEqual(response, 'True')
354
355 # Verify the files exist and are staged in the staging directory.
356 logging.info('Checking directories exist after we staged the files.')
357 staged_dir = os.path.join(self.test_data_path, build_id)
358 autotest_dir = os.path.join(staged_dir, 'autotest')
359 package_dir = os.path.join(autotest_dir, 'packages')
360 self.assertTrue(os.path.isdir(staged_dir))
361 self.assertTrue(os.path.isdir(autotest_dir))
362 self.assertTrue(os.path.isdir(package_dir))
363
364 control_files = self._MakeRPC(CONTROL_FILES, build=build_id,
365 suite_name='bvt')
366 logging.info('Checking for known control file in bvt suite.')
Amin Hassaniba847c82019-12-06 16:30:56 -0800367 self.assertIn('client/site_tests/platform_FilePerms/control', control_files)
Chris Sosa7cd23202013-10-15 17:22:57 -0700368
369 def testRemoteXBuddyAlias(self):
Luis Hector Chaveza1518052018-06-14 08:19:34 -0700370 """Another stage/update autotest workflow test with a test payload."""
371 build_id = 'eve-release/R69-10782.0.0'
372 xbuddy_path = 'remote/eve/R69-10782.0.0/full_payload'
373 xbuddy_bad_path = 'remote/eve/R32-9999.9999.9999'
Chris Sosa7cd23202013-10-15 17:22:57 -0700374 logging.info('Staging artifacts using xbuddy.')
375 response = self._MakeRPC('/'.join([XBUDDY, xbuddy_path]), return_dir=True)
376
377 logging.info('Verifying static url returned is valid.')
378 expected_static_url = '/'.join([self.devserver_url, STATIC, build_id])
379 self.assertEqual(response, expected_static_url)
380
Chris Sosa7cd23202013-10-15 17:22:57 -0700381 logging.info('Now give xbuddy a bad path.')
Amin Hassani6eec8792020-01-09 14:06:48 -0800382 self.assertRaises(requests.exceptions.RequestException,
Chris Sosa7cd23202013-10-15 17:22:57 -0700383 self._MakeRPC,
384 '/'.join([XBUDDY, xbuddy_bad_path]))
385
Prashanth Ba06d2d22014-03-07 15:35:19 -0800386 def testListImageDir(self):
387 """Verifies that we can list the contents of the image directory."""
388 build_id = 'x86-mario-release/R32-4810.0.0'
389 archive_url = 'gs://chromeos-image-archive/%s' % build_id
390 build_dir = os.path.join(self.test_data_path, build_id)
391 shutil.rmtree(build_dir, ignore_errors=True)
392
393 logging.info('checking for %s on an unstaged build.', LIST_IMAGE_DIR)
394 response = self._MakeRPC(LIST_IMAGE_DIR, archive_url=archive_url)
Amin Hassaniba847c82019-12-06 16:30:56 -0800395 self.assertIn(archive_url, response)
396 self.assertIn('not been staged', response)
Prashanth Ba06d2d22014-03-07 15:35:19 -0800397
398 logging.info('Checking for %s on a staged build.', LIST_IMAGE_DIR)
399 fake_file_name = 'fake_file'
400 try:
401 os.makedirs(build_dir)
402 open(os.path.join(build_dir, fake_file_name), 'w').close()
403 except OSError:
404 logging.error('Could not create files to imitate staged content. '
405 'Build dir %s, file %s', build_dir, fake_file_name)
406 raise
407 response = self._MakeRPC(LIST_IMAGE_DIR, archive_url=archive_url)
Amin Hassaniba847c82019-12-06 16:30:56 -0800408 self.assertIn(fake_file_name, response)
Prashanth Ba06d2d22014-03-07 15:35:19 -0800409 shutil.rmtree(build_dir, ignore_errors=True)
Chris Sosa7cd23202013-10-15 17:22:57 -0700410
Amin Hassani28df4212019-10-28 10:16:50 -0700411
Chris Sosa7cd23202013-10-15 17:22:57 -0700412if __name__ == '__main__':
Chris Sosa7cd23202013-10-15 17:22:57 -0700413 unittest.main()