diff options
Diffstat (limited to 'spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js')
-rw-r--r-- | spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js b/spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js new file mode 100644 index 00000000000..8eb1ffb3cd0 --- /dev/null +++ b/spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js @@ -0,0 +1,213 @@ +import { createMockClient } from 'mock-apollo-client'; +import { InMemoryCache } from 'apollo-cache-inmemory'; +import waitForPromises from 'helpers/wait_for_promises'; + +import createFlash from '~/flash'; +import { StatusPoller } from '~/import_entities/import_groups/graphql/services/status_poller'; +import bulkImportSourceGroupsQuery from '~/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql'; +import { STATUSES } from '~/import_entities/constants'; +import { SourceGroupsManager } from '~/import_entities/import_groups/graphql/services/source_groups_manager'; +import { generateFakeEntry } from '../fixtures'; + +jest.mock('~/flash'); +jest.mock('~/import_entities/import_groups/graphql/services/source_groups_manager', () => ({ + SourceGroupsManager: jest.fn().mockImplementation(function mock() { + this.setImportStatus = jest.fn(); + }), +})); + +const TEST_POLL_INTERVAL = 1000; + +describe('Bulk import status poller', () => { + let poller; + let clientMock; + + const listQueryCacheCalls = () => + clientMock.readQuery.mock.calls.filter(call => call[0].query === bulkImportSourceGroupsQuery); + + beforeEach(() => { + clientMock = createMockClient({ + cache: new InMemoryCache({ + fragmentMatcher: { match: () => true }, + }), + }); + + jest.spyOn(clientMock, 'readQuery'); + + poller = new StatusPoller({ + client: clientMock, + interval: TEST_POLL_INTERVAL, + }); + }); + + describe('general behavior', () => { + beforeEach(() => { + clientMock.cache.writeQuery({ + query: bulkImportSourceGroupsQuery, + data: { bulkImportSourceGroups: [] }, + }); + }); + + it('does not perform polling when constructed', () => { + jest.runOnlyPendingTimers(); + expect(listQueryCacheCalls()).toHaveLength(0); + }); + + it('immediately start polling when requested', async () => { + await poller.startPolling(); + expect(listQueryCacheCalls()).toHaveLength(1); + }); + + it('constantly polls when started', async () => { + poller.startPolling(); + expect(listQueryCacheCalls()).toHaveLength(1); + + jest.advanceTimersByTime(TEST_POLL_INTERVAL); + expect(listQueryCacheCalls()).toHaveLength(2); + + jest.advanceTimersByTime(TEST_POLL_INTERVAL); + expect(listQueryCacheCalls()).toHaveLength(3); + }); + + it('does not start polling when requested multiple times', async () => { + poller.startPolling(); + expect(listQueryCacheCalls()).toHaveLength(1); + + poller.startPolling(); + expect(listQueryCacheCalls()).toHaveLength(1); + }); + + it('stops polling when requested', async () => { + poller.startPolling(); + expect(listQueryCacheCalls()).toHaveLength(1); + + poller.stopPolling(); + jest.runOnlyPendingTimers(); + expect(listQueryCacheCalls()).toHaveLength(1); + }); + + it('does not query server when list is empty', async () => { + jest.spyOn(clientMock, 'query'); + poller.startPolling(); + expect(clientMock.query).not.toHaveBeenCalled(); + }); + }); + + it('does not query server when no groups have STARTED status', async () => { + clientMock.cache.writeQuery({ + query: bulkImportSourceGroupsQuery, + data: { + bulkImportSourceGroups: [STATUSES.NONE, STATUSES.FINISHED].map((status, idx) => + generateFakeEntry({ status, id: idx }), + ), + }, + }); + + jest.spyOn(clientMock, 'query'); + poller.startPolling(); + expect(clientMock.query).not.toHaveBeenCalled(); + }); + + describe('when there are groups which have STARTED status', () => { + const TARGET_NAMESPACE = 'root'; + + const STARTED_GROUP_1 = { + status: STATUSES.STARTED, + id: 'started1', + import_target: { + target_namespace: TARGET_NAMESPACE, + new_name: 'group1', + }, + }; + + const STARTED_GROUP_2 = { + status: STATUSES.STARTED, + id: 'started2', + import_target: { + target_namespace: TARGET_NAMESPACE, + new_name: 'group2', + }, + }; + + const NOT_STARTED_GROUP = { + status: STATUSES.NONE, + id: 'not_started', + import_target: { + target_namespace: TARGET_NAMESPACE, + new_name: 'group3', + }, + }; + + it('query server only for groups with STATUSES.STARTED', async () => { + clientMock.cache.writeQuery({ + query: bulkImportSourceGroupsQuery, + data: { + bulkImportSourceGroups: [STARTED_GROUP_1, NOT_STARTED_GROUP, STARTED_GROUP_2].map(group => + generateFakeEntry(group), + ), + }, + }); + + clientMock.query = jest.fn().mockResolvedValue({ data: {} }); + poller.startPolling(); + + expect(clientMock.query).toHaveBeenCalledTimes(1); + await waitForPromises(); + const [[doc]] = clientMock.query.mock.calls; + const { selections } = doc.query.definitions[0].selectionSet; + expect(selections.every(field => field.name.value === 'group')).toBeTruthy(); + expect(selections).toHaveLength(2); + expect(selections.map(sel => sel.arguments[0].value.value)).toStrictEqual([ + `${TARGET_NAMESPACE}/${STARTED_GROUP_1.import_target.new_name}`, + `${TARGET_NAMESPACE}/${STARTED_GROUP_2.import_target.new_name}`, + ]); + }); + + it('updates statuses only for groups in response', async () => { + clientMock.cache.writeQuery({ + query: bulkImportSourceGroupsQuery, + data: { + bulkImportSourceGroups: [STARTED_GROUP_1, STARTED_GROUP_2].map(group => + generateFakeEntry(group), + ), + }, + }); + + clientMock.query = jest.fn().mockResolvedValue({ data: { group0: {} } }); + poller.startPolling(); + await waitForPromises(); + const [managerInstance] = SourceGroupsManager.mock.instances; + expect(managerInstance.setImportStatus).toHaveBeenCalledTimes(1); + expect(managerInstance.setImportStatus).toHaveBeenCalledWith( + expect.objectContaining({ id: STARTED_GROUP_1.id }), + STATUSES.FINISHED, + ); + }); + + describe('when error occurs', () => { + beforeEach(() => { + clientMock.cache.writeQuery({ + query: bulkImportSourceGroupsQuery, + data: { + bulkImportSourceGroups: [STARTED_GROUP_1, STARTED_GROUP_2].map(group => + generateFakeEntry(group), + ), + }, + }); + + clientMock.query = jest.fn().mockRejectedValue(new Error('dummy error')); + poller.startPolling(); + return waitForPromises(); + }); + + it('reports an error', () => { + expect(createFlash).toHaveBeenCalled(); + }); + + it('continues polling', async () => { + jest.advanceTimersByTime(TEST_POLL_INTERVAL); + expect(listQueryCacheCalls()).toHaveLength(2); + }); + }); + }); +}); |