Commit f3e0148b authored by Miranda Fluharty's avatar Miranda Fluharty Committed by Scott Hampton

Reduce noisy code quality diff errors on MR page

Keep polling when the response status is 400 Bad Request
because we might still be generating/parsing/comparing new reports

Changelog: fixed
EE: true
parent 67139e53
...@@ -220,7 +220,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -220,7 +220,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end end
def codequality_mr_diff_reports def codequality_mr_diff_reports
reports_response(@merge_request.find_codequality_mr_diff_reports) reports_response(@merge_request.find_codequality_mr_diff_reports, head_pipeline)
end end
def codequality_reports def codequality_reports
......
...@@ -4,6 +4,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -4,6 +4,7 @@ import axios from '~/lib/utils/axios_utils';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
import Poll from '~/lib/utils/poll'; import Poll from '~/lib/utils/poll';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { MAX_RETRIES, RETRY_DELAY } from './constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
...@@ -28,6 +29,8 @@ export const restartCodequalityPolling = () => { ...@@ -28,6 +29,8 @@ export const restartCodequalityPolling = () => {
}; };
export const fetchCodequality = ({ commit, state, dispatch }) => { export const fetchCodequality = ({ commit, state, dispatch }) => {
let retryCount = 0;
codequalityPoll = new Poll({ codequalityPoll = new Poll({
resource: { resource: {
getCodequalityDiffReports: (endpoint) => axios.get(endpoint), getCodequalityDiffReports: (endpoint) => axios.get(endpoint),
...@@ -35,16 +38,32 @@ export const fetchCodequality = ({ commit, state, dispatch }) => { ...@@ -35,16 +38,32 @@ export const fetchCodequality = ({ commit, state, dispatch }) => {
data: state.endpointCodequality, data: state.endpointCodequality,
method: 'getCodequalityDiffReports', method: 'getCodequalityDiffReports',
successCallback: ({ status, data }) => { successCallback: ({ status, data }) => {
retryCount = 0;
if (status === httpStatusCodes.OK) { if (status === httpStatusCodes.OK) {
commit(types.SET_CODEQUALITY_DATA, data); commit(types.SET_CODEQUALITY_DATA, data);
dispatch('stopCodequalityPolling'); dispatch('stopCodequalityPolling');
} }
}, },
errorCallback: () => errorCallback: ({ response }) => {
createFlash({ if (response.status === httpStatusCodes.BAD_REQUEST) {
message: __('Something went wrong on our end while loading the code quality diff.'), // we could get a 400 status response temporarily during report processing
}), // so we retry up to MAX_RETRIES times in case the reports are on their way
// and stop polling if we get 400s consistently
if (retryCount < MAX_RETRIES) {
codequalityPoll.makeDelayedRequest(RETRY_DELAY);
retryCount += 1;
} else {
codequalityPoll.stop();
}
} else {
retryCount = 0;
dispatch('stopCodequalityPolling');
createFlash({
message: __('An unexpected error occurred while loading the code quality diff.'),
});
}
},
}); });
if (!Visibility.hidden()) { if (!Visibility.hidden()) {
......
export const MAX_RETRIES = 5;
export const RETRY_DELAY = 3000; // milliseconds
...@@ -5,10 +5,13 @@ import { ...@@ -5,10 +5,13 @@ import {
stopCodequalityPolling, stopCodequalityPolling,
fetchCodequality, fetchCodequality,
} from 'ee/diffs/store/actions'; } from 'ee/diffs/store/actions';
import { RETRY_DELAY } from 'ee/diffs/store/constants';
import * as types from 'ee/diffs/store/mutation_types'; import * as types from 'ee/diffs/store/mutation_types';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import Poll from '~/lib/utils/poll';
jest.mock('~/flash'); jest.mock('~/flash');
...@@ -30,7 +33,7 @@ describe('EE DiffsStoreActions', () => { ...@@ -30,7 +33,7 @@ describe('EE DiffsStoreActions', () => {
describe('fetchCodequality', () => { describe('fetchCodequality', () => {
let mock; let mock;
const endpoint = '/codequality_mr_diff.json'; const endpointCodequality = '/codequality_mr_diff.json';
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
...@@ -46,28 +49,86 @@ describe('EE DiffsStoreActions', () => { ...@@ -46,28 +49,86 @@ describe('EE DiffsStoreActions', () => {
files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] }, files: { 'app.js': [{ line: 1, description: 'Unexpected alert.', severity: 'minor' }] },
}; };
mock.onGet(endpoint).reply(200, { data }); mock.onGet(endpointCodequality).reply(200, { data });
testAction( testAction(
fetchCodequality, fetchCodequality,
{}, {},
{ endpointCodequality: endpoint }, { endpointCodequality },
[{ type: types.SET_CODEQUALITY_DATA, payload: { data } }], [{ type: types.SET_CODEQUALITY_DATA, payload: { data } }],
[{ type: 'stopCodequalityPolling' }], [{ type: 'stopCodequalityPolling' }],
done, done,
); );
}); });
it('should show flash on API error', (done) => { describe('with 400 status response', () => {
mock.onGet(endpoint).reply(400); let pollDelayedRequest;
let pollStop;
testAction(fetchCodequality, {}, { endpoint }, [], [], () => { beforeEach(() => {
expect(createFlash).toHaveBeenCalledTimes(1); pollDelayedRequest = jest.spyOn(Poll.prototype, 'makeDelayedRequest');
expect(createFlash).toHaveBeenCalledWith({ pollStop = jest.spyOn(Poll.prototype, 'stop');
message: 'Something went wrong on our end while loading the code quality diff.',
mock.onGet(endpointCodequality).reply(400);
});
it('should not show a flash message', (done) => {
testAction(fetchCodequality, {}, { endpointCodequality }, [], [], () => {
expect(createFlash).not.toHaveBeenCalled();
done();
});
});
it('should retry five times with a delay, then stop polling', (done) => {
testAction(fetchCodequality, {}, { endpointCodequality }, [], [], () => {
expect(pollDelayedRequest).toHaveBeenCalledTimes(1);
expect(pollStop).toHaveBeenCalledTimes(0);
jest.advanceTimersByTime(RETRY_DELAY);
waitForPromises()
.then(() => {
expect(pollDelayedRequest).toHaveBeenCalledTimes(2);
jest.advanceTimersByTime(RETRY_DELAY);
})
.then(() => waitForPromises())
.then(() => jest.advanceTimersByTime(RETRY_DELAY))
.then(() => waitForPromises())
.then(() => jest.advanceTimersByTime(RETRY_DELAY))
.then(() => waitForPromises())
.then(() => {
expect(pollDelayedRequest).toHaveBeenCalledTimes(5);
jest.advanceTimersByTime(RETRY_DELAY);
})
.then(() => waitForPromises())
.then(() => {
expect(pollStop).toHaveBeenCalledTimes(1);
})
.then(done)
.catch(done.fail);
}); });
done();
}); });
}); });
it('with unexpected error should stop polling and show a flash message', (done) => {
mock.onGet(endpointCodequality).reply(500);
testAction(
fetchCodequality,
{},
{ endpointCodequality },
[],
[{ type: 'stopCodequalityPolling' }],
() => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith({
message: 'An unexpected error occurred while loading the code quality diff.',
});
done();
},
);
});
}); });
}); });
...@@ -3831,6 +3831,9 @@ msgstr "" ...@@ -3831,6 +3831,9 @@ msgstr ""
msgid "An unexpected error occurred while communicating with the Web Terminal." msgid "An unexpected error occurred while communicating with the Web Terminal."
msgstr "" msgstr ""
msgid "An unexpected error occurred while loading the code quality diff."
msgstr ""
msgid "An unexpected error occurred while starting the Web Terminal." msgid "An unexpected error occurred while starting the Web Terminal."
msgstr "" msgstr ""
...@@ -30201,9 +30204,6 @@ msgstr "" ...@@ -30201,9 +30204,6 @@ msgstr ""
msgid "Something went wrong on our end" msgid "Something went wrong on our end"
msgstr "" msgstr ""
msgid "Something went wrong on our end while loading the code quality diff."
msgstr ""
msgid "Something went wrong on our end." msgid "Something went wrong on our end."
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment