| #!/usr/bin/env python2 |
| # -*- coding: utf-8 -*- |
| # Copyright 2018 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Unittests for Nebraska server.""" |
| |
| from __future__ import print_function |
| |
| # pylint: disable=cros-logging-import |
| import logging |
| import os |
| import shutil |
| import tempfile |
| import unittest |
| |
| from xml.etree import ElementTree |
| import mock |
| |
| from six.moves import builtins |
| from six.moves import http_client |
| |
| import nebraska |
| |
| |
| _NEBRASKA_PORT = 11235 |
| _INSTALL_DIR = 'test_install_dir' |
| _UPDATE_DIR = 'test_update_dir' |
| _PAYLOAD_ADDRESS = '111.222.212:2357' |
| _UPDATE_PAYLOADS_ADDRESS = 'www.google.com/update/' |
| _INSTALL_PAYLOADS_ADDRESS = 'www.google.com/install/' |
| |
| # pylint: disable=protected-access |
| |
| def GenerateAppData(appid='foo', name='foobar', is_delta=False, |
| target_version='2.0.0', source_version=None, |
| include_public_key=False): |
| """Generates an AppData test instance.""" |
| data = { |
| nebraska.AppIndex.AppData.APPID_KEY: appid, |
| nebraska.AppIndex.AppData.NAME_KEY: name, |
| nebraska.AppIndex.AppData.TARGET_VERSION_KEY: target_version, |
| nebraska.AppIndex.AppData.IS_DELTA_KEY: is_delta, |
| nebraska.AppIndex.AppData.SOURCE_VERSION_KEY: source_version, |
| nebraska.AppIndex.AppData.SIZE_KEY: '9001', |
| nebraska.AppIndex.AppData.METADATA_SIG_KEY: |
| 'Dr4RFXYgcfvFHV/0VRQs+SCQmz15Sk04LLEDswtvng8BqNbBXA7VvPUhpCgX5T/t7cwP' |
| 'xTUHJVtxIREuBZpyIQxJQFZATspaClelpKBwadQzj7dpfShLpcbdlfM8qbLjIbXfC2Vy' |
| 'mw03Mwf38lm0Fm75SANSTW9S4arPDf3sy9YGuqesnEJXyT3ZSGyK+Xto79zlURUXCgmi' |
| 'a6t7MaJE3ZbCdeF4EiEMPDsipqj9ggmKwiCdUl2+RxTznX/015XFiBhogLrx9RCPHTR8' |
| 'nLz0H9RcRhIvMd+8g4kHUZTDvjCvG5EZHpIKk8FK8z0zY/LWVr738evwuNNwyKIazkQB' |
| 'TA==', |
| nebraska.AppIndex.AppData.METADATA_SIZE_KEY: '42', |
| nebraska.AppIndex.AppData.SHA256_HEX_KEY: |
| '886fd274745b4fa8d1f253cff11242fac07a29522b1bb9e028ab1480353d3160', |
| } |
| if include_public_key: |
| data[nebraska.AppIndex.AppData.PUBLIC_KEY_RSA_KEY] = 'foo-public-key' |
| return nebraska.AppIndex.AppData(data) |
| |
| |
| def GenerateAppRequest(request_type=nebraska.Request.RequestType.UPDATE, |
| appid='foo', version='1.0.0', delta_okay=False, |
| event=False, event_type='1', event_result='1', |
| update_check=True, ping=False, rollback_allowed=False): |
| """Generates an app request test instance.""" |
| APP_TEMPLATE = """<app appid="" version="" delta_okay="" |
| track="foo-channel" board="foo-board"> </app>""" |
| PING_TEMPLATE = """<ping active="1" a="1" r="1"></ping>""" |
| UPDATE_CHECK_TEMPLATE = """<updatecheck></updatecheck>""" |
| EVENT_TEMPLATE = """<event eventtype="3" eventresult="1"></event>""" |
| |
| app = ElementTree.fromstring(APP_TEMPLATE) |
| app.set('appid', appid) |
| app.set('version', version) |
| app.set('delta_okay', str(bool(delta_okay)).lower()) |
| |
| if ping: |
| app.append(ElementTree.fromstring(PING_TEMPLATE)) |
| if update_check: |
| update_check = ElementTree.fromstring(UPDATE_CHECK_TEMPLATE) |
| app.append(update_check) |
| if rollback_allowed: |
| update_check.set('rollback_allowed', 'true') |
| if event: |
| event_tag = ElementTree.fromstring(EVENT_TEMPLATE) |
| event_tag.set('eventtype', event_type) |
| event_tag.set('eventresult', event_result) |
| app.append(event_tag) |
| |
| return nebraska.Request.AppRequest(app, request_type) |
| |
| |
| class MockNebraskaHandler(nebraska.NebraskaServer.NebraskaHandler): |
| """Subclass NebraskaHandler to facilitate testing. |
| |
| Because of the complexity of the socket handling super class init functions, |
| the easiest way to test NebraskaHandler is to just subclass it and mock |
| whatever we need from its super classes. |
| """ |
| # pylint: disable=super-init-not-called |
| def __init__(self): |
| self.headers = mock.MagicMock() |
| self.path = mock.MagicMock() |
| self._SendResponse = mock.MagicMock() |
| self.send_error = mock.MagicMock() |
| self.rfile = mock.MagicMock() |
| self.server = mock.MagicMock() |
| nebraska_props = nebraska.NebraskaProperties( |
| update_payloads_address=_PAYLOAD_ADDRESS) |
| nebraska_obj = nebraska.Nebraska(nebraska_props=nebraska_props) |
| self.server.owner = nebraska.NebraskaServer(nebraska_obj) |
| |
| |
| class NebraskaTest(unittest.TestCase): |
| """Test Nebraska.""" |
| |
| def testDefaultInstallPayloadsAddress(self): |
| """Tests the default install_payloads_address is correctly set.""" |
| update_addr = 'foo/update/' |
| install_addr = 'foo/install/' |
| # pylint: disable=protected-access |
| nebraska_props = nebraska.NebraskaProperties( |
| update_payloads_address=update_addr, |
| install_payloads_address=install_addr) |
| n = nebraska.Nebraska(nebraska_props=nebraska_props) |
| self.assertEqual(n._nebraska_props.install_payloads_address, install_addr) |
| self.assertEqual(n._nebraska_props.update_payloads_address, update_addr) |
| |
| nebraska_props = nebraska.NebraskaProperties( |
| update_payloads_address=update_addr) |
| n = nebraska.Nebraska(nebraska_props=nebraska_props) |
| self.assertEqual(n._nebraska_props.install_payloads_address, update_addr) |
| |
| n = nebraska.Nebraska() |
| self.assertEqual(n._nebraska_props.update_payloads_address, '') |
| self.assertEqual(n._nebraska_props.install_payloads_address, '') |
| |
| |
| class NebraskaHandlerTest(unittest.TestCase): |
| """Test NebraskaHandler.""" |
| |
| def testParseURL(self): |
| """Tests _ParseURL with different URLs.""" |
| nebraska_handler = MockNebraskaHandler() |
| self.assertEqual( |
| nebraska_handler._ParseURL('http://goo.gle/path/?tick=tock'), |
| ('path', {'tick': ['tock']})) |
| |
| self.assertEqual(nebraska_handler._ParseURL('http://goo.gle/path/'), |
| ('path', {})) |
| |
| self.assertEqual(nebraska_handler._ParseURL('http://goo.gle/'), ('', {})) |
| |
| @mock.patch.object(nebraska.Nebraska, 'GetResponseToRequest', |
| return_value='foobar') |
| @mock.patch.object(nebraska, 'Request') |
| def testDoPostSuccess(self, _, response_mock): |
| """Tests do_POST success.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/update' |
| |
| nebraska_handler.do_POST() |
| |
| response_mock.assert_called_once() |
| nebraska_handler._SendResponse.assert_called_once_with( |
| 'application/xml', response_mock.return_value) |
| |
| @mock.patch.object(nebraska.Nebraska, 'GetResponseToRequest') |
| @mock.patch.object(nebraska, 'Request') |
| def testDoPostSuccessWithCriticalUpdate(self, _, response_mock): |
| """Tests do_POST success with critical_update query string in URL.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/update/?critical_update=True' |
| |
| nebraska_handler.do_POST() |
| |
| response_mock.assert_called_once() |
| self.assertTrue( |
| response_mock.call_args_list[0].response_props.critical_update) |
| |
| @mock.patch.object(nebraska.Nebraska, 'GetResponseToRequest') |
| @mock.patch.object(nebraska, 'Request') |
| def testDoPostSuccessWithNoUpdate(self, _, response_mock): |
| """Tests do_POST success with no_update query string in URL.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/update/?no_update=True' |
| |
| nebraska_handler.do_POST() |
| |
| response_mock.assert_called_once() |
| self.assertTrue(response_mock.call_args_list[0].response_props.no_update) |
| |
| def testDoPostInvalidPath(self): |
| """Test do_POST invalid path.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/invalid-path' |
| nebraska_handler.do_POST() |
| |
| nebraska_handler.send_error.assert_called_once_with( |
| http_client.BAD_REQUEST, |
| 'The requested path "invalid-path" was not found!') |
| |
| @mock.patch.object(nebraska, 'traceback') |
| @mock.patch.object(nebraska.Request, 'ParseRequest', |
| side_effect=nebraska.InvalidRequestError) |
| def testDoPostInvalidRequest(self, _, traceback_mock): |
| """Test do_POST invalid request.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/update' |
| nebraska_handler.do_POST() |
| |
| self.assertEqual(traceback_mock.format_exc.call_count, 2) |
| nebraska_handler.send_error.assert_called_once_with( |
| http_client.INTERNAL_SERVER_ERROR, traceback_mock.format_exc()) |
| |
| @mock.patch.object(nebraska, 'traceback') |
| @mock.patch.object(nebraska, 'Response') |
| def testDoPostInvalidResponse(self, response_mock, traceback_mock): |
| """Tests do_POST invalid response handling.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/update' |
| |
| response_instance = response_mock.return_value |
| response_instance.GetXMLString.side_effect = Exception |
| nebraska_handler.do_POST() |
| |
| self.assertEqual(traceback_mock.format_exc.call_count, 2) |
| nebraska_handler.send_error.assert_called_once_with( |
| http_client.INTERNAL_SERVER_ERROR, traceback_mock.format_exc()) |
| |
| def testDoGetSuccess(self): |
| """Tests do_GET success.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/requestlog' |
| |
| nebraska_handler.do_GET() |
| nebraska_handler._SendResponse.assert_called_once_with( |
| 'application/json', b'[]') |
| |
| def testDoGetFailureBadPath(self): |
| """Tests do_GET failure on bad path.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/invalid-path' |
| |
| nebraska_handler.do_GET() |
| nebraska_handler.send_error(http_client.BAD_REQUEST, mock.ANY) |
| |
| def testDoGetHealthCheck(self): |
| """Tests do_GET with health_check path.""" |
| nebraska_handler = MockNebraskaHandler() |
| nebraska_handler.path = 'http://test.com/health_check' |
| |
| nebraska_handler.do_GET() |
| nebraska_handler._SendResponse.assert_called_once_with( |
| 'text/plain', 'Nebraska is alive!') |
| |
| class NebraskaServerTest(unittest.TestCase): |
| """Test NebraskaServer.""" |
| |
| def testStart(self): |
| """Tests Start.""" |
| nebraska_props = nebraska.NebraskaProperties(_PAYLOAD_ADDRESS) |
| nebraska_instance = nebraska.Nebraska(nebraska_props=nebraska_props) |
| server = nebraska.NebraskaServer(nebraska_instance, port=_NEBRASKA_PORT) |
| |
| with mock.patch.object(nebraska.BaseHTTPServer, |
| 'HTTPServer') as server_mock: |
| with mock.patch.object(nebraska.threading, 'Thread') as thread_mock: |
| server.Start() |
| |
| server_mock.assert_called_once_with( |
| ('', _NEBRASKA_PORT), nebraska.NebraskaServer.NebraskaHandler) |
| |
| # pylint: disable=protected-access |
| thread_mock.assert_has_calls([ |
| mock.call(target=server._httpd.serve_forever), |
| mock.call().start()]) |
| |
| def testStop(self): |
| """Tests Stop.""" |
| nebraska_props = nebraska.NebraskaProperties(_PAYLOAD_ADDRESS) |
| nebraska_instance = nebraska.Nebraska(nebraska_props=nebraska_props) |
| server = nebraska.NebraskaServer(nebraska_instance, port=_NEBRASKA_PORT) |
| |
| # pylint: disable=protected-access |
| server._httpd = mock.MagicMock(name='_httpd') |
| server._server_thread = mock.MagicMock(name='_server_thread') |
| server.Stop() |
| # pylint: disable=protected-access |
| server._httpd.shutdown.assert_called_once_with() |
| server._server_thread.join.assert_called_once_with() |
| |
| def testMiscFiles(self): |
| """Tests PID and port files are correctly written.""" |
| temp_dir = tempfile.mkdtemp() |
| runtime_root = os.path.join(temp_dir, 'runtime_root') |
| nebraska_props = nebraska.NebraskaProperties(_PAYLOAD_ADDRESS) |
| nebraska_instance = nebraska.Nebraska(nebraska_props=nebraska_props) |
| server = nebraska.NebraskaServer(nebraska_instance, port=_NEBRASKA_PORT, |
| runtime_root=runtime_root) |
| |
| port_file = os.path.join(runtime_root, 'port') |
| pid_file = os.path.join(runtime_root, 'pid') |
| |
| with mock.patch.object(nebraska.BaseHTTPServer, 'HTTPServer'): |
| with mock.patch.object(nebraska.threading, 'Thread'): |
| server.Start() |
| |
| # Make sure files are created and written with correct values. |
| with open(port_file, 'r') as f: |
| self.assertEqual(f.read(), str(server.GetPort())) |
| with open(pid_file, 'r') as f: |
| self.assertEqual(f.read(), str(os.getpid())) |
| |
| server.Stop() |
| |
| # Make sure files are deleted correctly. |
| self.assertFalse(os.path.exists(runtime_root)) |
| |
| # Delete the temp directory. |
| shutil.rmtree(temp_dir, ignore_errors=True) |
| |
| |
| class JSONStrings(object): |
| """Collection of JSON strings for testing.""" |
| |
| app_foo = """{ |
| "appid": "foo", |
| "is_delta": "false", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "1.0.0", |
| "source_version": "null" |
| } |
| """ |
| |
| app_foo_update = """{ |
| "appid": "foo", |
| "is_delta": "true", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "2.0.0", |
| "source_version": "1.0.0" |
| } |
| """ |
| |
| app_bar = """{ |
| "appid": "bar", |
| "is_delta": "false", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "1.0.0", |
| "source_version": "null" |
| } |
| """ |
| |
| app_bar_update = """{ |
| "appid": "bar", |
| "is_delta": "true", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "2.0.0", |
| "source_version": "1.0.0" |
| } |
| """ |
| |
| app_foobar = """{ |
| "appid": "foobar", |
| "is_delta": "false", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "1.0.0", |
| "source_version": "null" |
| } |
| """ |
| |
| app_empty = """{ |
| "appid": "", |
| "is_delta": "false", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "1.0.0", |
| "source_version": "null" |
| } |
| """ |
| |
| invalid_app = """{ |
| "appid": "bar", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "1.0.0", |
| "source_version": "null" |
| } |
| """ |
| |
| invalid_json = """blah |
| { |
| "appid": "bar", |
| "is_delta": "false", |
| "size": "9001", |
| "metadata_signature": "0xdeadbeef", |
| "metadata_size": "42", |
| "sha256_hex": "0xcafef00d==", |
| "target_version": "1.0.0", |
| "source_version": "null" |
| } |
| """ |
| |
| |
| class AppIndexTest(unittest.TestCase): |
| """Test AppIndex.""" |
| |
| def testScanEmpty(self): |
| """Tests Scan on an empty directory.""" |
| with mock.patch('os.listdir') as listdir_mock: |
| with mock.patch.object(builtins, 'open') as open_mock: |
| listdir_mock.return_value = [] |
| app_index = nebraska.AppIndex(_INSTALL_DIR) |
| self.assertFalse(app_index._index) |
| listdir_mock.assert_called_once_with(_INSTALL_DIR) |
| open_mock.assert_not_called() |
| |
| def testScanNoJson(self): |
| """Tests Scan on a directory with no JSON files.""" |
| with mock.patch('os.listdir') as listdir_mock: |
| with mock.patch.object(builtins, 'open') as open_mock: |
| listdir_mock.return_value = ['foo.bin', 'bar.bin', 'json'] |
| app_index = nebraska.AppIndex(_INSTALL_DIR) |
| self.assertFalse(app_index._index) |
| listdir_mock.assert_called_once_with(_INSTALL_DIR) |
| open_mock.assert_not_called() |
| |
| def testScanMultiple(self): |
| """Tests Scan on a directory with multiple appids.""" |
| # Providing some mock properties and non-properties files. |
| with mock.patch('os.listdir') as listdir_mock: |
| with mock.patch.object(builtins, 'open') as open_mock: |
| listdir_mock.return_value = [ |
| 'foo_install.json', |
| 'foo_update.json', |
| 'bar_install.json', |
| 'bar_update.json', |
| 'foobar.json', |
| 'foobar.blah' |
| ] |
| |
| # Mock loading the properties files. |
| open_mock.side_effect = [ |
| mock.mock_open(read_data=JSONStrings.app_foo).return_value, |
| mock.mock_open(read_data=JSONStrings.app_foo_update).return_value, |
| mock.mock_open(read_data=JSONStrings.app_bar).return_value, |
| mock.mock_open(read_data=JSONStrings.app_bar_update).return_value, |
| mock.mock_open(read_data=JSONStrings.app_foobar).return_value |
| ] |
| |
| # Make sure the Scan() scans all the files and at least correct App IDs |
| # are generated. |
| app_index = nebraska.AppIndex(_INSTALL_DIR) |
| listdir_mock.assert_called_once_with(_INSTALL_DIR) |
| self.assertEqual( |
| [x.appid for x in app_index._index], |
| ['foo', 'foo', 'bar', 'bar', 'foobar']) |
| |
| def testScanInvalidJson(self): |
| """Tests Scan with invalid JSON files.""" |
| # Providing some mock properties and non-properties files. |
| with mock.patch('os.listdir') as listdir_mock: |
| with mock.patch.object(builtins, 'open') as open_mock: |
| listdir_mock.return_value = [ |
| 'foo_install.json', |
| 'foo_update.json', |
| 'bar_install.json', |
| 'bar_update.json', |
| 'foobar.json', |
| 'foobar.blah' |
| ] |
| |
| # Mock loading the properties files. |
| open_mock.side_effect = [ |
| mock.mock_open(read_data=JSONStrings.app_foo).return_value, |
| mock.mock_open(read_data=JSONStrings.app_foo_update).return_value, |
| IOError('File not found!'), |
| mock.mock_open(read_data=JSONStrings.invalid_json).return_value, |
| mock.mock_open(read_data=JSONStrings.app_foobar).return_value |
| ] |
| |
| # Make sure we raise error when loading files raises one. |
| with self.assertRaises(IOError): |
| nebraska.AppIndex(_INSTALL_DIR) |
| |
| def testScanInvalidApp(self): |
| """Tests Scan on JSON files lacking required keys.""" |
| # Providing some mock properties and non-properties files. |
| with mock.patch('os.listdir') as listdir_mock: |
| with mock.patch.object(builtins, 'open') as open_mock: |
| listdir_mock.return_value = [ |
| 'foo_install.json', |
| 'foo_update.json', |
| 'bar_install.json', |
| 'bar_update.json', |
| 'foobar.json', |
| 'foobar.blah' |
| ] |
| |
| # Mock loading the properties files. |
| open_mock.side_effect = [ |
| mock.mock_open(read_data=JSONStrings.app_foo).return_value, |
| mock.mock_open(read_data=JSONStrings.app_foo_update).return_value, |
| mock.mock_open(read_data=JSONStrings.invalid_app).return_value, |
| mock.mock_open(read_data=JSONStrings.invalid_app).return_value, |
| mock.mock_open(read_data=JSONStrings.app_foobar).return_value |
| ] |
| |
| # Make sure we raise error when properties files are invalid. |
| with self.assertRaises(KeyError): |
| nebraska.AppIndex(_INSTALL_DIR) |
| |
| def testContains(self): |
| """Tests Constains() correctly finds matching AppData.""" |
| # Providing some mock properties files. |
| with mock.patch('os.listdir') as listdir_mock: |
| with mock.patch.object(builtins, 'open') as open_mock: |
| listdir_mock.return_value = [ |
| 'foo.json', |
| ] |
| # Mock loading the properties files. |
| open_mock.side_effect = [ |
| mock.mock_open(read_data=JSONStrings.app_foo).return_value, |
| mock.mock_open(read_data=JSONStrings.app_empty).return_value, |
| ] |
| |
| app_index = nebraska.AppIndex(_UPDATE_DIR) |
| |
| no_match_request = GenerateAppRequest(appid='random') |
| self.assertFalse(app_index.Contains(no_match_request)) |
| |
| # Matches against the AppData with exact appid 'foo'. |
| match_request = GenerateAppRequest(appid='foo') |
| self.assertTrue(app_index.Contains(match_request)) |
| |
| # Partially matches against the AppData with appid 'foo'. |
| partial_match_request = GenerateAppRequest( |
| appid='mefoolme') |
| self.assertTrue(app_index.Contains(partial_match_request)) |
| |
| def testContainsEmpty(self): |
| """Tests Constains() correctly finds matching AppData with empty appid.""" |
| # Providing some mock properties files. |
| with mock.patch('os.listdir') as listdir_mock: |
| with mock.patch.object(builtins, 'open') as open_mock: |
| listdir_mock.return_value = [ |
| 'foo.json', |
| 'empty.json' |
| ] |
| # Mock loading the properties files. |
| open_mock.side_effect = [ |
| mock.mock_open(read_data=JSONStrings.app_foo).return_value, |
| mock.mock_open(read_data=JSONStrings.app_empty).return_value, |
| ] |
| |
| app_index = nebraska.AppIndex(_UPDATE_DIR) |
| |
| request = GenerateAppRequest(appid='random') |
| # It will match against the AppData with an empty appid. |
| self.assertTrue(app_index.Contains(request)) |
| |
| |
| class AppDataTest(unittest.TestCase): |
| """Test AppData.""" |
| |
| def testMatchAppDataInstall(self): |
| """Tests MatchAppData for matching install request.""" |
| app_data = GenerateAppData(source_version=None) |
| request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.INSTALL) |
| self.assertTrue(request.MatchAppData(app_data)) |
| |
| def testMatchAppDataDelta(self): |
| """Tests MatchAppData for matching delta update request.""" |
| app_data = GenerateAppData(is_delta=True, source_version='1.0.0') |
| request = GenerateAppRequest(delta_okay=True) |
| self.assertTrue(request.MatchAppData(app_data)) |
| |
| def testMatchAppDataUpdate(self): |
| """Tests MatchAppData for matching full update request.""" |
| app_data = GenerateAppData() |
| request = GenerateAppRequest() |
| self.assertTrue(request.MatchAppData(app_data)) |
| |
| def testMatchAppDataAppidMismatch(self): |
| """Tests MatchAppData for appid mismatch.""" |
| app_data = GenerateAppData(appid='bar') |
| request = GenerateAppRequest( |
| appid='foo', |
| request_type=nebraska.Request.RequestType.INSTALL) |
| self.assertFalse(request.MatchAppData(app_data)) |
| |
| def testMatchAppDataDeltaMismatch(self): |
| """Tests MatchAppData for delta mismatch.""" |
| app_data = GenerateAppData(is_delta=True, source_version='1.2.0') |
| request = GenerateAppRequest(delta_okay=False) |
| self.assertFalse(request.MatchAppData(app_data)) |
| |
| app_data = GenerateAppData(is_delta=True, source_version='1.2.0') |
| request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.INSTALL, delta_okay=True) |
| self.assertFalse(request.MatchAppData(app_data)) |
| |
| def testMatchAppDataWildCardMatchingEmptyAppId(self): |
| """Tests MatchAppData for matching update request with empty appid.""" |
| app_data = GenerateAppData(appid='') |
| request = GenerateAppRequest(appid='foobar') |
| self.assertFalse(request.MatchAppData(app_data)) |
| self.assertTrue(request.MatchAppData(app_data, partial_match_appid=True)) |
| |
| def testMatchAppDataWildCardMatchingPartialAppId(self): |
| """Tests MatchAppData for matching update request with partial appid.""" |
| app_data = GenerateAppData(appid='oob') |
| request = GenerateAppRequest(appid='foobar') |
| self.assertFalse(request.MatchAppData(app_data)) |
| self.assertTrue(request.MatchAppData(app_data, partial_match_appid=True)) |
| |
| def testNoMatchAppDataWildCardMatchingPartialAppId(self): |
| """Tests MatchAppData for not matching update request with partial appid.""" |
| app_data = GenerateAppData(appid='foo') |
| request = GenerateAppRequest(appid='bar') |
| self.assertFalse(request.MatchAppData(app_data)) |
| self.assertFalse(request.MatchAppData(app_data, partial_match_appid=True)) |
| |
| def testMatchAppDataMatchingCanaryAppId(self): |
| """Tests MatchAppData for matching update request with canary appid.""" |
| app_data = GenerateAppData( |
| appid='1' * len(nebraska.AppIndex.AppData.CANARY_APP_ID) + 'foo') |
| request = GenerateAppRequest( |
| appid=nebraska.AppIndex.AppData.CANARY_APP_ID + 'foo') |
| self.assertFalse(request.MatchAppData(app_data)) |
| self.assertTrue(request.MatchAppData(app_data, check_against_canary=True)) |
| |
| def testNoMatchAppDataMatchingCanaryAppId(self): |
| """Tests MatchAppData for matching update request with canary appid.""" |
| app_data = GenerateAppData( |
| appid='1' * len(nebraska.AppIndex.AppData.CANARY_APP_ID) + 'foo') |
| request = GenerateAppRequest( |
| appid='0' * len(nebraska.AppIndex.AppData.CANARY_APP_ID) + 'foo') |
| self.assertFalse(request.MatchAppData(app_data)) |
| self.assertFalse(request.MatchAppData(app_data, check_against_canary=True)) |
| |
| |
| |
| class XMLStrings(object): |
| """Collection of XML request strings for testing.""" |
| |
| INSTALL_REQUEST = """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="false" |
| track="stable-channel" board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| <app appid="foo" version="1.0.0" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| <app appid="bar" version="1.0.0" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| </request> |
| """ |
| |
| UPDATE_REQUEST = """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="true" |
| track="stable-channel" board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| <app appid="foo" version="1.0.0" delta_okay="true"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| <event eventtype="3" eventresult="1" previousversion="1"></event> |
| </app> |
| <app appid="bar" version="1.0.0" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| </request> |
| """ |
| |
| INVALID_NOOP_REQUEST = """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="true" |
| track="stable-channel" board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| <app appid="foo" version="1.0.0" delta_okay="true"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| <app appid="bar" version="1.0.0" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| </request> |
| """ |
| |
| EVENT_REQUEST = """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="true" |
| track="stable-channel" board="eve"> |
| <event eventtype="3" eventresult="1" previousversion="1"></event> |
| </app> |
| </request> |
| """ |
| |
| INVALID_XML_REQUEST = """invalid xml! |
| <?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="foo" version="1.0.0" delta_okay="false" track="stable-channel" |
| board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| </request> |
| """ |
| |
| # No appid. |
| INVALID_APP_REQUEST = """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app version="1.0.0" delta_okay="true" |
| track="stable-channel" board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| </request> |
| """ |
| |
| # No version number. |
| INVALID_INSTALL_REQUEST = """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="false" |
| track="stable-channel" board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| <app appid="foo" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| </request> |
| """ |
| |
| # Missing all board attributes. |
| MISSING_REQUIRED_ATTR_REQUEST = """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| <app appid="foo" version="1.0.0" track="stable-channel" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| </request> |
| """ |
| |
| # Mismatched versions UPDATE. |
| MISMATCHED_VERSION_ATTR_UPDATE_REQUEST = \ |
| """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="false" |
| track="stable-channel" board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| <app appid="foo" version="2.0.0" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| </request> |
| """ |
| |
| # Mismatched versions INSTALL. |
| MISMATCHED_VERSION_ATTR_INSTALL_REQUEST = \ |
| """<?xml version="1.0" encoding="UTF-8"?> |
| <request protocol="3.0"> |
| <os version="Indy" platform="Chrome OS" sp="10323.52.0_x86_64"></os> |
| <app appid="platform" version="1.0.0" delta_okay="false" |
| track="stable-channel" board="eve"> |
| <ping active="1" a="1" r="1"></ping> |
| </app> |
| <app appid="foo" version="2.0.0" delta_okay="false"> |
| <ping active="1" a="1" r="1"></ping> |
| <updatecheck targetversionprefix=""></updatecheck> |
| </app> |
| </request> |
| """ |
| |
| |
| class RequestTest(unittest.TestCase): |
| """Tests for Request class.""" |
| |
| def testParseRequestInvalidXML(self): |
| """Tests ParseRequest handling of invalid XML.""" |
| with self.assertRaises(nebraska.InvalidRequestError): |
| nebraska.Request(XMLStrings.INVALID_XML_REQUEST) |
| |
| def testParseRequestInvalidApp(self): |
| """Tests ParseRequest handling of invalid app requests.""" |
| with self.assertRaises(nebraska.InvalidRequestError): |
| nebraska.Request(XMLStrings.INVALID_APP_REQUEST) |
| |
| def testParseRequestInvalidInstall(self): |
| """Tests ParseRequest handling of invalid app requests.""" |
| with self.assertRaises(nebraska.InvalidRequestError): |
| nebraska.Request(XMLStrings.INVALID_INSTALL_REQUEST) |
| |
| def testParseRequestInvalidNoop(self): |
| """Tests ParseRequest handling of invalid mixed no-op request.""" |
| with self.assertRaises(nebraska.InvalidRequestError): |
| nebraska.Request(XMLStrings.INVALID_NOOP_REQUEST) |
| |
| def testParseRequestMissingAtLeastOneRequiredAttr(self): |
| """Tests ParseRequest handling of missing required attributes in request.""" |
| with self.assertRaises(nebraska.InvalidRequestError): |
| nebraska.Request(XMLStrings.MISSING_REQUIRED_ATTR_REQUEST) |
| |
| def testParseRequestMismatchedVersionUpdate(self): |
| """Tests ParseRequest handling of mismatched update version numbers.""" |
| with self.assertRaises(nebraska.InvalidRequestError): |
| nebraska.Request(XMLStrings.MISMATCHED_VERSION_ATTR_UPDATE_REQUEST) |
| |
| def testParseRequestMismatchedVersionInstall(self): |
| """Tests ParseRequest handling of mismatched install version numbers.""" |
| # Not raises |nebraska.InvalidRequestError|. |
| nebraska.Request(XMLStrings.MISMATCHED_VERSION_ATTR_INSTALL_REQUEST) |
| |
| def testParseRequestInstall(self): |
| """Tests ParseRequest handling of install requests.""" |
| app_requests = nebraska.Request(XMLStrings.INSTALL_REQUEST).app_requests |
| |
| self.assertEqual(app_requests[0].request_type, |
| nebraska.Request.RequestType.INSTALL) |
| self.assertEqual(app_requests[1].request_type, |
| nebraska.Request.RequestType.INSTALL) |
| self.assertEqual(app_requests[2].request_type, |
| nebraska.Request.RequestType.INSTALL) |
| |
| self.assertEqual(app_requests[0].appid, 'platform') |
| self.assertEqual(app_requests[1].appid, 'foo') |
| self.assertEqual(app_requests[2].appid, 'bar') |
| |
| self.assertEqual(app_requests[0].version, '1.0.0') |
| self.assertEqual(app_requests[1].version, '1.0.0') |
| self.assertEqual(app_requests[2].version, '1.0.0') |
| |
| def testParseRequestUpdate(self): |
| """Tests ParseRequest handling of update requests.""" |
| app_requests = nebraska.Request(XMLStrings.UPDATE_REQUEST).app_requests |
| |
| self.assertEqual(app_requests[0].request_type, |
| nebraska.Request.RequestType.UPDATE) |
| self.assertEqual(app_requests[1].request_type, |
| nebraska.Request.RequestType.UPDATE) |
| self.assertEqual(app_requests[2].request_type, |
| nebraska.Request.RequestType.UPDATE) |
| |
| self.assertEqual(app_requests[0].appid, 'platform') |
| self.assertEqual(app_requests[1].appid, 'foo') |
| self.assertEqual(app_requests[2].appid, 'bar') |
| |
| self.assertEqual(app_requests[0].version, '1.0.0') |
| self.assertEqual(app_requests[1].version, '1.0.0') |
| self.assertEqual(app_requests[2].version, '1.0.0') |
| |
| self.assertTrue(app_requests[0].delta_okay) |
| self.assertTrue(app_requests[1].delta_okay) |
| self.assertFalse(app_requests[2].delta_okay) |
| |
| def testParseRequestEventPing(self): |
| """Tests ParseRequest handling of event ping requests.""" |
| app_requests = nebraska.Request(XMLStrings.EVENT_REQUEST).app_requests |
| |
| self.assertEqual(app_requests[0].request_type, |
| nebraska.Request.RequestType.EVENT) |
| self.assertEqual(app_requests[0].appid, 'platform') |
| self.assertEqual(app_requests[0].event_type, 3) |
| self.assertEqual(app_requests[0].event_result, 1) |
| self.assertEqual(app_requests[0].previous_version, '1') |
| |
| def testDetectingPlatformAppRequest(self): |
| """Tests we correctly identify platform VS. DLC requests""" |
| request = GenerateAppRequest(appid='foo-platform') |
| self.assertTrue(request.is_platform) |
| |
| request = GenerateAppRequest(appid='') |
| self.assertTrue(request.is_platform) |
| |
| request = GenerateAppRequest(appid='foo-platform_dlc') |
| self.assertFalse(request.is_platform) |
| |
| request = GenerateAppRequest(appid='_dlc') |
| self.assertFalse(request.is_platform) |
| |
| |
| class ResponseTest(unittest.TestCase): |
| """Tests for Response class.""" |
| |
| def testGetXMLStringSuccess(self): |
| """Tests GetXMLString success.""" |
| nebraska_props = nebraska.NebraskaProperties( |
| update_payloads_address=_UPDATE_PAYLOADS_ADDRESS, |
| install_payloads_address=_INSTALL_PAYLOADS_ADDRESS) |
| |
| app_list = ( |
| GenerateAppData(is_delta=True, source_version='0.9.0'), |
| GenerateAppData(appid='bar', is_delta=True, source_version='1.9.0'), |
| GenerateAppData(appid='foobar')) |
| nebraska_props.update_app_index._index = app_list |
| |
| request = mock.MagicMock() |
| request.app_requests = [ |
| GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.UPDATE, |
| appid='foo', |
| ping=True, |
| delta_okay=False), |
| GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.UPDATE, |
| appid='bar', |
| ping=True, |
| delta_okay=False), |
| GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.UPDATE, |
| appid='foobar', |
| ping=True, |
| delta_okay=False)] |
| |
| response = nebraska.Response(request, nebraska_props, |
| nebraska.ResponseProperties()).GetXMLString() |
| response_root = ElementTree.fromstring(response) |
| app_responses = response_root.findall('app') |
| |
| self.assertEqual(len(app_responses), 3) |
| for response, app in zip(app_responses, app_list): |
| self.assertEqual(response.attrib['appid'], app.appid) |
| self.assertIsNotNone(response.find('ping')) |
| |
| |
| class AppResponseTest(unittest.TestCase): |
| """Tests for AppResponse class.""" |
| |
| def setUp(self): |
| """Setting up common parameters.""" |
| self._nebraska_props = nebraska.NebraskaProperties( |
| update_payloads_address=_UPDATE_PAYLOADS_ADDRESS, |
| install_payloads_address=_INSTALL_PAYLOADS_ADDRESS) |
| self._response_props = nebraska.ResponseProperties() |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testAppResponseUpdate(self, find_mock): |
| """Tests AppResponse for an update request with matching payload.""" |
| app_request = GenerateAppRequest() |
| match = find_mock.return_value |
| # Setting the install app index object to None to make sure it is not being |
| # called. |
| self._nebraska_props.install_app_index.Find = None |
| |
| response = nebraska.Response.AppResponse(app_request, |
| self._nebraska_props, |
| self._response_props) |
| |
| self.assertIn(_UPDATE_PAYLOADS_ADDRESS.encode('utf-8'), |
| ElementTree.tostring(response.Compile())) |
| self.assertEqual(response._app_request, app_request) |
| self.assertFalse(response._err_not_found) |
| self.assertIs(response._app_data, match) |
| find_mock.assert_called_once_with(app_request) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testAppResponseInstall(self, find_mock): |
| """Tests AppResponse generation for install request with match.""" |
| app_request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.INSTALL) |
| match = find_mock.return_value |
| # Setting the update app index object to None to make sure it is not being |
| # called. |
| self._nebraska_props.update_app_index.Find = None |
| |
| response = nebraska.Response.AppResponse(app_request, |
| self._nebraska_props, |
| self._response_props) |
| |
| self.assertIn(_INSTALL_PAYLOADS_ADDRESS.encode('utf-8'), |
| ElementTree.tostring(response.Compile())) |
| self.assertEqual(response._app_request, app_request) |
| self.assertFalse(response._err_not_found) |
| self.assertIs(response._app_data, match) |
| find_mock.assert_called_once_with(app_request) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=None) |
| @mock.patch.object(nebraska.AppIndex, 'Contains', return_value=False) |
| def testAppResponseNoMatch(self, contains_mock, find_mock): |
| """Tests AppResponse generation for update request with an unknown appid.""" |
| app_request = GenerateAppRequest() |
| response = nebraska.Response.AppResponse(app_request, |
| self._nebraska_props, |
| self._response_props) |
| |
| self.assertEqual(response._app_request, app_request) |
| self.assertTrue(response._err_not_found) |
| self.assertIsNone(response._app_data) |
| find_mock.assert_called_once_with(app_request) |
| contains_mock.assert_called_once_with(app_request) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=None) |
| @mock.patch.object(nebraska.AppIndex, 'Contains', return_value=True) |
| # pylint: disable=unused-argument |
| def testAppResponseNoUpdate(self, contains_mock, find_mock): |
| """Tests AppResponse generation for update request with no new versions.""" |
| # GIVEN an update request. |
| app_request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.UPDATE) |
| self._response_props.eol_date = 10 |
| |
| # WHEN Nebraska sends a response. |
| response = nebraska.Response.AppResponse(app_request, |
| self._nebraska_props, |
| self._response_props) |
| |
| # THEN the response contains <updatecheck status="noupdate" |
| # _eol_date="10"/>. |
| update_check_tag = response.Compile().findall('updatecheck')[0] |
| self.assertEqual(update_check_tag.attrib['status'], 'noupdate') |
| self.assertEqual(update_check_tag.attrib['_eol_date'], '10') |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| @mock.patch.object(nebraska.AppIndex, 'Contains', return_value=True) |
| # pylint: disable=unused-argument |
| def testAppResponseNoUpdateFlag(self, contains_mock, find_mock): |
| """Tests status="noupdate" is included in the response.""" |
| app_request = GenerateAppRequest() |
| self._response_props.no_update = True |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| update_check_tag = response.findall('updatecheck')[0] |
| self.assertEqual(update_check_tag.attrib['status'], 'noupdate') |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find') |
| @mock.patch.object(nebraska.AppIndex, 'Contains', return_value=True) |
| def testAppResponsePing(self, contains_mock, find_mock): |
| """Tests AppResponse generation for no-op with a ping request.""" |
| app_request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.EVENT, ping=True) |
| response = nebraska.Response.AppResponse(app_request, |
| self._nebraska_props, |
| self._response_props) |
| |
| self.assertEqual(response._app_request, app_request) |
| self.assertFalse(response._err_not_found) |
| self.assertIsNone(response._app_data) |
| find_mock.assert_not_called() |
| contains_mock.assert_not_called() |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find') |
| @mock.patch.object(nebraska.AppIndex, 'Contains') |
| def testAppResponseEvent(self, contains_mock, find_mock): |
| """Tests AppResponse generation for requests with events.""" |
| app_request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.EVENT) |
| |
| response = nebraska.Response.AppResponse(app_request, |
| self._nebraska_props, |
| self._response_props) |
| |
| self.assertEqual(response._app_request, app_request) |
| self.assertFalse(response._err_not_found) |
| self.assertIsNone(response._app_data) |
| find_mock.assert_not_called() |
| contains_mock.assert_not_called() |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testCompileSuccess(self, find_mock): |
| """Tests successful compilation of an AppData instance.""" |
| app_request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.INSTALL) |
| match = find_mock.return_value |
| |
| response = nebraska.Response.AppResponse(app_request, |
| self._nebraska_props, |
| self._response_props) |
| compiled_response = response.Compile() |
| |
| update_check_tag = compiled_response.find('updatecheck') |
| url_tags = compiled_response.findall('updatecheck/urls/url') |
| manifest_tag = compiled_response.find('updatecheck/manifest') |
| package_tag = compiled_response.find( |
| 'updatecheck/manifest/packages/package') |
| action_tag = compiled_response.findall( |
| 'updatecheck/manifest/actions/action')[1] |
| |
| self.assertEqual(len(url_tags), 1) |
| self.assertEqual(url_tags[0].attrib['codebase'], _INSTALL_PAYLOADS_ADDRESS) |
| self.assertIsNotNone(manifest_tag) |
| self.assertIsNotNone(package_tag) |
| self.assertIsNotNone(action_tag) |
| self.assertEqual(action_tag.attrib['sha256'], match.sha256) |
| self.assertEqual(action_tag.attrib['DisablePayloadBackoff'], 'false') |
| self.assertEqual(compiled_response.attrib['status'], 'ok') |
| self.assertEqual(compiled_response.attrib['appid'], match.appid) |
| self.assertEqual(update_check_tag.attrib['status'], 'ok') |
| self.assertEqual(manifest_tag.attrib['version'], match.target_version) |
| self.assertEqual(package_tag.attrib['hash_sha256'].encode('utf-8'), |
| match.sha256_hex) |
| self.assertEqual(package_tag.attrib['fp'], '1.%s' % match.sha256_hex) |
| self.assertEqual(package_tag.attrib['name'], match.name) |
| self.assertEqual(package_tag.attrib['size'], match.size) |
| self.assertEqual( |
| action_tag.attrib['ChromeOSVersion'], match.target_version) |
| self.assertEqual(action_tag.attrib['IsDeltaPayload'], |
| str(match.is_delta).lower()) |
| self.assertNotIn('deadline', action_tag.attrib) |
| self.assertNotIn('PublicKeyRsa', action_tag.attrib) |
| self.assertNotIn('MaxFailureCountPerUrl', action_tag) |
| self.assertNotIn('_is_rollback', update_check_tag.attrib) |
| self.assertNotIn('_eol_date', update_check_tag.attrib) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| # pylint: disable=unused-argument |
| def testCriticalUpdate(self, find_mock): |
| """Tests correct response for critical updates.""" |
| app_request = GenerateAppRequest() |
| self._response_props.critical_update = True |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| action_tag = response.findall( |
| 'updatecheck/manifest/actions/action')[1] |
| self.assertEqual(action_tag.attrib['deadline'], 'now') |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| # pylint: disable=unused-argument |
| def testCriticalInstall(self, find_mock): |
| """Tests correct response for critical installs.""" |
| app_request = GenerateAppRequest( |
| request_type=nebraska.Request.RequestType.INSTALL) |
| self._response_props.critical_update = True |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| action_tag = response.findall( |
| 'updatecheck/manifest/actions/action')[1] |
| self.assertEqual(action_tag.attrib['deadline'], 'now') |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', |
| return_value=GenerateAppData(include_public_key=True)) |
| def testPublicKey(self, find_mock): |
| """Tests public key is included in the response.""" |
| app_request = GenerateAppRequest() |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| action_tag = response.findall( |
| 'updatecheck/manifest/actions/action')[1] |
| self.assertEqual(action_tag.attrib['PublicKeyRsa'], |
| find_mock.return_value.public_key) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testRollback(self, _): |
| """Tests rollback parametes are setup correctly.""" |
| app_request = GenerateAppRequest(rollback_allowed=True) |
| self._response_props.is_rollback = True |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| update_check_tag = response.find('updatecheck') |
| index_strs = ['', '_0', '_1', '_2', '_3', '_4'] |
| self.assertEqual(update_check_tag.attrib['_is_rollback'], 'true') |
| for idx in index_strs: |
| self.assertEqual(update_check_tag.attrib['_firmware_version' + idx], |
| nebraska._FIRMWARE_VER) |
| self.assertEqual(update_check_tag.attrib['_kernel_version' + idx], |
| nebraska._KERNEL_VER) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testNotRollback(self, _): |
| """Tests that we should not do rollback if it was not requested.""" |
| app_request = GenerateAppRequest(rollback_allowed=False) |
| self._response_props.is_rollback = True |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| update_check_tag = response.find('updatecheck') |
| self.assertNotIn('_is_rollback', update_check_tag.attrib) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testFailuresPerUrl(self, _): |
| """Tests response for number of failures allowed per URL.""" |
| app_request = GenerateAppRequest() |
| |
| self._response_props.failures_per_url = 1 |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| action_tag = response.findall( |
| 'updatecheck/manifest/actions/action')[1] |
| self.assertEqual(action_tag.attrib['MaxFailureCountPerUrl'], '1') |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testDisablePayloadBackoff(self, _): |
| """Tests disabling payload backoff on the client.""" |
| app_request = GenerateAppRequest() |
| self._response_props.disable_payload_backoff = True |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| action_tag = response.findall( |
| 'updatecheck/manifest/actions/action')[1] |
| self.assertEqual(action_tag.attrib['DisablePayloadBackoff'], 'true') |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testNumUrls(self, _): |
| """Tests the number of URLs are passed correctly.""" |
| app_request = GenerateAppRequest() |
| self._response_props.num_urls = 2 |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| url_tags = response.findall('updatecheck/urls/url') |
| self.assertEqual(len(url_tags), 2) |
| |
| @mock.patch.object(nebraska.AppIndex, 'Find', return_value=GenerateAppData()) |
| def testEolDate(self, _): |
| """Tests the number of URLs are passed correctly.""" |
| app_request = GenerateAppRequest() |
| self._response_props.eol_date = 1000 |
| |
| response = nebraska.Response.AppResponse( |
| app_request, self._nebraska_props, self._response_props).Compile() |
| |
| update_check_tag = response.find('updatecheck') |
| self.assertEqual(update_check_tag.attrib['_eol_date'], '1000') |
| |
| |
| if __name__ == '__main__': |
| # Disable logging so it doesn't pollute the unit test output. Failures and |
| # exceptions are still shown. |
| logging.disable(logging.CRITICAL) |
| |
| unittest.main() |