Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
    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)
Exemple #4
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)
Exemple #5
0
    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)
Exemple #6
0
    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)
Exemple #7
0
    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)
Exemple #8
0
    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)
Exemple #9
0
    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)
Exemple #10
0
    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)
Exemple #11
0
    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)
Exemple #12
0
    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)
Exemple #13
0
    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)
Exemple #14
0
    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.'})
Exemple #15
0
    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.'})