blob: bfcd85c15f2376503fbe189eca93eb0a01a46bcf [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',
81 '--factory_config', self.factory_config,
82 ]
83 process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
84 stdout, _ = process.communicate()
85 self.assertEqual(0, process.returncode)
86 self.assertTrue('Config file looks good.' in stdout)
87
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010088 def _StartServer(self, data_dir=''):
Girtsdba6ab22010-10-11 15:53:52 -070089 """Starts devserver, returns process."""
90 cmd = [
91 'python',
Zdenek Behan1347a312011-02-10 03:59:17 +010092 os.path.join(base_dir, 'devserver.py'),
Girtsdba6ab22010-10-11 15:53:52 -070093 'devserver.py',
94 '--factory_config', self.factory_config,
95 ]
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010096 if data_dir:
97 cmd.append('--data_dir')
98 cmd.append(data_dir)
Girtsdba6ab22010-10-11 15:53:52 -070099 process = subprocess.Popen(cmd)
100 return process.pid
101
102 def testHandleUpdate(self):
103 """Tests running the server and getting an update."""
104 pid = self._StartServer()
105 try:
106 # Wait for the server to start up.
107 time.sleep(1)
108 request = urllib2.Request(UPDATE_URL, UPDATE_REQUEST)
109 connection = urllib2.urlopen(request)
110 response = connection.read()
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100111 connection.close()
Girtsdba6ab22010-10-11 15:53:52 -0700112 self.assertNotEqual('', response)
113
114 # Parse the response and check if it contains the right result.
115 dom = minidom.parseString(response)
116 update = dom.getElementsByTagName('updatecheck')[0]
117
118 codebase = update.getAttribute('codebase')
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100119 self.assertEqual('http://127.0.0.1:8080/static/' + TEST_IMAGE_NAME,
Girtsdba6ab22010-10-11 15:53:52 -0700120 codebase)
121
122 hash_value = update.getAttribute('hash')
123 self.assertEqual('kGcOinJ0vA8vdYX53FN0F5BdwfY=', hash_value)
124
125 # Try to fetch the image.
126 connection = urllib2.urlopen(codebase)
127 contents = connection.read()
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100128 connection.close()
Girtsdba6ab22010-10-11 15:53:52 -0700129 self.assertEqual('Developers, developers, developers!\n', contents)
130 finally:
131 os.kill(pid, signal.SIGKILL)
132
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100133 def testHandleDatadirUpdate(self):
134 """Tests getting an update from a specified datadir"""
135 # Push the image to the expected path where devserver picks it up.
136 image_path = os.path.join(TEST_DATA_PATH, STATIC_DIR)
137 if not os.path.exists(image_path):
138 os.makedirs(image_path)
139
140 foreign_image = os.path.join(image_path, TEST_IMAGE_NAME)
141 if os.path.exists(foreign_image):
142 os.unlink(foreign_image)
143 shutil.copy(self.image_src, foreign_image)
144
145 pid = self._StartServer(data_dir=TEST_DATA_PATH)
146 try:
147 # Wait for the server to start up.
148 time.sleep(1)
149
150 request = urllib2.Request(UPDATE_URL, UPDATE_REQUEST)
151 connection = urllib2.urlopen(request)
152 response = connection.read()
153 connection.close()
154 self.assertNotEqual('', response)
155
156 # Parse the response and check if it contains the right result.
157 dom = minidom.parseString(response)
158 update = dom.getElementsByTagName('updatecheck')[0]
159
160 codebase = update.getAttribute('codebase')
161 self.assertEqual('http://127.0.0.1:8080/static/' + TEST_IMAGE_NAME,
162 codebase)
163
164 hash_value = update.getAttribute('hash')
165 self.assertEqual('kGcOinJ0vA8vdYX53FN0F5BdwfY=', hash_value)
166
167 # Try to fetch the image.
168 connection = urllib2.urlopen(codebase)
169 contents = connection.read()
170 connection.close()
171 self.assertEqual('Developers, developers, developers!\n', contents)
172 os.unlink(foreign_image)
173 finally:
174 os.kill(pid, signal.SIGKILL)
175
Dale Curtisc9aaf3a2011-08-09 15:47:40 -0700176 def testApiBadSetNextUpdateRequest(self):
177 """Tests sending a bad setnextupdate request."""
178 pid = self._StartServer()
179 try:
180 # Wait for the server to start up.
181 time.sleep(1)
182
183 # Send bad request and ensure it fails...
184 try:
185 request = urllib2.Request(API_SET_UPDATE_URL, '')
186 connection = urllib2.urlopen(request)
187 connection.read()
188 connection.close()
189 self.fail('Invalid setnextupdate request did not fail!')
190 except urllib2.URLError:
191 pass
192 finally:
193 os.kill(pid, signal.SIGKILL)
194
195 def testApiBadSetNextUpdateURL(self):
196 """Tests contacting a bad setnextupdate url."""
197 pid = self._StartServer()
198 try:
199 # Wait for the server to start up.
200 time.sleep(1)
201
202 # Send bad request and ensure it fails...
203 try:
204 connection = urllib2.urlopen(API_SET_UPDATE_BAD_URL)
205 connection.read()
206 connection.close()
207 self.fail('Invalid setnextupdate url did not fail!')
208 except urllib2.URLError:
209 pass
210 finally:
211 os.kill(pid, signal.SIGKILL)
212
213 def testApiBadHostInfoURL(self):
214 """Tests contacting a bad hostinfo url."""
215 pid = self._StartServer()
216 try:
217 # Wait for the server to start up.
218 time.sleep(1)
219
220 # Send bad request and ensure it fails...
221 try:
222 connection = urllib2.urlopen(API_HOST_INFO_BAD_URL)
223 connection.read()
224 connection.close()
225 self.fail('Invalid hostinfo url did not fail!')
226 except urllib2.URLError:
227 pass
228 finally:
229 os.kill(pid, signal.SIGKILL)
230
231 def testApiHostInfoAndSetNextUpdate(self):
232 """Tests using the setnextupdate and hostinfo api commands."""
233 pid = self._StartServer()
234 try:
235 # Wait for the server to start up.
236 time.sleep(1)
237
238 # Send setnextupdate command.
239 request = urllib2.Request(API_SET_UPDATE_URL, API_SET_UPDATE_REQUEST)
240 connection = urllib2.urlopen(request)
241 response = connection.read()
242 connection.close()
243
244 # Send hostinfo command and verify the setnextupdate worked.
245 connection = urllib2.urlopen(API_HOST_INFO_URL)
246 response = connection.read()
247 connection.close()
248
249 self.assertEqual(
250 json.loads(response)['forced_update_label'], API_SET_UPDATE_REQUEST)
251 finally:
252 os.kill(pid, signal.SIGKILL)
253
Girtsdba6ab22010-10-11 15:53:52 -0700254
255if __name__ == '__main__':
256 unittest.main()