blob: e97517b5e0a634a4ca0b46319858fa2defd5c230 [file] [log] [blame]
Girtsdba6ab22010-10-11 15:53:52 -07001#!/usr/bin/python
2
3# Copyright (c) 2010 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"""Regression tests for devserver."""
8
Dale Curtisc9aaf3a2011-08-09 15:47:40 -07009import json
Girtsdba6ab22010-10-11 15:53:52 -070010import os
11import signal
12import shutil
13import subprocess
14import sys
15import time
16import unittest
17import urllib2
18from xml.dom import minidom
19
20# Paths are relative to this script's base directory.
21STATIC_DIR = 'static'
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010022TEST_IMAGE_PATH = 'testdata/devserver'
23TEST_IMAGE_NAME = 'developer-test.gz'
24TEST_IMAGE = TEST_IMAGE_PATH + '/' + TEST_IMAGE_NAME
Girtsdba6ab22010-10-11 15:53:52 -070025TEST_FACTORY_CONFIG = 'testdata/devserver/miniomaha-test.conf'
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010026TEST_DATA_PATH = '/tmp/devserver-test'
Greg Spencerc8b59b22011-03-15 14:15:23 -070027TEST_CLIENT_PREFIX = 'ChromeOSUpdateEngine'
Girtsdba6ab22010-10-11 15:53:52 -070028
Girtsdba6ab22010-10-11 15:53:52 -070029UPDATE_REQUEST = """<?xml version="1.0" encoding="UTF-8"?>
Greg Spencerc8b59b22011-03-15 14:15:23 -070030<o:gupdate xmlns:o="http://www.google.com/update2/request" version="ChromeOSUpdateEngine-0.1.0.0" updaterversion="ChromeOSUpdateEngine-0.1.0.0" protocol="2.0" ismachine="1">
31 <o:os version="Indy" platform="Chrome OS" sp="0.11.254.2011_03_09_1814_i686"></o:os>
32 <o:app appid="{DEV-BUILD}" version="0.11.254.2011_03_09_1814" lang="en-US" track="developer-build" board="x86-generic" hardware_class="BETA DVT" delta_okay="true">
33 <o:updatecheck></o:updatecheck>
34 <o:event eventtype="3" eventresult="2" previousversion="0.11.216.2011_03_02_1358"></o:event>
35 </o:app>
Girtsdba6ab22010-10-11 15:53:52 -070036</o:gupdate>
37"""
38# TODO(girts): use a random available port.
39UPDATE_URL = 'http://127.0.0.1:8080/update'
40
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070041API_HOST_INFO_BAD_URL = 'http://127.0.0.1:8080/api/hostinfo/'
42API_HOST_INFO_URL = API_HOST_INFO_BAD_URL + '127.0.0.1'
43
44API_SET_UPDATE_BAD_URL = 'http://127.0.0.1:8080/api/setnextupdate/'
45API_SET_UPDATE_URL = API_SET_UPDATE_BAD_URL + '127.0.0.1'
46
47API_SET_UPDATE_REQUEST = 'new_update-test/the-new-update'
48
Zdenek Behan1347a312011-02-10 03:59:17 +010049# Run all tests while being in /
50base_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
51os.chdir("/")
Girtsdba6ab22010-10-11 15:53:52 -070052
53class DevserverTest(unittest.TestCase):
54 """Regressions tests for devserver."""
55
56 def setUp(self):
57 """Copies in testing files."""
Girtsdba6ab22010-10-11 15:53:52 -070058
59 # Copy in developer-test.gz, as "static/" directory is hardcoded, and it
60 # would be very hard to change it (static file serving is handled deep
61 # inside webpy).
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010062 self.image_src = os.path.join(base_dir, TEST_IMAGE)
63 self.image = os.path.join(base_dir, STATIC_DIR, TEST_IMAGE_NAME)
Girtsdba6ab22010-10-11 15:53:52 -070064 if os.path.exists(self.image):
65 os.unlink(self.image)
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010066 shutil.copy(self.image_src, self.image)
Girtsdba6ab22010-10-11 15:53:52 -070067
68 self.factory_config = os.path.join(base_dir, TEST_FACTORY_CONFIG)
69
70 def tearDown(self):
71 """Removes testing files."""
72 if os.path.exists(self.image):
73 os.unlink(self.image)
74
75 def testValidateFactoryConfig(self):
76 """Tests --validate_factory_config."""
77 cmd = [
78 'python',
Zdenek Behan1347a312011-02-10 03:59:17 +010079 os.path.join(base_dir, 'devserver.py'),
Girtsdba6ab22010-10-11 15:53:52 -070080 '--validate_factory_config',
Greg Spencerc8b59b22011-03-15 14:15:23 -070081 '--client_prefix', TEST_CLIENT_PREFIX,
Girtsdba6ab22010-10-11 15:53:52 -070082 '--factory_config', self.factory_config,
83 ]
84 process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
85 stdout, _ = process.communicate()
86 self.assertEqual(0, process.returncode)
87 self.assertTrue('Config file looks good.' in stdout)
88
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010089 def _StartServer(self, data_dir=''):
Girtsdba6ab22010-10-11 15:53:52 -070090 """Starts devserver, returns process."""
91 cmd = [
92 'python',
Zdenek Behan1347a312011-02-10 03:59:17 +010093 os.path.join(base_dir, 'devserver.py'),
Girtsdba6ab22010-10-11 15:53:52 -070094 'devserver.py',
Greg Spencerc8b59b22011-03-15 14:15:23 -070095 '--client_prefix', TEST_CLIENT_PREFIX,
Girtsdba6ab22010-10-11 15:53:52 -070096 '--factory_config', self.factory_config,
97 ]
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010098 if data_dir:
99 cmd.append('--data_dir')
100 cmd.append(data_dir)
Girtsdba6ab22010-10-11 15:53:52 -0700101 process = subprocess.Popen(cmd)
102 return process.pid
103
104 def testHandleUpdate(self):
105 """Tests running the server and getting an update."""
106 pid = self._StartServer()
107 try:
108 # Wait for the server to start up.
109 time.sleep(1)
110 request = urllib2.Request(UPDATE_URL, UPDATE_REQUEST)
111 connection = urllib2.urlopen(request)
112 response = connection.read()
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100113 connection.close()
Girtsdba6ab22010-10-11 15:53:52 -0700114 self.assertNotEqual('', response)
115
116 # Parse the response and check if it contains the right result.
117 dom = minidom.parseString(response)
118 update = dom.getElementsByTagName('updatecheck')[0]
119
120 codebase = update.getAttribute('codebase')
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100121 self.assertEqual('http://127.0.0.1:8080/static/' + TEST_IMAGE_NAME,
Girtsdba6ab22010-10-11 15:53:52 -0700122 codebase)
123
124 hash_value = update.getAttribute('hash')
125 self.assertEqual('kGcOinJ0vA8vdYX53FN0F5BdwfY=', hash_value)
126
127 # Try to fetch the image.
128 connection = urllib2.urlopen(codebase)
129 contents = connection.read()
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100130 connection.close()
Girtsdba6ab22010-10-11 15:53:52 -0700131 self.assertEqual('Developers, developers, developers!\n', contents)
132 finally:
133 os.kill(pid, signal.SIGKILL)
134
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100135 def testHandleDatadirUpdate(self):
136 """Tests getting an update from a specified datadir"""
137 # Push the image to the expected path where devserver picks it up.
138 image_path = os.path.join(TEST_DATA_PATH, STATIC_DIR)
139 if not os.path.exists(image_path):
140 os.makedirs(image_path)
141
142 foreign_image = os.path.join(image_path, TEST_IMAGE_NAME)
143 if os.path.exists(foreign_image):
144 os.unlink(foreign_image)
145 shutil.copy(self.image_src, foreign_image)
146
147 pid = self._StartServer(data_dir=TEST_DATA_PATH)
148 try:
149 # Wait for the server to start up.
150 time.sleep(1)
151
152 request = urllib2.Request(UPDATE_URL, UPDATE_REQUEST)
153 connection = urllib2.urlopen(request)
154 response = connection.read()
155 connection.close()
156 self.assertNotEqual('', response)
157
158 # Parse the response and check if it contains the right result.
159 dom = minidom.parseString(response)
160 update = dom.getElementsByTagName('updatecheck')[0]
161
162 codebase = update.getAttribute('codebase')
163 self.assertEqual('http://127.0.0.1:8080/static/' + TEST_IMAGE_NAME,
164 codebase)
165
166 hash_value = update.getAttribute('hash')
167 self.assertEqual('kGcOinJ0vA8vdYX53FN0F5BdwfY=', hash_value)
168
169 # Try to fetch the image.
170 connection = urllib2.urlopen(codebase)
171 contents = connection.read()
172 connection.close()
173 self.assertEqual('Developers, developers, developers!\n', contents)
174 os.unlink(foreign_image)
175 finally:
176 os.kill(pid, signal.SIGKILL)
177
Dale Curtisc9aaf3a2011-08-09 15:47:40 -0700178 def testApiBadSetNextUpdateRequest(self):
179 """Tests sending a bad setnextupdate request."""
180 pid = self._StartServer()
181 try:
182 # Wait for the server to start up.
183 time.sleep(1)
184
185 # Send bad request and ensure it fails...
186 try:
187 request = urllib2.Request(API_SET_UPDATE_URL, '')
188 connection = urllib2.urlopen(request)
189 connection.read()
190 connection.close()
191 self.fail('Invalid setnextupdate request did not fail!')
192 except urllib2.URLError:
193 pass
194 finally:
195 os.kill(pid, signal.SIGKILL)
196
197 def testApiBadSetNextUpdateURL(self):
198 """Tests contacting a bad setnextupdate url."""
199 pid = self._StartServer()
200 try:
201 # Wait for the server to start up.
202 time.sleep(1)
203
204 # Send bad request and ensure it fails...
205 try:
206 connection = urllib2.urlopen(API_SET_UPDATE_BAD_URL)
207 connection.read()
208 connection.close()
209 self.fail('Invalid setnextupdate url did not fail!')
210 except urllib2.URLError:
211 pass
212 finally:
213 os.kill(pid, signal.SIGKILL)
214
215 def testApiBadHostInfoURL(self):
216 """Tests contacting a bad hostinfo url."""
217 pid = self._StartServer()
218 try:
219 # Wait for the server to start up.
220 time.sleep(1)
221
222 # Send bad request and ensure it fails...
223 try:
224 connection = urllib2.urlopen(API_HOST_INFO_BAD_URL)
225 connection.read()
226 connection.close()
227 self.fail('Invalid hostinfo url did not fail!')
228 except urllib2.URLError:
229 pass
230 finally:
231 os.kill(pid, signal.SIGKILL)
232
233 def testApiHostInfoAndSetNextUpdate(self):
234 """Tests using the setnextupdate and hostinfo api commands."""
235 pid = self._StartServer()
236 try:
237 # Wait for the server to start up.
238 time.sleep(1)
239
240 # Send setnextupdate command.
241 request = urllib2.Request(API_SET_UPDATE_URL, API_SET_UPDATE_REQUEST)
242 connection = urllib2.urlopen(request)
243 response = connection.read()
244 connection.close()
245
246 # Send hostinfo command and verify the setnextupdate worked.
247 connection = urllib2.urlopen(API_HOST_INFO_URL)
248 response = connection.read()
249 connection.close()
250
251 self.assertEqual(
252 json.loads(response)['forced_update_label'], API_SET_UPDATE_REQUEST)
253 finally:
254 os.kill(pid, signal.SIGKILL)
255
Girtsdba6ab22010-10-11 15:53:52 -0700256
257if __name__ == '__main__':
258 unittest.main()