def test_get_filtered_by_organization(self, mock_get_pr_by_number, mock_get_commit_id_from_ref): """ GET+POST - A user (instance manager) can only manage PRs from WF which belong to the user's organization. """ wpr1 = make_watched_pr_and_instance(username='******', organization=self.organization) wpr2 = make_watched_pr_and_instance(username='******', organization=self.organization2) self.assertEqual(WatchedPullRequest.objects.count(), 2) # We'll log in with user4, and we should only see pr2, but not pr1 self.api_client.login(username='******', password='******') # Check the PR list response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertNotIn(('id', wpr1.pk), response.data[0].items()) self.assertIn(('id', wpr2.pk), response.data[0].items()) # Also check the detailed view response = self.api_client.get('/api/v1/pr_watch/{pk}/'.format(pk=wpr1.pk)) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) response = self.api_client.get('/api/v1/pr_watch/{pk}/'.format(pk=wpr2.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK) # Also check update_instance mock_get_pr_by_number.return_value = PRFactory(number=wpr1.github_pr_number) response = self.api_client.post('/api/v1/pr_watch/{pk}/update_instance/'.format(pk=wpr1.pk)) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) mock_get_pr_by_number.return_value = PRFactory(number=wpr2.github_pr_number) response = self.api_client.post('/api/v1/pr_watch/{pk}/update_instance/'.format(pk=wpr2.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_shut_down_obsolete_pr_sandboxes(self, data, mock_archive, mock_logger, mock_consul): """ Test that `shut_down_obsolete_pr_sandboxes` correctly identifies and shuts down instances whose PRs got merged (more than) one week ago. """ mock_logger.side_effect = self.mock_logger_process reference_date = timezone.now() # Create PRs and instances for i in range(5): make_watched_pr_and_instance(source_fork_name='some/fork{}'.format(i)) # Calculate date when PR was closed pr_state = data['pr_state'] if pr_state == 'closed': pr_closed_date = reference_date - timedelta(days=data['pr_days_since_closed']) closed_at = pr_closed_date.strftime('%Y-%m-%dT%H:%M:%SZ') else: closed_at = None with patch( 'pr_watch.github.get_pr_info_by_number', return_value={'state': pr_state, 'closed_at': closed_at}, ): # Run task tasks.shut_down_obsolete_pr_sandboxes() # Check if task tried to shut down instances if data['instance_is_archived']: self.assertEqual(mock_archive.call_count, 5) self.assertEqual(mock_logger.call_count, 15) mock_logger.assert_called_with("Shutting down obsolete sandbox instance", {}) else: self.assertEqual(mock_archive.call_count, 0) self.assertEqual(mock_logger.call_count, 10)
def test_shut_down_obsolete_pr_sandboxes(self, data, mock_shut_down): """ Test that `shut_down_obsolete_pr_sandboxes` correctly identifies and shuts down instances whose PRs got merged (more than) one week ago. """ reference_date = timezone.now() # Create PRs and instances for dummy in range(5): make_watched_pr_and_instance() # Calculate date when PR was closed pr_state = data['pr_state'] if pr_state == 'closed': pr_closed_date = reference_date - timedelta(days=data['pr_days_since_closed']) closed_at = pr_closed_date.strftime('%Y-%m-%dT%H:%M:%SZ') else: closed_at = None with patch( 'pr_watch.github.get_pr_info_by_number', return_value={'state': pr_state, 'closed_at': closed_at}, ): # Run task tasks.shut_down_obsolete_pr_sandboxes() # Check if task tried to shut down instances if data['instance_is_shut_down']: self.assertEqual(mock_shut_down.call_count, 5) else: self.assertEqual(mock_shut_down.call_count, 0)
def test_get_authenticated(self, username, mock_consul): """ GET - Authenticated - instance manager users (superuser or not) allowed access """ self.api_client.login(username=username, password='******') response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.data, []) # This uses user4's organization. Both user3 and user4 will be able to see it later watched_pr = make_watched_pr_and_instance( branch_name='api-test-branch', username='******', organization=self.organization2) def check_output(data): """ Check that the data object passed matches expectations for 'watched_pr' """ data = data.items() self.assertIn(('id', watched_pr.pk), data) self.assertIn(('fork_name', 'fork/repo'), data) self.assertIn(('target_fork_name', 'source/repo'), data) self.assertIn(('branch_name', 'api-test-branch'), data) self.assertIn(('github_pr_number', watched_pr.github_pr_number), data) self.assertIn(('github_pr_url', watched_pr.github_pr_url), data) self.assertIn(('instance_id', watched_pr.instance.ref.id), data) response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.status_code, status.HTTP_200_OK) check_output(response.data[0]) # And check the details view: response = self.api_client.get( '/api/v1/pr_watch/{pk}/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK) check_output(response.data)
def test_update_instance(self, username, mock_get_pr_by_number, mock_consul): """ POST /pr_watch/:id/update_instance/ - Update instance with latest settings from the PR """ self.api_client.login(username=username, password='******') # Create a WatchedPullRequest, and OpenEdXInstance: watched_pr = make_watched_pr_and_instance( username='******', organization=self.organization2) instance = OpenEdXInstance.objects.get(pk=watched_pr.instance_id) self.assertIn('fork/master (5555555)', instance.name) self.assertEqual(instance.edx_platform_commit, '5' * 40) # Now mock the PR being updated on GitHub mock_get_pr_by_number.return_value = PRFactory( number=watched_pr.github_pr_number, title="Updated Title", ) with patch('pr_watch.github.get_commit_id_from_ref', return_value=('6' * 40)): response = self.api_client.post( '/api/v1/pr_watch/{pk}/update_instance/'.format( pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK) instance.refresh_from_db() self.assertEqual( instance.name, 'PR#{}: Updated Title (edx) - fork/master (6666666)'.format( watched_pr.github_pr_number)) self.assertEqual(instance.edx_platform_commit, '6' * 40)
def test_update_instance(self, mock_get_pr_by_number): """ POST /pr_watch/:id/update_instance/ - Update instance with latest settings from the PR """ self.api_client.login(username='******', password='******') # Create a WatchedPullRequest, and OpenEdXInstance: watched_pr = make_watched_pr_and_instance() instance = OpenEdXInstance.objects.get(pk=watched_pr.instance_id) self.assertIn('fork/master (5555555)', instance.name) self.assertEqual(instance.edx_platform_commit, '5' * 40) # Now mock the PR being updated on GitHub mock_get_pr_by_number.return_value = PRFactory( number=watched_pr.github_pr_number, title="Updated Title", ) with patch('pr_watch.github.get_commit_id_from_ref', return_value=('6' * 40)): response = self.api_client.post('/api/v1/pr_watch/{pk}/update_instance/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK) instance.refresh_from_db() self.assertEqual( instance.name, 'PR#{}: Updated Title (edx) - fork/master (6666666)'.format(watched_pr.github_pr_number) ) self.assertEqual(instance.edx_platform_commit, '6' * 40)
def test_get_authenticated(self): """ GET - Authenticated """ self.api_client.login(username='******', password='******') response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.data, []) watched_pr = make_watched_pr_and_instance(branch_name='api-test-branch') def check_output(data): """ Check that the data object passed matches expectations for 'watched_pr' """ data = data.items() self.assertIn(('id', watched_pr.pk), data) self.assertIn(('fork_name', 'fork/repo'), data) self.assertIn(('target_fork_name', 'source/repo'), data) self.assertIn(('branch_name', 'api-test-branch'), data) self.assertIn(('github_pr_number', watched_pr.github_pr_number), data) self.assertIn(('github_pr_url', watched_pr.github_pr_url), data) self.assertIn(('instance_id', watched_pr.instance.ref.id), data) response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.status_code, status.HTTP_200_OK) check_output(response.data[0]) # And check the details view: response = self.api_client.get('/api/v1/pr_watch/{pk}/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_200_OK) check_output(response.data)
def test_update_unauthenticated(self): """ POST /pr_watch/:id/update_instance/ - Denied to anonymous users """ forbidden_message = {"detail": "Authentication credentials were not provided."} # Create a WatchedPullRequest, and OpenEdXInstance: watched_pr = make_watched_pr_and_instance() response = self.api_client.post('/api/v1/pr_watch/{pk}/update_instance/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.data, forbidden_message)
def test_update_permission_denied(self, username): """ POST /pr_watch/:id/update_instance/ - Denied to non instance managers (basic user and staff) """ forbidden_message = {"detail": "You do not have permission to perform this action."} self.api_client.login(username=username, password='******') # Create a WatchedPullRequest, and OpenEdXInstance: watched_pr = make_watched_pr_and_instance() response = self.api_client.post('/api/v1/pr_watch/{pk}/update_instance/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.data, forbidden_message)
def test_get_unauthenticated(self): """ GET - Require to be authenticated """ forbidden_message = {"detail": "Authentication credentials were not provided."} response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.data, forbidden_message) watched_pr = make_watched_pr_and_instance() response = self.api_client.get('/api/v1/pr_watch/{pk}/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.data, forbidden_message)
def test_get_permission_denied(self, username): """ GET - basic and staff users denied access """ forbidden_message = {"detail": "You do not have permission to perform this action."} self.api_client.login(username=username, password='******') response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.data, forbidden_message) watched_pr = make_watched_pr_and_instance() response = self.api_client.get('/api/v1/pr_watch/{pk}/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.data, forbidden_message)
def test_no_organization(self): """ GET+POST - An instance manager without an organization can't see/update any PR. """ self.api_client.login(username='******', password='******') watched_pr = make_watched_pr_and_instance(branch_name='api-test-branch') response = self.api_client.get('/api/v1/pr_watch/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data, []) response = self.api_client.get('/api/v1/pr_watch/{pk}/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) response = self.api_client.post('/api/v1/pr_watch/{pk}/update_instance/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_update_instance_branch_delete(self, mock_get_pr_by_number, mock_get_commit_id_from_ref): """ Test what happens when we try to update an instance for a PR whose branch has been deleted. Note: Once WatchedPullRequest.update_instance_from_pr() has been refactored so that it first queries GitHub for PR details (rather than accepting a PR parameter), it can get the commit ID from the PR details response, rather than using get_branch_tip(), and then this test won't be necessary since the PR API always contains the commit information (in ["head"]["sha"]) even if the branch has been deleted. """ self.api_client.login(username='******', password='******') watched_pr = make_watched_pr_and_instance() mock_get_pr_by_number.return_value = PRFactory(number=watched_pr.github_pr_number) response = self.api_client.post('/api/v1/pr_watch/{pk}/update_instance/'.format(pk=watched_pr.pk)) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.data, {'error': 'Could not fetch updated details from GitHub.'})