blob: 815b5d7eb4c0c2c92868df160411bea3151dece0 [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
Gilad Arnoldabb352e2012-09-23 01:24:27 -07009from xml.dom import minidom
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070010import json
Girtsdba6ab22010-10-11 15:53:52 -070011import os
Girtsdba6ab22010-10-11 15:53:52 -070012import shutil
Gilad Arnoldabb352e2012-09-23 01:24:27 -070013import signal
Girtsdba6ab22010-10-11 15:53:52 -070014import subprocess
15import sys
16import time
17import unittest
18import urllib2
Gilad Arnoldabb352e2012-09-23 01:24:27 -070019
Girtsdba6ab22010-10-11 15:53:52 -070020
21# Paths are relative to this script's base directory.
22STATIC_DIR = 'static'
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010023TEST_IMAGE_PATH = 'testdata/devserver'
24TEST_IMAGE_NAME = 'developer-test.gz'
25TEST_IMAGE = TEST_IMAGE_PATH + '/' + TEST_IMAGE_NAME
Girtsdba6ab22010-10-11 15:53:52 -070026TEST_FACTORY_CONFIG = 'testdata/devserver/miniomaha-test.conf'
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010027TEST_DATA_PATH = '/tmp/devserver-test'
Greg Spencerc8b59b22011-03-15 14:15:23 -070028TEST_CLIENT_PREFIX = 'ChromeOSUpdateEngine'
Girtsdba6ab22010-10-11 15:53:52 -070029
Girtsdba6ab22010-10-11 15:53:52 -070030UPDATE_REQUEST = """<?xml version="1.0" encoding="UTF-8"?>
Greg Spencerc8b59b22011-03-15 14:15:23 -070031<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">
32 <o:os version="Indy" platform="Chrome OS" sp="0.11.254.2011_03_09_1814_i686"></o:os>
33 <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">
34 <o:updatecheck></o:updatecheck>
35 <o:event eventtype="3" eventresult="2" previousversion="0.11.216.2011_03_02_1358"></o:event>
36 </o:app>
Girtsdba6ab22010-10-11 15:53:52 -070037</o:gupdate>
38"""
39# TODO(girts): use a random available port.
40UPDATE_URL = 'http://127.0.0.1:8080/update'
41
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070042API_HOST_INFO_BAD_URL = 'http://127.0.0.1:8080/api/hostinfo/'
43API_HOST_INFO_URL = API_HOST_INFO_BAD_URL + '127.0.0.1'
44
45API_SET_UPDATE_BAD_URL = 'http://127.0.0.1:8080/api/setnextupdate/'
46API_SET_UPDATE_URL = API_SET_UPDATE_BAD_URL + '127.0.0.1'
47
48API_SET_UPDATE_REQUEST = 'new_update-test/the-new-update'
49
Zdenek Behan1347a312011-02-10 03:59:17 +010050# Run all tests while being in /
51base_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
52os.chdir("/")
Girtsdba6ab22010-10-11 15:53:52 -070053
54class DevserverTest(unittest.TestCase):
55 """Regressions tests for devserver."""
56
57 def setUp(self):
58 """Copies in testing files."""
Girtsdba6ab22010-10-11 15:53:52 -070059
60 # Copy in developer-test.gz, as "static/" directory is hardcoded, and it
61 # would be very hard to change it (static file serving is handled deep
62 # inside webpy).
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010063 self.image_src = os.path.join(base_dir, TEST_IMAGE)
64 self.image = os.path.join(base_dir, STATIC_DIR, TEST_IMAGE_NAME)
Girtsdba6ab22010-10-11 15:53:52 -070065 if os.path.exists(self.image):
66 os.unlink(self.image)
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010067 shutil.copy(self.image_src, self.image)
Girtsdba6ab22010-10-11 15:53:52 -070068
69 self.factory_config = os.path.join(base_dir, TEST_FACTORY_CONFIG)
70
71 def tearDown(self):
72 """Removes testing files."""
73 if os.path.exists(self.image):
74 os.unlink(self.image)
75
76 def testValidateFactoryConfig(self):
77 """Tests --validate_factory_config."""
78 cmd = [
79 'python',
Zdenek Behan1347a312011-02-10 03:59:17 +010080 os.path.join(base_dir, 'devserver.py'),
Girtsdba6ab22010-10-11 15:53:52 -070081 '--validate_factory_config',
82 '--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',
95 '--factory_config', self.factory_config,
96 ]
Zdenek Behan5d21a2a2011-02-12 02:06:01 +010097 if data_dir:
98 cmd.append('--data_dir')
99 cmd.append(data_dir)
Girtsdba6ab22010-10-11 15:53:52 -0700100 process = subprocess.Popen(cmd)
101 return process.pid
102
103 def testHandleUpdate(self):
104 """Tests running the server and getting an update."""
105 pid = self._StartServer()
106 try:
107 # Wait for the server to start up.
108 time.sleep(1)
109 request = urllib2.Request(UPDATE_URL, UPDATE_REQUEST)
110 connection = urllib2.urlopen(request)
111 response = connection.read()
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100112 connection.close()
Girtsdba6ab22010-10-11 15:53:52 -0700113 self.assertNotEqual('', response)
114
115 # Parse the response and check if it contains the right result.
116 dom = minidom.parseString(response)
117 update = dom.getElementsByTagName('updatecheck')[0]
118
119 codebase = update.getAttribute('codebase')
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100120 self.assertEqual('http://127.0.0.1:8080/static/' + TEST_IMAGE_NAME,
Girtsdba6ab22010-10-11 15:53:52 -0700121 codebase)
122
123 hash_value = update.getAttribute('hash')
124 self.assertEqual('kGcOinJ0vA8vdYX53FN0F5BdwfY=', hash_value)
125
126 # Try to fetch the image.
127 connection = urllib2.urlopen(codebase)
128 contents = connection.read()
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100129 connection.close()
Girtsdba6ab22010-10-11 15:53:52 -0700130 self.assertEqual('Developers, developers, developers!\n', contents)
131 finally:
132 os.kill(pid, signal.SIGKILL)
133
Zdenek Behan5d21a2a2011-02-12 02:06:01 +0100134 def testHandleDatadirUpdate(self):
135 """Tests getting an update from a specified datadir"""
136 # Push the image to the expected path where devserver picks it up.
137 image_path = os.path.join(TEST_DATA_PATH, STATIC_DIR)
138 if not os.path.exists(image_path):
139 os.makedirs(image_path)
140
141 foreign_image = os.path.join(image_path, TEST_IMAGE_NAME)
142 if os.path.exists(foreign_image):
143 os.unlink(foreign_image)
144 shutil.copy(self.image_src, foreign_image)
145
146 pid = self._StartServer(data_dir=TEST_DATA_PATH)
147 try:
148 # Wait for the server to start up.
149 time.sleep(1)
150
151 request = urllib2.Request(UPDATE_URL, UPDATE_REQUEST)
152 connection = urllib2.urlopen(request)
153 response = connection.read()
154 connection.close()
155 self.assertNotEqual('', response)
156
157 # Parse the response and check if it contains the right result.
158 dom = minidom.parseString(response)
159 update = dom.getElementsByTagName('updatecheck')[0]
160
161 codebase = update.getAttribute('codebase')
162 self.assertEqual('http://127.0.0.1:8080/static/' + TEST_IMAGE_NAME,
163 codebase)
164
165 hash_value = update.getAttribute('hash')
166 self.assertEqual('kGcOinJ0vA8vdYX53FN0F5BdwfY=', hash_value)
167
168 # Try to fetch the image.
169 connection = urllib2.urlopen(codebase)
170 contents = connection.read()
171 connection.close()
172 self.assertEqual('Developers, developers, developers!\n', contents)
173 os.unlink(foreign_image)
174 finally:
175 os.kill(pid, signal.SIGKILL)
176
Dale Curtisc9aaf3a2011-08-09 15:47:40 -0700177 def testApiBadSetNextUpdateRequest(self):
178 """Tests sending a bad setnextupdate request."""
179 pid = self._StartServer()
180 try:
181 # Wait for the server to start up.
182 time.sleep(1)
183
184 # Send bad request and ensure it fails...
185 try:
186 request = urllib2.Request(API_SET_UPDATE_URL, '')
187 connection = urllib2.urlopen(request)
188 connection.read()
189 connection.close()
190 self.fail('Invalid setnextupdate request did not fail!')
191 except urllib2.URLError:
192 pass
193 finally:
194 os.kill(pid, signal.SIGKILL)
195
196 def testApiBadSetNextUpdateURL(self):
197 """Tests contacting a bad setnextupdate url."""
198 pid = self._StartServer()
199 try:
200 # Wait for the server to start up.
201 time.sleep(1)
202
203 # Send bad request and ensure it fails...
204 try:
205 connection = urllib2.urlopen(API_SET_UPDATE_BAD_URL)
206 connection.read()
207 connection.close()
208 self.fail('Invalid setnextupdate url did not fail!')
209 except urllib2.URLError:
210 pass
211 finally:
212 os.kill(pid, signal.SIGKILL)
213
214 def testApiBadHostInfoURL(self):
215 """Tests contacting a bad hostinfo url."""
216 pid = self._StartServer()
217 try:
218 # Wait for the server to start up.
219 time.sleep(1)
220
221 # Send bad request and ensure it fails...
222 try:
223 connection = urllib2.urlopen(API_HOST_INFO_BAD_URL)
224 connection.read()
225 connection.close()
226 self.fail('Invalid hostinfo url did not fail!')
227 except urllib2.URLError:
228 pass
229 finally:
230 os.kill(pid, signal.SIGKILL)
231
232 def testApiHostInfoAndSetNextUpdate(self):
233 """Tests using the setnextupdate and hostinfo api commands."""
234 pid = self._StartServer()
235 try:
236 # Wait for the server to start up.
237 time.sleep(1)
238
239 # Send setnextupdate command.
240 request = urllib2.Request(API_SET_UPDATE_URL, API_SET_UPDATE_REQUEST)
241 connection = urllib2.urlopen(request)
242 response = connection.read()
243 connection.close()
244
245 # Send hostinfo command and verify the setnextupdate worked.
246 connection = urllib2.urlopen(API_HOST_INFO_URL)
247 response = connection.read()
248 connection.close()
249
250 self.assertEqual(
251 json.loads(response)['forced_update_label'], API_SET_UPDATE_REQUEST)
252 finally:
253 os.kill(pid, signal.SIGKILL)
254
Girtsdba6ab22010-10-11 15:53:52 -0700255
256if __name__ == '__main__':
257 unittest.main()