# Copyright 2020 The Nomulus Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """End-to-end test of rollback.""" import textwrap from typing import Any, Dict import unittest from unittest import mock import appengine_test import gcs_test import plan def _make_serving_version(service: str, version: str) -> Dict[str, Any]: """Creates description of one serving version in API response.""" return { 'split': { 'allocations': { version: 1, } }, 'id': service } def _make_version_config(version, scaling: str, instance_tag: str, instances: int = 10) -> Dict[str, Any]: """Creates one version config as part of an API response.""" return {scaling: {instance_tag: instances}, 'id': version} class RollbackTestCase(unittest.TestCase): """End-to-end test of rollback.""" def setUp(self) -> None: self._appengine_admin, self._appengine_request = ( appengine_test.setup_appengine_admin()) self._gcs_client, self._schema_tag, self._version_map = ( gcs_test.setup_gcs_client('crash')) self.addCleanup(mock.patch.stopall) def test_rollback_success(self): self._schema_tag.download_as_text.return_value = ( 'nomulus-2010-1014-RC00') self._version_map.download_as_text.return_value = textwrap.dedent("""\ nomulus-20201014-RC00,backend,nomulus-backend-v009 nomulus-20201014-RC00,default,nomulus-default-v009 nomulus-20201014-RC00,pubapi,nomulus-pubapi-v009 nomulus-20201014-RC00,tools,nomulus-tools-v009 nomulus-20201014-RC01,backend,nomulus-backend-v011 nomulus-20201014-RC01,default,nomulus-default-v010 nomulus-20201014-RC01,pubapi,nomulus-pubapi-v010 nomulus-20201014-RC01,tools,nomulus-tools-v010 """) self._appengine_request.execute.side_effect = [ # Response to get_serving_versions: { 'services': [ _make_serving_version('backend', 'nomulus-backend-v011'), _make_serving_version('default', 'nomulus-default-v010'), _make_serving_version('pubapi', 'nomulus-pubapi-v010'), _make_serving_version('tools', 'nomulus-tools-v010') ] }, # Responses to get_version_configs. AppEngineAdmin queries the # services by alphabetical order to facilitate this test. { 'versions': [ _make_version_config('nomulus-backend-v009', 'basicScaling', 'maxInstances'), _make_version_config('nomulus-backend-v011', 'basicScaling', 'maxInstances') ] }, { 'versions': [ _make_version_config('nomulus-default-v009', 'basicScaling', 'maxInstances'), _make_version_config('nomulus-default-v010', 'basicScaling', 'maxInstances') ] }, { 'versions': [ _make_version_config('nomulus-pubapi-v009', 'manualScaling', 'instances'), _make_version_config('nomulus-pubapi-v010', 'manualScaling', 'instances') ] }, { 'versions': [ _make_version_config('nomulus-tools-v009', 'automaticScaling', 'maxTotalInstances'), _make_version_config('nomulus-tools-v010', 'automaticScaling', 'maxTotalInstances') ] } ] steps = plan.get_rollback_plan(self._gcs_client, self._appengine_admin, 'crash', 'nomulus-20201014-RC00') self.assertEqual(len(steps), 15) self.assertRegex(steps[0].info(), '.*nom_build :integration:sqlIntegrationTest.*') self.assertRegex(steps[1].info(), '.*gcloud app versions start.*') self.assertRegex(steps[5].info(), '.*gcloud app services set-traffic.*') self.assertRegex(steps[9].info(), '.*gcloud app versions stop.*') self.assertRegex(steps[13].info(), '.*echo nomulus-20201014-RC00 | gsutil cat -.*') self.assertRegex(steps[14].info(), '.*gsutil -m rsync -d .*') if __name__ == '__main__': unittest.main()