blob: 94db2b4e3865024480283b8e2b4780273348594e [file] [log] [blame]
Luis Hector Chaveza1518052018-06-14 08:19:34 -07001#!/usr/bin/env python2
2# -*- coding: utf-8 -*-
Chris Sosa0356d3b2010-09-16 15:46:22 -07003# 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"""Unit tests for autoupdate.py."""
8
Don Garrettfb15e322016-06-21 19:12:08 -07009from __future__ import print_function
10
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070011import json
Chris Sosa6a3697f2013-01-29 16:44:43 -080012import shutil
Chris Sosa7c931362010-10-11 19:49:01 -070013import socket
joychen121fc9b2013-08-02 14:30:30 -070014import tempfile
Chris Sosa0356d3b2010-09-16 15:46:22 -070015import unittest
Chris Sosa0356d3b2010-09-16 15:46:22 -070016
Amin Hassani4f1e4622019-10-03 10:40:50 -070017import mock
Achuith Bhandarkar662fb722019-10-31 16:12:49 -070018import cherrypy # pylint: disable=import-error
Gilad Arnoldabb352e2012-09-23 01:24:27 -070019
Chris Sosa0356d3b2010-09-16 15:46:22 -070020import autoupdate
Achuith Bhandarkar662fb722019-10-31 16:12:49 -070021
22import setup_chromite # pylint: disable=unused-import
23from chromite.lib.xbuddy import common_util
24from chromite.lib.xbuddy import xbuddy
Chris Sosa0356d3b2010-09-16 15:46:22 -070025
Chris Sosa0356d3b2010-09-16 15:46:22 -070026
Amin Hassani8d718d12019-06-02 21:28:39 -070027_TEST_REQUEST = """<?xml version="1.0" encoding="UTF-8"?>
28<request protocol="3.0" updater="ChromeOSUpdateEngine" updaterversion="0.1.0.0">
29 <app appid="test-appid" version="%(version)s" track="%(track)s"
30 board="%(board)s" hardware_class="%(hwclass)s">
31 <updatecheck />
32 </app>
33</request>"""
Chris Sosa4b951602014-04-09 20:26:07 -070034
Amin Hassani4f1e4622019-10-03 10:40:50 -070035class AutoupdateTest(unittest.TestCase):
Chris Sosa4b951602014-04-09 20:26:07 -070036 """Tests for the autoupdate.Autoupdate class."""
37
Chris Sosa0356d3b2010-09-16 15:46:22 -070038 def setUp(self):
Chris Sosa7c931362010-10-11 19:49:01 -070039 self.port = 8080
Chris Sosa0356d3b2010-09-16 15:46:22 -070040 self.test_board = 'test-board'
joychen121fc9b2013-08-02 14:30:30 -070041 self.build_root = tempfile.mkdtemp('autoupdate_build_root')
Amin Hassanic91fc0d2019-12-04 11:07:16 -080042 self.tempdir = tempfile.mkdtemp('tempdir')
Chris Sosa0356d3b2010-09-16 15:46:22 -070043 self.latest_dir = '12345_af_12-a1'
44 self.latest_verision = '12345_af_12'
joychen121fc9b2013-08-02 14:30:30 -070045 self.static_image_dir = tempfile.mkdtemp('autoupdate_static_dir')
Chris Sosa7c931362010-10-11 19:49:01 -070046 self.hostname = '%s:%s' % (socket.gethostname(), self.port)
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070047 self.test_dict = {
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070048 'version': 'ForcedUpdate',
Chris Sosa4b951602014-04-09 20:26:07 -070049 'track': 'test-channel',
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070050 'board': self.test_board,
Amin Hassani8d718d12019-06-02 21:28:39 -070051 'hwclass': 'test-hardware-class',
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070052 }
Chris Sosa0356d3b2010-09-16 15:46:22 -070053 self.test_data = _TEST_REQUEST % self.test_dict
Chris Sosa0356d3b2010-09-16 15:46:22 -070054 self.payload = 'My payload'
Chris Sosa54555862010-10-25 17:26:17 -070055 cherrypy.request.base = 'http://%s' % self.hostname
joychen121fc9b2013-08-02 14:30:30 -070056 common_util.MkDirP(self.static_image_dir)
57 self._xbuddy = xbuddy.XBuddy(False,
joychen121fc9b2013-08-02 14:30:30 -070058 static_dir=self.static_image_dir)
Amin Hassani4f1e4622019-10-03 10:40:50 -070059 mock.patch.object(xbuddy.XBuddy, '_GetArtifact')
Chris Sosa6a3697f2013-01-29 16:44:43 -080060
61 def tearDown(self):
joychen121fc9b2013-08-02 14:30:30 -070062 shutil.rmtree(self.build_root)
Amin Hassanic91fc0d2019-12-04 11:07:16 -080063 shutil.rmtree(self.tempdir)
Chris Sosa6a3697f2013-01-29 16:44:43 -080064 shutil.rmtree(self.static_image_dir)
Chris Sosa54555862010-10-25 17:26:17 -070065
Gilad Arnold0c9c8602012-10-02 23:58:58 -070066 def _DummyAutoupdateConstructor(self, **kwargs):
Chris Sosa0356d3b2010-09-16 15:46:22 -070067 """Creates a dummy autoupdater. Used to avoid using constructor."""
joychen121fc9b2013-08-02 14:30:30 -070068 dummy = autoupdate.Autoupdate(self._xbuddy,
Chris Sosa7c931362010-10-11 19:49:01 -070069 static_dir=self.static_image_dir,
Gilad Arnold0c9c8602012-10-02 23:58:58 -070070 **kwargs)
Chris Sosa0356d3b2010-09-16 15:46:22 -070071 return dummy
72
Don Garrett0ad09372010-12-06 16:20:30 -080073 def testChangeUrlPort(self):
Amin Hassani4f1e4622019-10-03 10:40:50 -070074 # pylint: disable=protected-access
Don Garrett0ad09372010-12-06 16:20:30 -080075 r = autoupdate._ChangeUrlPort('http://fuzzy:8080/static', 8085)
76 self.assertEqual(r, 'http://fuzzy:8085/static')
77
78 r = autoupdate._ChangeUrlPort('http://fuzzy/static', 8085)
79 self.assertEqual(r, 'http://fuzzy:8085/static')
80
81 r = autoupdate._ChangeUrlPort('ftp://fuzzy/static', 8085)
82 self.assertEqual(r, 'ftp://fuzzy:8085/static')
83
84 r = autoupdate._ChangeUrlPort('ftp://fuzzy', 8085)
85 self.assertEqual(r, 'ftp://fuzzy:8085')
86
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070087 def testHandleHostInfoPing(self):
88 au_mock = self._DummyAutoupdateConstructor()
89 self.assertRaises(AssertionError, au_mock.HandleHostInfoPing, None)
90
Gilad Arnold286a0062012-01-12 13:47:02 -080091 # Setup fake host_infos entry and ensure it comes back to us in one piece.
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070092 test_ip = '1.2.3.4'
Gilad Arnold286a0062012-01-12 13:47:02 -080093 au_mock.host_infos.GetInitHostInfo(test_ip).attrs = self.test_dict
Dale Curtisc9aaf3a2011-08-09 15:47:40 -070094 self.assertEqual(
95 json.loads(au_mock.HandleHostInfoPing(test_ip)), self.test_dict)
96
Amin Hassanic91fc0d2019-12-04 11:07:16 -080097 @mock.patch.object(autoupdate.Autoupdate, 'GetPathToPayload')
98 def testHandleUpdatePing(self, path_to_payload_mock):
99 """Tests HandleUpdatePing"""
100 au_mock = self._DummyAutoupdateConstructor()
101 path_to_payload_mock.return_value = self.tempdir
102 request = """<?xml version="1.0" encoding="UTF-8"?>
103<request protocol="3.0">
104 <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os>
105 <app appid="platform" version="1.0.0" delta_okay="true"
106 track="stable-channel" board="eve">
107 <ping active="1" a="1" r="1"></ping>
108 <updatecheck targetversionprefix=""></updatecheck>
109 </app>
110</request>"""
111
112 self.assertIn('error-unknownApplication', au_mock.HandleUpdatePing(request))
Dale Curtisc9aaf3a2011-08-09 15:47:40 -0700113
Amin Hassaniaef2b292020-01-10 10:44:16 -0800114
115class MaxUpdatesTableTest(unittest.TestCase):
116 """Tests MaxUpdatesTable"""
117
118 def testSessionTable(self):
119 """Tests that SessionData() method correctly returns requested data."""
120 table = autoupdate.SessionTable()
121 g_data = {'foo': 0}
122
123 table.SetSessionData('id-1', g_data)
124 with table.SessionData('id-1') as data:
125 data.update({'foo': data.get('foo') + 1})
126 # Value of the global data should be increased by now.
127 self.assertTrue(g_data['foo'], 1)
128
129 # Increase again.
130 with table.SessionData('id-1') as data:
131 data.update({'foo': data.get('foo') + 1})
132 self.assertTrue(g_data['foo'], 2)
133
134 # Make sure multiple sessions can be set and used.
135 g_data2 = {'foo': 10}
136 table.SetSessionData('id-2', g_data2)
137 with table.SessionData('id-2') as data:
138 data.update({'foo': data.get('foo') + 1})
139 self.assertTrue(g_data2['foo'], 11)
140
141 def testNoneSession(self):
142 """Tests if a session is not set, it should be returned as None."""
143 table = autoupdate.SessionTable()
144 # A session ID that has never been set should not return anything.
145 with table.SessionData('foo-id') as data:
146 self.assertDictEqual(data, {})
147
148 def testOverrideSession(self):
149 """Tests that a session can be overriden.."""
150 table = autoupdate.SessionTable()
151
152 table.SetSessionData('id-1', {'foo': 0})
153 table.SetSessionData('id-1', {'bar': 1})
154 with table.SessionData('id-1') as data:
155 self.assertEqual(data.get('bar'), 1)
156
157 @mock.patch.object(autoupdate.SessionTable, '_IsSessionExpired',
158 side_effect=lambda s: 'foo' in s.data)
159 @mock.patch.object(autoupdate.SessionTable, '_ShouldPurge',
160 return_value=True)
161 # pylint: disable=unused-argument
162 def testPurge(self, p, ps):
163 """Tests that data is being purged correctly."""
164 table = autoupdate.SessionTable()
165
166 table.SetSessionData('id-1', {'foo': 1})
167 table.SetSessionData('id-2', {'bar': 2})
168
169 # Set a random session to make _Purge() be called.
170 table.SetSessionData('blah', {'blah': 1})
171 # Only id-1 should be purged by now.
172 with table.SessionData('id-1') as data:
173 self.assertDictEqual(data, {})
174 with table.SessionData('id-2') as data:
175 self.assertDictEqual(data, {'bar': 2})
176
177
Gilad Arnoldc65330c2012-09-20 15:17:48 -0700178if __name__ == '__main__':
179 unittest.main()