def test_ansible_settings_mongo(self): """ Add mongo ansible vars if INSTANCE_MONGO_URL is set """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=False) instance.reset_ansible_settings() self.assertIn('EDXAPP_MONGO_USER: {0}'.format(instance.mongo_user), instance.ansible_settings) self.assertIn('EDXAPP_MONGO_PASSWORD: {0}'.format(instance.mongo_pass), instance.ansible_settings) self.assertIn('EDXAPP_MONGO_HOSTS: [mongo.opencraft.com]', instance.ansible_settings) self.assertIn('EDXAPP_MONGO_PORT: 27017', instance.ansible_settings) self.assertIn( 'EDXAPP_MONGO_DB_NAME: {0}'.format(instance.mongo_database_name), instance.ansible_settings) self.assertIn('FORUM_MONGO_USER: {0}'.format(instance.mongo_user), instance.ansible_settings) self.assertIn('FORUM_MONGO_PASSWORD: {0}'.format(instance.mongo_pass), instance.ansible_settings) self.assertIn('FORUM_MONGO_HOSTS: [mongo.opencraft.com]', instance.ansible_settings) self.assertIn('FORUM_MONGO_PORT: 27017', instance.ansible_settings) self.assertIn( 'FORUM_MONGO_DATABASE: {0}'.format(instance.forum_database_name), instance.ansible_settings)
def test_get_log_entries(self): """ GET - Log entries """ self.api_client.login(username='******', password='******') instance = OpenEdXInstanceFactory(sub_domain='instance0') server = OpenStackServerFactory(openstack_id="vm0", instance=instance) instance.logger.info("info") instance.logger.error("error") server.logger.info("info") server.logger.error("error") response = self.api_client.get('/api/v1/openedxinstance/{pk}/'.format(pk=instance.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK) expected_list = [ {'level': 'INFO', 'text': 'instance.models.instance | instance=instance0 | info'}, {'level': 'ERROR', 'text': 'instance.models.instance | instance=instance0 | error'}, {'level': 'INFO', 'text': 'instance.models.server | instance=instance0,server=vm0 | info'}, {'level': 'ERROR', 'text': 'instance.models.server | instance=instance0,server=vm0 | error'}, ] self.assertEqual(len(expected_list), len(response.data['log_entries'])) for expected_entry, log_entry in zip(expected_list, response.data['log_entries']): self.assertEqual(expected_entry['level'], log_entry['level']) self.assertEqual(expected_entry['text'], log_entry['text'])
def test_ansible_settings_mysql_not_set(self): """ Don't add mysql ansible vars if INSTANCE_MYSQL_URL is not set """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=False) instance.reset_ansible_settings() self.check_mysql_vars_not_set(instance)
def test_provision_mongo(self): """ Provision mongo databases """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=False) instance.provision_mongo() self.check_mongo(instance)
def test_inventory_str(self, os_server_manager): """ Ansible inventory - showing servers once they are in booted status """ instance = OpenEdXInstanceFactory() self.assertEqual(instance.inventory_str, '[app]') # Server 1: 'started' StartedOpenStackServerFactory(instance=instance) self.assertEqual(instance.inventory_str, '[app]') # Server 2: 'booted' server2 = BootedOpenStackServerFactory(instance=instance) os_server_manager.add_fixture(server2.openstack_id, 'openstack/api_server_2_active.json') self.assertEqual(instance.inventory_str, '[app]') # Server 3: 'provisioning' server3 = ProvisioningOpenStackServerFactory(instance=instance) os_server_manager.add_fixture(server3.openstack_id, 'openstack/api_server_2_active.json') self.assertEqual(instance.inventory_str, '[app]\n192.168.100.200') # Server 4: 'provisioning' server4 = ProvisioningOpenStackServerFactory(instance=instance) os_server_manager.add_fixture(server4.openstack_id, 'openstack/api_server_3_active.json') self.assertEqual(instance.inventory_str, '[app]\n192.168.100.200\n192.168.99.66')
def test_ansible_s3_settings(self): """ Add extra settings in ansible vars, which can override existing settings """ instance = OpenEdXInstanceFactory( s3_access_key='test-s3-access-key', s3_secret_access_key='test-s3-secret-access-key', s3_bucket_name='test-s3-bucket-name', ) instance.reset_ansible_settings() self.assertIn('AWS_ACCESS_KEY_ID: test-s3-access-key', instance.ansible_settings) self.assertIn('AWS_SECRET_ACCESS_KEY: test-s3-secret-access-key', instance.ansible_settings) self.assertIn( 'EDXAPP_AUTH_EXTRA: {AWS_STORAGE_BUCKET_NAME: test-s3-bucket-name}', instance.ansible_settings) self.assertIn('EDXAPP_AWS_ACCESS_KEY_ID: test-s3-access-key', instance.ansible_settings) self.assertIn( 'EDXAPP_AWS_SECRET_ACCESS_KEY: test-s3-secret-access-key', instance.ansible_settings) self.assertIn('XQUEUE_AWS_ACCESS_KEY_ID: test-s3-access-key', instance.ansible_settings) self.assertIn( 'XQUEUE_AWS_SECRET_ACCESS_KEY: test-s3-secret-access-key', instance.ansible_settings) self.assertIn('XQUEUE_S3_BUCKET: test-s3-bucket-name', instance.ansible_settings)
def setUp(self): """ Set up an instance and server to use for testing. """ super().setUp() self.instance = OpenEdXInstanceFactory(sub_domain='my.instance') self.server = OpenStackServerFactory(instance=self.instance, openstack_id='vm1_id')
def test_provision_failed_email(self): """ Tests that provision_failed sends email when called from normal program flow """ instance = OpenEdXInstanceFactory(name='test', sub_domain='test') reason = "something went wrong" log_lines = ["log line1", "log_line2"] instance.provision_failed_email(reason, log_lines) expected_subject = OpenEdXInstance.EmailSubject.PROVISION_FAILED.format( instance_name=instance.name, instance_url=instance.url) expected_recipients = [ admin_tuple[1] for admin_tuple in settings.ADMINS ] self.assertEqual(len(django_mail.outbox), 1) mail = django_mail.outbox[0] self.assertIn(expected_subject, mail.subject) self.assertIn(instance.name, mail.body) self.assertIn(reason, mail.body) self.assertEqual(mail.from_email, settings.SERVER_EMAIL) self.assertEqual(mail.to, expected_recipients) self.assertEqual(len(mail.attachments), 1) self.assertEqual(mail.attachments[0], ("provision.log", "\n".join(log_lines), "text/plain"))
def test_ansible_settings_mysql_ephemeral(self): """ Don't add mysql ansible vars for ephemeral databases """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=True) instance.reset_ansible_settings() self.check_mysql_vars_not_set(instance)
def test_provision_with_external_databases(self, mocks): """ Run provisioning sequence, with external databases """ mocks.mock_create_server.side_effect = [ Mock(id='test-run-provisioning-server'), None ] mocks.os_server_manager.add_fixture( 'test-run-provisioning-server', 'openstack/api_server_2_active.json') instance = OpenEdXInstanceFactory(sub_domain='run.provisioning', use_ephemeral_databases=False) def deploy(): """ Make sure that ansible settings are present at deploy time """ ansible_settings = yaml.load(instance.ansible_settings) for setting in ('EDXAPP_MYSQL_USER', 'EDXAPP_MONGO_PASSWORD', 'EDXAPP_MONGO_USER', 'EDXAPP_MONGO_PASSWORD', 'EDXAPP_SWIFT_USERNAME', 'EDXAPP_SWIFT_KEY'): self.assertTrue(ansible_settings[setting]) return (['log'], 0) mocks.mock_deploy.side_effect = deploy instance.provision() self.assertEqual(mocks.mock_provision_mysql.call_count, 1) self.assertEqual(mocks.mock_provision_mongo.call_count, 1) self.assertEqual(mocks.mock_provision_swift.call_count, 1)
def test_provision(self, mocks): """ Run provisioning sequence """ mocks.mock_deploy.return_value = (['log'], 0) mocks.mock_create_server.side_effect = [ Mock(id='test-run-provisioning-server'), None ] mocks.os_server_manager.add_fixture( 'test-run-provisioning-server', 'openstack/api_server_2_active.json') mock_reboot = mocks.os_server_manager.get_os_server( 'test-run-provisioning-server').reboot instance = OpenEdXInstanceFactory(sub_domain='run.provisioning', use_ephemeral_databases=True) instance.provision() self.assertEqual(mocks.mock_set_dns_record.mock_calls, [ call(name='run.provisioning', type='A', value='192.168.100.200'), call(name='studio.run.provisioning', type='CNAME', value='run.provisioning'), ]) self.assertEqual(mocks.mock_deploy.call_count, 1) self.assertEqual(mock_reboot.call_count, 1) self.assertEqual(mocks.mock_provision_mysql.call_count, 0) self.assertEqual(mocks.mock_provision_mongo.call_count, 0) self.assertEqual(mocks.mock_provision_swift.call_count, 0)
def test_ansible_settings_mongo_ephemeral(self): """ Don't add mongo ansible vars if INSTANCE_MONGO_URL is not set """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=True) instance.reset_ansible_settings() self.check_mongo_vars_not_set(instance)
def test_provision_mysql(self): """ Provision mysql database """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=False) instance.provision_mysql() self.check_mysql(instance)
def test_swift_disabled(self, mock_swift_connection): """ Verify disabling Swift provisioning works. """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=False) instance.provision_swift() self.assertIs(instance.swift_provisioned, False) self.assertFalse(mock_swift_connection.called)
def test_ansible_playbook_filename(self): """ Set name of ansible playbook & get filename """ instance = OpenEdXInstanceFactory( ansible_playbook_name='test_playbook') self.assertEqual(instance.ansible_playbook_filename, 'test_playbook.yml')
def test_provision_github_branch_deleted(self, mock_get_commit_id_from_ref): """ POST /:id/provision - GitHub returns 404 response for instance branch """ self.api_client.login(username='******', password='******') instance = OpenEdXInstanceFactory() mock_get_commit_id_from_ref.side_effect = github.ObjectDoesNotExist response = self.api_client.post('/api/v1/openedxinstance/{pk}/provision/'.format(pk=instance.pk)) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_status_terminated(self): """ Instance status should revert to 'empty' when all its servers are terminated """ instance = OpenEdXInstanceFactory() server = StartedOpenStackServerFactory(instance=instance) self.assertEqual(instance.status, server.Status.Started) server._transition(server._status_to_terminated) self.assertIsNone(instance.status)
def test_commit_short_id(self): """ Short representation of a commit_id """ instance = OpenEdXInstanceFactory( commit_id='6e580ca9fed6fb65ec45949494dabec40e8cb533') self.assertEqual(instance.commit_short_id, '6e580ca') instance.commit_id = None self.assertEqual(instance.commit_short_id, None)
def test_github_admin_username_list_default(self): """ By default, no admin should be configured """ instance = OpenEdXInstanceFactory() instance.reset_ansible_settings() self.assertEqual(instance.github_admin_organization_name, '') self.assertEqual(instance.github_admin_username_list, []) self.assertNotIn('COMMON_USER_INFO', instance.ansible_settings)
def test_set_to_branch_tip_extra_args(self, mock_get_commit_id_from_ref): """ Set the commit id to the tip of a specified reference """ mock_get_commit_id_from_ref.return_value = 'c' * 40 instance = OpenEdXInstanceFactory(commit_id='a' * 40) instance.set_to_branch_tip(branch_name='new-branch', ref_type='tag') self.assertEqual(instance.commit_id, 'c' * 40) self.assertEqual(instance.branch_name, 'new-branch') self.assertEqual(instance.ref_type, 'tag')
def test_provision_sandbox_instance(self, mock_instance_provision): """ Create sandbox instance """ instance = OpenEdXInstanceFactory() tasks.provision_instance(instance.pk) self.assertEqual(mock_instance_provision.call_count, 1) self.assertEqual(mock_instance_provision.mock_calls[0][1][0].pk, instance.pk) self.mock_db_connection_close.assert_called_once_with()
def test_provision_mysql_no_url(self): """ Don't provision a mysql database if INSTANCE_MYSQL_URL is not set """ instance = OpenEdXInstanceFactory(use_ephemeral_databases=False) instance.provision_mysql() databases = subprocess.check_output( "mysql -u root -e 'SHOW DATABASES'", shell=True).decode() for database in instance.mysql_database_names: self.assertNotIn(database, databases)
def test_set_to_branch_tip_replace_commit_hash( self, mock_get_commit_id_from_ref): """ The hash should be updated in the instance name when updating """ mock_get_commit_id_from_ref.return_value = '1234567' + 'd' * 33 instance = OpenEdXInstanceFactory(commit_id='a' * 40, name='Test Instance (aaaaaaa)') instance.set_to_branch_tip(branch_name='new-branch', ref_type='tag') self.assertEqual(instance.name, 'Test Instance (1234567)')
def test_get_by_fork_name(self): """ Use `fork_name` to get an instance object from the ORM """ OpenEdXInstanceFactory( github_organization_name='get-by', github_repository_name='fork-name', ) instance = OpenEdXInstance.objects.get(fork_name='get-by/fork-name') self.assertEqual(instance.fork_name, 'get-by/fork-name')
def test_provision_not_ready(self): """ POST /:id/provision - Status not ready """ self.api_client.login(username='******', password='******') instance = OpenEdXInstanceFactory() OpenStackServerFactory(instance=instance, progress=OpenStackServer.Progress.Running) self.assertEqual(instance.progress, OpenStackServer.Progress.Running) response = self.api_client.post('/api/v1/openedxinstance/{pk}/provision/'.format(pk=instance.pk)) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_new_instance(self): """ New OpenEdXInstance object """ self.assertFalse(OpenEdXInstance.objects.all()) instance = OpenEdXInstanceFactory() self.assertEqual(OpenEdXInstance.objects.get().pk, instance.pk) self.assertTrue( re.search( r'Test Instance \d+ \(http://instance\d+\.test\.example\.com/\)', str(instance)))
def test_status_multiple_servers(self): """ Instance status should not allow multiple active servers """ instance = OpenEdXInstanceFactory() StartedOpenStackServerFactory(instance=instance) self.assertEqual(instance.status, Server.Status.Started) self.assertEqual(instance.progress, Server.Progress.Running) StartedOpenStackServerFactory(instance=instance) with self.assertRaises(InconsistentInstanceState): instance.status #pylint: disable=pointless-statement
def test_get_domain(self): """ GET - Domain attributes """ self.api_client.login(username='******', password='******') OpenEdXInstanceFactory(sub_domain='domain.api') response = self.api_client.get('/api/v1/openedxinstance/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertIn(('domain', 'domain.api.example.com'), response.data[0].items()) self.assertIn(('url', 'http://domain.api.example.com/'), response.data[0].items()) self.assertIn(('studio_url', 'http://studio.domain.api.example.com/'), response.data[0].items())
def test_provision_mysql_weird_domain(self): """ Make sure that database names are escaped correctly """ sub_domain = 'really.really.really.really.long.subdomain' base_domain = 'this-is-a-really-long-unusual-domain-แปลกมาก.com' instance = OpenEdXInstanceFactory(use_ephemeral_databases=False, sub_domain=sub_domain, base_domain=base_domain) instance.provision_mysql() self.check_mysql(instance)
def test_provision_mongo_no_url(self): """ Don't provision any mongo databases if INSTANCE_MONGO_URL is not set """ mongo = pymongo.MongoClient(settings.INSTANCE_MONGO_URL) with override_settings(INSTANCE_MONGO_URL=None): instance = OpenEdXInstanceFactory(use_ephemeral_databases=False) instance.provision_mongo() databases = mongo.database_names() for database in instance.mongo_database_names: self.assertNotIn(database, databases)