def test_get_deployment_status_up_to_date(self, mock_create_new_deployment, mock_consul): """ Test that the correct status is returned when instance is up-to-date. """ self.client.force_login(self.user_with_instance) instance = self._setup_user_instance() instance.name = self.instance_config.instance_name instance.privacy_policy_url = self.instance_config.privacy_policy_url instance.email = self.instance_config.public_contact_email instance.theme_config = self.instance_config.draft_theme_config instance.save() make_test_deployment(instance, appserver_states=[Status.Running], active=True) url = reverse( 'api:v2:openedx-instance-deployment-detail', args=(self.instance_config.pk, ), ) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assert_deployment_response(response.data, status='healthy', undeployed_changes=0)
def test_multi_appserver_partial_activation(self, mock_consul, mock_make_active): """ Test the start_deployment task, and that it can be used to spawn multiple AppServer(s) for a new instance. """ instance = OpenEdXInstanceFactory() instance.openedx_appserver_count = 3 instance.save() make_test_deployment(instance, active=True) self.mock_make_appserver_active.s = Mock() self.mock_make_appserver_active.s.side_effect = make_appserver_active.s self.assertEqual(instance.appserver_set.count(), 3) self.assertTrue( all(instance.appserver_set.values_list('_is_active', flat=True))) deployment = OpenEdXDeployment.objects.create( instance_id=instance.ref.id) statuses = [ (AppServerStatus.Running, ServerStatus.Ready.state_id), (AppServerStatus.ConfigurationFailed, ServerStatus.BuildFailed.state_id), (AppServerStatus.Running, ServerStatus.Ready.state_id), ] self.mock_spawn_appserver.side_effect = gen_appserver_side_effect( deployment, instance, statuses) tasks.start_deployment( instance.ref.id, deployment.pk, mark_active_on_success=False, ).get() self.assertEqual(self.mock_make_appserver_active.s.call_count, 0) self.assertEqual(mock_make_active.call_count, 0)
def test_commit_changes_fail_first_deployment(self, mock_create_deployment, mock_consul): """ Test that committing changes fails when a user is new. """ self.client.force_login(self.user_with_instance) instance = self._setup_user_instance() make_test_deployment(instance, appserver_states=[]) response = self.client.post( reverse('api:v2:openedx-instance-deployment-list'), data={"id": self.instance_config.id}) self.assertEqual(response.status_code, 400) self.assertIn( "You must wait for your initial instance to finish building.", response.content.decode('utf-8'))
def test_commit_changes_fail_running_appserver(self, mock_create_deployment, mock_consul): """ Test that committing changes fails when a user is new. """ self.client.force_login(self.user_with_instance) instance = self._setup_user_instance() make_test_deployment(instance, appserver_states=[Status.ConfiguringServer]) response = self.client.post( reverse('api:v2:openedx-instance-deployment-list'), data={"id": self.instance_config.id}) self.assertEqual(response.status_code, 400) self.assertIn("Instance launch already in progress", response.content.decode('utf-8'))
def test_status(self, server_statuses, appserver_count, status, additional_deployment=False): """ Asserts that the .status() method returns the correct status based on the state of deployments and app servers. """ instance = OpenEdXInstanceFactory() if additional_deployment: deployment = make_test_deployment(instance) make_test_appserver(deployment=deployment, instance=instance) deployment = make_test_deployment(instance, appserver_states=server_statuses) deployment.instance.instance.openedx_appserver_count = appserver_count deployment.instance.instance.save() self.assertEqual(deployment.status(), status)
def test_get_deployment_notifications(self, mock_create_new_deployment, mock_consul): """ Ensures that notification contain deployment's deployed changes and that status of last healthy deployment with undeployed changes is 'changes_pending'. """ instance = self._setup_user_instance() first_deployment = make_test_deployment( instance, appserver_states=[Status.Running], active=True) second_deployment = make_test_deployment( instance, appserver_states=[Status.Running], active=True) changes = build_instance_config_diff(self.instance_config) first_deployment.changes = changes first_deployment.save() url = reverse("api:v2:notifications-list") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual( dict(response.data[0]), { "deployed_changes": [], "status": "changes_pending", "date": second_deployment.created.isoformat().replace("+00:00", "Z"), }, response.data) self.assertEqual( dict(response.data[1]), { # simulate postgres json field serialization and deserialization "deployed_changes": json.loads(json.dumps(changes)), "status": "healthy", "date": first_deployment.created.isoformat().replace("+00:00", "Z"), }, response.data)
def test_get_deployment_status_pending_changes(self, mock_create_new_deployment, mock_consul): """ Test that the correct status is returned when there's changes to be deployed. """ self.client.force_login(self.user_with_instance) instance = self._setup_user_instance() make_test_deployment(instance, active=True) url = reverse( 'api:v2:openedx-instance-deployment-detail', args=(self.instance_config.pk, ), ) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assert_deployment_response(response.data, status='changes_pending', undeployed_changes=3)
def test_cancel_deployment(self, deploy_type, status_code, mock_create_new_deployment, mock_consul): """ Test that trying to stop a provisioning succeeds. """ self.client.force_login(self.user_with_instance) instance = self._setup_user_instance() make_test_deployment(instance, appserver_states=[Status.Running], active=True) make_test_deployment(instance, appserver_states=[Status.ConfiguringServer], deployment_type=deploy_type) url = reverse( 'api:v2:openedx-instance-deployment-detail', args=(self.instance_config.pk, ), ) response = self.client.delete(url) self.assertEqual(response.status_code, status_code)
def test_spawn_when_cancelled(self, mocks, mock_provision, mock_consul): """ Spawn appserver with a cancelled deployment """ mock_provision.return_value = False instance = OpenEdXInstanceFactory(internal_lms_domain='test.activate.opencraft.co.uk') deployment = make_test_deployment(instance) deployment.cancelled = True deployment.save() appserver_id = instance.spawn_appserver(deployment_id=deployment.id) self.assertEqual(mock_provision.call_count, 1) self.assertIs(appserver_id, None)
def test_multi_appserver_activation(self, mock_consul, mock_make_active): """ Test the start_deployment task, and that it can be used to spawn multiple AppServer(s) for a new instance. """ instance = OpenEdXInstanceFactory() instance.openedx_appserver_count = 3 instance.save() make_test_deployment(instance, active=True) self.mock_make_appserver_active.s = Mock() self.mock_make_appserver_active.s.side_effect = make_appserver_active.s self.assertEqual(instance.appserver_set.count(), 3) appservers = list(instance.appserver_set.all()) self.assertTrue( all(instance.appserver_set.values_list('_is_active', flat=True))) deployment = OpenEdXDeployment.objects.create( instance_id=instance.ref.id) statuses = [(AppServerStatus.Running, ServerStatus.Ready.state_id)] * 3 self.mock_spawn_appserver.side_effect = gen_appserver_side_effect( deployment, instance, statuses) with self.assertLogs() as ctx: tasks.start_deployment( instance.ref.id, deployment.pk, mark_active_on_success=True, ).get() self.assertEqual(self.mock_make_appserver_active.s.call_count, 3) self.assertEqual(mock_make_active.call_count, 6) mock_make_active.assert_has_calls([ call(active=True), call(active=True), call(active=True), call(active=False), call(active=False), call(active=False), ]) for appserver in appservers: self.assertIn( f'INFO:instance.tasks:Deactivating {appserver} [{appserver.id}]', ctx.output)
def test_notifications_limit(self, mock_create_new_deployment, mock_consul): """ Tests that limit query param works as intended and doesn't allow malformed data. """ instance = self._setup_user_instance() for _ in range(5): make_test_deployment(instance, appserver_states=[Status.Running], active=True) url = reverse("api:v2:notifications-list") response = self.client.get(url, data={'limit': -1}) self.assertEqual(response.status_code, 400) response = self.client.get(url, data={'limit': 3}) self.assertEqual(response.status_code, 200) self.assertEqual(len(response.data), 3)
def test_multi_appserver_activation(self, mock_consul, mock_make_active): """ Test the create_new_deployment task, and that it can be used to spawn multiple AppServer(s) for a new instance. """ instance = OpenEdXInstanceFactory() instance.openedx_appserver_count = 3 instance.save() make_test_deployment(instance, active=True) self.assertEqual(instance.appserver_set.count(), 3) appservers = list(instance.appserver_set.all()) self.assertTrue( all(instance.appserver_set.values_list('_is_active', flat=True))) with self.assertLogs() as ctx: tasks.create_new_deployment( instance.ref.pk, mark_active_on_success=True, ).get() self.assertEqual(self.mock_make_appserver_active.call_count, 3) self.assertEqual(mock_make_active.call_count, 3) for appserver in appservers: self.assertIn( f'INFO:instance.tasks:Deactivating {appserver} [{appserver.id}]', ctx.output)
def test_provision_when_cancelled(self, mocks, mock_consul): """ Provision appserver with a cancelled deployment """ mocks.mock_run_ansible_playbooks.return_value = (['log'], 0) instance = OpenEdXInstanceFactory(internal_lms_domain='test.activate.opencraft.co.uk') deployment = make_test_deployment(instance) deployment.cancelled = True deployment.save() appserver = make_test_appserver(deployment=deployment) self.assertEqual(appserver.status, AppServerStatus.New) self.assertEqual(appserver.server.status, Server.Status.Pending) result = appserver.provision() self.assertFalse(result) self.assertEqual(mocks.mock_run_ansible_playbooks.call_count, 0) self.assertEqual(appserver.status, AppServerStatus.ConfiguringServer)