Commit 632083c7 authored by Paul Slaughter's avatar Paul Slaughter

Add traceTimeout to state and stopPolling action

**Why?**
This was causing an issue in tests because the poll
was never properly disposed.

https://gitlab.com/gitlab-org/gitlab/issues/55254
parent 43a868d8
...@@ -176,7 +176,9 @@ export default { ...@@ -176,7 +176,9 @@ export default {
mounted() { mounted() {
this.updateSidebar(); this.updateSidebar();
}, },
destroyed() { beforeDestroy() {
this.stopPollingTrace();
this.stopPolling();
window.removeEventListener('resize', this.onResize); window.removeEventListener('resize', this.onResize);
window.removeEventListener('scroll', this.updateScroll); window.removeEventListener('scroll', this.updateScroll);
}, },
...@@ -192,6 +194,8 @@ export default { ...@@ -192,6 +194,8 @@ export default {
'fetchTrace', 'fetchTrace',
'scrollBottom', 'scrollBottom',
'scrollTop', 'scrollTop',
'stopPollingTrace',
'stopPolling',
'toggleScrollButtons', 'toggleScrollButtons',
'toggleScrollAnimation', 'toggleScrollAnimation',
]), ]),
......
...@@ -147,7 +147,6 @@ export const toggleScrollisInBottom = ({ commit }, toggle) => { ...@@ -147,7 +147,6 @@ export const toggleScrollisInBottom = ({ commit }, toggle) => {
export const requestTrace = ({ commit }) => commit(types.REQUEST_TRACE); export const requestTrace = ({ commit }) => commit(types.REQUEST_TRACE);
let traceTimeout;
export const fetchTrace = ({ dispatch, state }) => export const fetchTrace = ({ dispatch, state }) =>
axios axios
.get(`${state.traceEndpoint}/trace.json`, { .get(`${state.traceEndpoint}/trace.json`, {
...@@ -157,24 +156,32 @@ export const fetchTrace = ({ dispatch, state }) => ...@@ -157,24 +156,32 @@ export const fetchTrace = ({ dispatch, state }) =>
dispatch('toggleScrollisInBottom', isScrolledToBottom()); dispatch('toggleScrollisInBottom', isScrolledToBottom());
dispatch('receiveTraceSuccess', data); dispatch('receiveTraceSuccess', data);
if (!data.complete) { if (data.complete) {
traceTimeout = setTimeout(() => {
dispatch('fetchTrace');
}, 4000);
} else {
dispatch('stopPollingTrace'); dispatch('stopPollingTrace');
} else if (!state.traceTimeout) {
dispatch('startPollingTrace');
} }
}) })
.catch(() => dispatch('receiveTraceError')); .catch(() => dispatch('receiveTraceError'));
export const stopPollingTrace = ({ commit }) => { export const startPollingTrace = ({ dispatch, commit }) => {
const traceTimeout = setTimeout(() => {
commit(types.SET_TRACE_TIMEOUT, 0);
dispatch('fetchTrace');
}, 4000);
commit(types.SET_TRACE_TIMEOUT, traceTimeout);
};
export const stopPollingTrace = ({ state, commit }) => {
clearTimeout(state.traceTimeout);
commit(types.SET_TRACE_TIMEOUT, 0);
commit(types.STOP_POLLING_TRACE); commit(types.STOP_POLLING_TRACE);
clearTimeout(traceTimeout);
}; };
export const receiveTraceSuccess = ({ commit }, log) => commit(types.RECEIVE_TRACE_SUCCESS, log); export const receiveTraceSuccess = ({ commit }, log) => commit(types.RECEIVE_TRACE_SUCCESS, log);
export const receiveTraceError = ({ commit }) => { export const receiveTraceError = ({ dispatch }) => {
commit(types.RECEIVE_TRACE_ERROR); dispatch('stopPollingTrace');
clearTimeout(traceTimeout);
flash(__('An error occurred while fetching the job log.')); flash(__('An error occurred while fetching the job log.'));
}; };
/** /**
......
...@@ -20,6 +20,7 @@ export const RECEIVE_JOB_SUCCESS = 'RECEIVE_JOB_SUCCESS'; ...@@ -20,6 +20,7 @@ export const RECEIVE_JOB_SUCCESS = 'RECEIVE_JOB_SUCCESS';
export const RECEIVE_JOB_ERROR = 'RECEIVE_JOB_ERROR'; export const RECEIVE_JOB_ERROR = 'RECEIVE_JOB_ERROR';
export const REQUEST_TRACE = 'REQUEST_TRACE'; export const REQUEST_TRACE = 'REQUEST_TRACE';
export const SET_TRACE_TIMEOUT = 'SET_TRACE_TIMEOUT';
export const STOP_POLLING_TRACE = 'STOP_POLLING_TRACE'; export const STOP_POLLING_TRACE = 'STOP_POLLING_TRACE';
export const RECEIVE_TRACE_SUCCESS = 'RECEIVE_TRACE_SUCCESS'; export const RECEIVE_TRACE_SUCCESS = 'RECEIVE_TRACE_SUCCESS';
export const RECEIVE_TRACE_ERROR = 'RECEIVE_TRACE_ERROR'; export const RECEIVE_TRACE_ERROR = 'RECEIVE_TRACE_ERROR';
......
...@@ -53,17 +53,14 @@ export default { ...@@ -53,17 +53,14 @@ export default {
state.isTraceComplete = log.complete || state.isTraceComplete; state.isTraceComplete = log.complete || state.isTraceComplete;
}, },
/** [types.SET_TRACE_TIMEOUT](state, id) {
* Will remove loading animation state.traceTimeout = id;
*/
[types.STOP_POLLING_TRACE](state) {
state.isTraceComplete = true;
}, },
/** /**
* Will remove loading animation * Will remove loading animation
*/ */
[types.RECEIVE_TRACE_ERROR](state) { [types.STOP_POLLING_TRACE](state) {
state.isTraceComplete = true; state.isTraceComplete = true;
}, },
......
...@@ -22,6 +22,7 @@ export default () => ({ ...@@ -22,6 +22,7 @@ export default () => ({
isTraceComplete: false, isTraceComplete: false,
traceSize: 0, traceSize: 0,
isTraceSizeVisible: false, isTraceSizeVisible: false,
traceTimeout: 0,
// used as a query parameter to fetch the trace // used as a query parameter to fetch the trace
traceState: null, traceState: null,
......
...@@ -157,17 +157,21 @@ describe('Jobs Store Mutations', () => { ...@@ -157,17 +157,21 @@ describe('Jobs Store Mutations', () => {
}); });
}); });
describe('STOP_POLLING_TRACE', () => { describe('SET_TRACE_TIMEOUT', () => {
it('sets isTraceComplete to true', () => { it('sets the traceTimeout id', () => {
mutations[types.STOP_POLLING_TRACE](stateCopy); const id = 7;
expect(stateCopy.isTraceComplete).toEqual(true); expect(stateCopy.traceTimeout).not.toEqual(id);
mutations[types.SET_TRACE_TIMEOUT](stateCopy, id);
expect(stateCopy.traceTimeout).toEqual(id);
}); });
}); });
describe('RECEIVE_TRACE_ERROR', () => { describe('STOP_POLLING_TRACE', () => {
it('resets trace state and sets error to true', () => { it('sets isTraceComplete to true', () => {
mutations[types.RECEIVE_TRACE_ERROR](stateCopy); mutations[types.STOP_POLLING_TRACE](stateCopy);
expect(stateCopy.isTraceComplete).toEqual(true); expect(stateCopy.isTraceComplete).toEqual(true);
}); });
......
...@@ -46,9 +46,10 @@ describe('Job App ', () => { ...@@ -46,9 +46,10 @@ describe('Job App ', () => {
}); });
afterEach(() => { afterEach(() => {
resetStore(store);
vm.$destroy(); vm.$destroy();
mock.restore(); mock.restore();
resetStore(store);
}); });
describe('while loading', () => { describe('while loading', () => {
...@@ -384,7 +385,6 @@ describe('Job App ', () => { ...@@ -384,7 +385,6 @@ describe('Job App ', () => {
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
done();
}); });
it('displays remaining time for a delayed job', done => { it('displays remaining time for a delayed job', done => {
......
...@@ -15,6 +15,7 @@ import { ...@@ -15,6 +15,7 @@ import {
scrollBottom, scrollBottom,
requestTrace, requestTrace,
fetchTrace, fetchTrace,
startPollingTrace,
stopPollingTrace, stopPollingTrace,
receiveTraceSuccess, receiveTraceSuccess,
receiveTraceError, receiveTraceError,
...@@ -241,6 +242,50 @@ describe('Job State actions', () => { ...@@ -241,6 +242,50 @@ describe('Job State actions', () => {
done, done,
); );
}); });
describe('when job is incomplete', () => {
let tracePayload;
beforeEach(() => {
tracePayload = {
html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
complete: false,
};
mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(200, tracePayload);
});
it('dispatches startPollingTrace', done => {
testAction(
fetchTrace,
null,
mockedState,
[],
[
{ type: 'toggleScrollisInBottom', payload: true },
{ type: 'receiveTraceSuccess', payload: tracePayload },
{ type: 'startPollingTrace' },
],
done,
);
});
it('does not dispatch startPollingTrace when timeout is non-empty', done => {
mockedState.traceTimeout = 1;
testAction(
fetchTrace,
null,
mockedState,
[],
[
{ type: 'toggleScrollisInBottom', payload: true },
{ type: 'receiveTraceSuccess', payload: tracePayload },
],
done,
);
});
});
}); });
describe('error', () => { describe('error', () => {
...@@ -265,16 +310,69 @@ describe('Job State actions', () => { ...@@ -265,16 +310,69 @@ describe('Job State actions', () => {
}); });
}); });
describe('startPollingTrace', () => {
let dispatch;
let commit;
beforeEach(() => {
jasmine.clock().install();
dispatch = jasmine.createSpy();
commit = jasmine.createSpy();
startPollingTrace({ dispatch, commit });
});
afterEach(() => {
jasmine.clock().uninstall();
});
it('should save the timeout id but not call fetchTrace', () => {
expect(commit).toHaveBeenCalledWith(types.SET_TRACE_TIMEOUT, 1);
expect(dispatch).not.toHaveBeenCalledWith('fetchTrace');
});
describe('after timeout has passed', () => {
beforeEach(() => {
jasmine.clock().tick(4000);
});
it('should clear the timeout id and fetchTrace', () => {
expect(commit).toHaveBeenCalledWith(types.SET_TRACE_TIMEOUT, 0);
expect(dispatch).toHaveBeenCalledWith('fetchTrace');
});
});
});
describe('stopPollingTrace', () => { describe('stopPollingTrace', () => {
let origTimeout;
beforeEach(() => {
// Can't use spyOn(window, 'clearTimeout') because this caused unrelated specs to timeout
// https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23838#note_280277727
origTimeout = window.clearTimeout;
window.clearTimeout = jasmine.createSpy();
});
afterEach(() => {
window.clearTimeout = origTimeout;
});
it('should commit STOP_POLLING_TRACE mutation ', done => { it('should commit STOP_POLLING_TRACE mutation ', done => {
const traceTimeout = 7;
testAction( testAction(
stopPollingTrace, stopPollingTrace,
null, null,
mockedState, { ...mockedState, traceTimeout },
[{ type: types.STOP_POLLING_TRACE }], [{ type: types.SET_TRACE_TIMEOUT, payload: 0 }, { type: types.STOP_POLLING_TRACE }],
[], [],
done, )
); .then(() => {
expect(window.clearTimeout).toHaveBeenCalledWith(traceTimeout);
})
.then(done)
.catch(done.fail);
}); });
}); });
...@@ -292,15 +390,8 @@ describe('Job State actions', () => { ...@@ -292,15 +390,8 @@ describe('Job State actions', () => {
}); });
describe('receiveTraceError', () => { describe('receiveTraceError', () => {
it('should commit RECEIVE_TRACE_ERROR mutation ', done => { it('should commit stop polling trace', done => {
testAction( testAction(receiveTraceError, null, mockedState, [], [{ type: 'stopPollingTrace' }], done);
receiveTraceError,
null,
mockedState,
[{ type: types.RECEIVE_TRACE_ERROR }],
[],
done,
);
}); });
}); });
......
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