katello 3.15.0.rc1.3 → 3.15.0.rc2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of katello might be problematic. Click here for more details.

Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/api_controller.rb +5 -0
  3. data/app/controllers/katello/api/v2/host_packages_controller.rb +1 -0
  4. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +1 -1
  5. data/app/lib/actions/katello/content_view/destroy.rb +1 -0
  6. data/app/lib/actions/katello/host/erratum/applicable_errata_install.rb +1 -1
  7. data/app/lib/actions/pulp3/content_view/delete_repository_references.rb +26 -0
  8. data/app/lib/actions/pulp3/orchestration/repository/delete.rb +8 -1
  9. data/app/lib/actions/pulp3/repository/delete_version.rb +20 -0
  10. data/app/lib/katello/concerns/base_template_scope_extensions.rb +23 -1
  11. data/app/lib/katello/errors.rb +2 -0
  12. data/app/models/katello/repository.rb +44 -9
  13. data/app/models/setting/content.rb +8 -2
  14. data/app/services/katello/pulp3/migration.rb +19 -4
  15. data/app/services/katello/pulp3/repository.rb +4 -0
  16. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-details.controller.js +13 -0
  17. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-subscriptions.controller.js +4 -2
  18. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-subscriptions.html +11 -8
  19. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/katello-agent-notice.html +8 -0
  20. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-errata-modal.html +2 -0
  21. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-packages-modal.html +2 -0
  22. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-errata.html +2 -0
  23. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-actions.html +1 -0
  24. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-applicable.html +2 -1
  25. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-installed.html +4 -2
  26. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details.controller.js +10 -1
  27. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +6 -3
  28. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-subscriptions.html +4 -2
  29. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-client.html +9 -1
  30. data/lib/katello/tasks/pulp3_content_switchover.rake +2 -1
  31. data/lib/katello/version.rb +1 -1
  32. data/webpack/__mocks__/foremanReact/redux/API.js +6 -0
  33. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors.js +6 -0
  34. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/index.js +11 -0
  35. data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryReducer.js +0 -12
  36. data/webpack/scenes/Subscriptions/Manifest/index.js +0 -1
  37. data/webpack/scenes/Subscriptions/SubscriptionActions.js +49 -10
  38. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +10 -5
  39. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +37 -43
  40. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +55 -131
  41. data/webpack/scenes/Subscriptions/SubscriptionsSelectors.js +2 -5
  42. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +1 -1
  43. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsActions.test.js +75 -8
  44. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +35 -8
  45. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsReducer.test.js +58 -46
  46. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsSelectors.test.js +3 -5
  47. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +85 -9
  48. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +0 -2
  49. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +111 -124
  50. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsSelectors.test.js.snap +2 -12
  51. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +2 -8
  52. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +1 -16
  53. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +1 -6
  54. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/UpdateDialog.js +0 -25
  55. data/webpack/scenes/Subscriptions/index.js +2 -5
  56. data/webpack/scenes/Tasks/TaskActions.js +34 -104
  57. data/webpack/scenes/Tasks/TaskSelectors.js +7 -0
  58. data/webpack/scenes/Tasks/__tests__/TaskActions.test.js +17 -154
  59. data/webpack/scenes/Tasks/__tests__/TaskSelectors.test.js +21 -0
  60. data/webpack/scenes/Tasks/__tests__/__snapshots__/TaskActions.test.js.snap +57 -0
  61. data/webpack/scenes/Tasks/__tests__/__snapshots__/TaskSelectors.test.js.snap +9 -0
  62. data/webpack/scenes/Tasks/__tests__/task.fixtures.js +0 -82
  63. data/webpack/scenes/Tasks/helpers.js +13 -6
  64. metadata +12 -3
  65. data/webpack/scenes/Tasks/TaskConstants.js +0 -9
@@ -6,24 +6,14 @@ exports[`Subscriptions selectors should select delete-modal-opened 1`] = `false`
6
6
 
7
7
  exports[`Subscriptions selectors should select search-query 1`] = `"some-query"`;
8
8
 
9
- exports[`Subscriptions selectors should select subscriptions tasks 1`] = `
10
- Array [
11
- "task1",
12
- "task2",
13
- ]
14
- `;
15
-
16
- exports[`Subscriptions selectors should select task-modal-opened 1`] = `false`;
9
+ exports[`Subscriptions selectors should select subscriptions task 1`] = `Object {}`;
17
10
 
18
11
  exports[`Subscriptions selectors should select the subscriptions state 1`] = `
19
12
  Object {
20
13
  "deleteButtonDisabled": true,
21
14
  "deleteModalOpened": false,
22
15
  "searchQuery": "some-query",
16
+ "task": Object {},
23
17
  "taskModalOpened": false,
24
- "tasks": Array [
25
- "task1",
26
- "task2",
27
- ],
28
18
  }
29
19
  `;
@@ -11,7 +11,7 @@ export const initialState = Immutable({
11
11
  itemCount: 0,
12
12
  quantitiesLoading: false,
13
13
  availableQuantities: null,
14
- tasks: [],
14
+ task: undefined,
15
15
  tableColumns: [],
16
16
  selectedTableColumns: [],
17
17
  });
@@ -248,7 +248,6 @@ export const groupedSubscriptions = Immutable({
248
248
  itemCount: 81,
249
249
  quantitiesLoading: false,
250
250
  availableQuantities: null,
251
- tasks: [],
252
251
  tableColumns: [],
253
252
  selectedTableColumns: [],
254
253
  });
@@ -318,7 +317,6 @@ export const successState = Immutable({
318
317
  itemCount: 81,
319
318
  quantitiesLoading: false,
320
319
  availableQuantities: null,
321
- tasks: [],
322
320
  tableColumns: [],
323
321
  selectedTableColumns: [],
324
322
  });
@@ -335,7 +333,6 @@ export const permissionDeniedState = Immutable({
335
333
  itemCount: 0,
336
334
  quantitiesLoading: false,
337
335
  availableQuantities: null,
338
- tasks: [],
339
336
  tableColumns: [],
340
337
  selectedTableColumns: [],
341
338
  });
@@ -366,7 +363,6 @@ export const errorState = Immutable({
366
363
  results: [],
367
364
  quantitiesLoading: false,
368
365
  availableQuantities: null,
369
- tasks: [],
370
366
  tableColumns: [],
371
367
  selectedTableColumns: [],
372
368
  });
@@ -436,18 +432,16 @@ export const poolsUpdate = [{
436
432
  export const updateQuantitySuccessActions = [
437
433
  {
438
434
  type: 'UPDATE_QUANTITY_REQUEST',
439
- quantities: poolsUpdate,
440
435
  },
441
436
  {
442
- response: requestSuccessResponse,
443
437
  type: 'UPDATE_QUANTITY_SUCCESS',
438
+ response: requestSuccessResponse,
444
439
  },
445
440
  ];
446
441
 
447
442
  export const updateQuantityFailureActions = [
448
443
  {
449
444
  type: 'UPDATE_QUANTITY_REQUEST',
450
- quantities: poolsUpdate,
451
445
  },
452
446
  failureAction('UPDATE_QUANTITY_FAILURE'),
453
447
  toastErrorAction(),
@@ -128,16 +128,12 @@ class SubscriptionsTable extends Component {
128
128
  getUpdateDialogProps = () => {
129
129
  const { showUpdateConfirmDialog: show, updatedQuantity } = this.state;
130
130
  const {
131
- updateQuantity, bulkSearch, organization, task,
131
+ updateQuantity,
132
132
  } = this.props;
133
133
  return {
134
- bulkSearch,
135
- organization,
136
134
  show,
137
- task,
138
135
  updatedQuantity,
139
136
  updateQuantity,
140
- confirmEdit: this.confirmEdit,
141
137
  enableEditing: this.enableEditing,
142
138
  showUpdateConfirm: this.showUpdateConfirm,
143
139
  };
@@ -198,7 +194,6 @@ class SubscriptionsTable extends Component {
198
194
 
199
195
  groupedSubscriptions[groupId].open = !open;
200
196
 
201
-
202
197
  const rows = buildTableRows(
203
198
  groupedSubscriptions,
204
199
  subscriptions.availableQuantities,
@@ -287,21 +282,11 @@ SubscriptionsTable.propTypes = {
287
282
  onDeleteSubscriptions: PropTypes.func.isRequired,
288
283
  onSubscriptionDeleteModalClose: PropTypes.func.isRequired,
289
284
  toggleDeleteButton: PropTypes.func.isRequired,
290
- task: PropTypes.shape({}),
291
- bulkSearch: PropTypes.func,
292
- organization: PropTypes.shape({
293
- owner_details: PropTypes.shape({
294
- displayName: PropTypes.string,
295
- }),
296
- }),
297
285
  selectedRows: PropTypes.instanceOf(Array).isRequired,
298
286
  onSelectedRowsChange: PropTypes.func.isRequired,
299
287
  };
300
288
 
301
289
  SubscriptionsTable.defaultProps = {
302
- task: { humanized: {} },
303
- bulkSearch: undefined,
304
- organization: undefined,
305
290
  canManageSubscriptionAllocations: false,
306
291
  };
307
292
 
@@ -23,7 +23,7 @@ exports[`subscriptions table should render a loading state 1`] = `
23
23
  "results": Array [],
24
24
  "selectedTableColumns": Array [],
25
25
  "tableColumns": Array [],
26
- "tasks": Array [],
26
+ "task": undefined,
27
27
  }
28
28
  }
29
29
  tableColumns={
@@ -35,11 +35,6 @@ exports[`subscriptions table should render a loading state 1`] = `
35
35
  "end_date",
36
36
  ]
37
37
  }
38
- task={
39
- Object {
40
- "humanized": Object {},
41
- }
42
- }
43
38
  toggleDeleteButton={[Function]}
44
39
  updateQuantity={[Function]}
45
40
  >
@@ -3,17 +3,12 @@ import PropTypes from 'prop-types';
3
3
  import { sprintf, translate as __ } from 'foremanReact/common/I18n';
4
4
  import { MessageDialog } from 'patternfly-react';
5
5
  import { buildPools } from '../../SubscriptionsTableHelpers';
6
- import { renderTaskStartedToast } from '../../../../../Tasks/helpers';
7
- import { BLOCKING_FOREMAN_TASK_TYPES } from '../../../../SubscriptionConstants';
8
6
 
9
7
  const UpdateDialog = ({
10
8
  show,
11
9
  updatedQuantity,
12
10
  updateQuantity,
13
11
  showUpdateConfirm,
14
- bulkSearch,
15
- organization,
16
- task,
17
12
  enableEditing,
18
13
  }) => {
19
14
  const quantityLength = Object.keys(updatedQuantity).length;
@@ -21,12 +16,6 @@ const UpdateDialog = ({
21
16
  showUpdateConfirm(false);
22
17
  if (quantityLength > 0) {
23
18
  await updateQuantity(buildPools(updatedQuantity));
24
- await bulkSearch({
25
- action: `organization '${organization.owner_details.displayName}'`,
26
- result: 'pending',
27
- label: BLOCKING_FOREMAN_TASK_TYPES.join(' or '),
28
- });
29
- renderTaskStartedToast(task);
30
19
  }
31
20
  enableEditing(false);
32
21
  };
@@ -60,21 +49,7 @@ UpdateDialog.propTypes = {
60
49
  updateQuantity: PropTypes.func.isRequired,
61
50
  updatedQuantity: PropTypes.shape(PropTypes.Object).isRequired,
62
51
  showUpdateConfirm: PropTypes.func.isRequired,
63
- bulkSearch: PropTypes.func,
64
- organization: PropTypes.shape({
65
- owner_details: PropTypes.shape({
66
- displayName: PropTypes.string,
67
- }),
68
- }),
69
- task: PropTypes.shape({}),
70
52
  enableEditing: PropTypes.func.isRequired,
71
53
  };
72
54
 
73
- UpdateDialog.defaultProps = {
74
- task: { humanized: {} },
75
- bulkSearch: undefined,
76
- organization: undefined,
77
- };
78
-
79
-
80
55
  export default UpdateDialog;
@@ -11,9 +11,8 @@ import {
11
11
  selectSubscriptionsState,
12
12
  selectSearchQuery,
13
13
  selectDeleteModalOpened,
14
- selectTaskModalOpened,
15
14
  selectDeleteButtonDisabled,
16
- selectSubscriptionsTasks,
15
+ selectSubscriptionsTask,
17
16
  selectActivePermissions,
18
17
  selectTableSettings,
19
18
  } from './SubscriptionsSelectors';
@@ -33,13 +32,11 @@ const mapStateToProps = (state) => {
33
32
  subscriptionTableSettings,
34
33
  activePermissions: selectActivePermissions(state),
35
34
  simpleContentAccess: selectSimpleContentAccessEnabled(state),
36
- tasks: selectSubscriptionsTasks(state),
35
+ task: selectSubscriptionsTask(state),
37
36
  searchQuery: selectSearchQuery(state),
38
37
  deleteModalOpened: selectDeleteModalOpened(state),
39
- taskModalOpened: selectTaskModalOpened(state),
40
38
  deleteButtonDisabled: selectDeleteButtonDisabled(state),
41
39
  organization: state.katello.organization,
42
- taskDetails: state.katello.manifestHistory.taskDetails,
43
40
  };
44
41
  };
45
42
 
@@ -1,111 +1,41 @@
1
+ import { addToast } from 'foremanReact/redux/actions/toasts';
1
2
  import { propsToSnakeCase } from 'foremanReact/common/helpers';
3
+ import { get } from 'foremanReact/redux/API';
4
+ import { stopInterval, withInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
5
+ import { foremanTasksApi } from '../../services/api';
6
+ import { bulkSearchKey, pollTaskKey, taskFinishedToast } from './helpers';
7
+
8
+ export const toastTaskFinished = task => async dispatch =>
9
+ dispatch(addToast(taskFinishedToast(task)));
10
+
11
+ const taskBulkSearchParams = params => ({
12
+ search: Object.entries(propsToSnakeCase(params))
13
+ .map((item) => {
14
+ if (item[0] === 'action') {
15
+ return `${item[0]}~${item[1]}`;
16
+ }
17
+ return `${item[0]}=${item[1]}`;
18
+ })
19
+ .join(' and '),
20
+ });
2
21
 
3
- import { foremanTasksApi as api } from '../../services/api';
4
- import {
5
- GET_TASK_REQUEST,
6
- GET_TASK_SUCCESS,
7
- GET_TASK_FAILURE,
8
- TASK_BULK_SEARCH_REQUEST,
9
- TASK_BULK_SEARCH_SUCCESS,
10
- TASK_BULK_SEARCH_FAILURE,
11
- RESET_TASKS,
12
- } from './TaskConstants';
13
-
14
- export const bulkSearch = (extendedParams = {}) => async (dispatch) => {
15
- const params = {
16
- search: Object.entries(propsToSnakeCase(extendedParams))
17
- .map((item) => {
18
- if (item[0] === 'action') {
19
- return `${item[0]}~${item[1]}`;
20
- }
21
- return `${item[0]}=${item[1]}`;
22
- })
23
- .join(' and '),
24
- };
25
-
26
- dispatch({ type: TASK_BULK_SEARCH_REQUEST });
27
-
28
- try {
29
- const { data } = await api.get('/tasks', {}, params);
30
- return dispatch({
31
- type: TASK_BULK_SEARCH_SUCCESS,
32
- response: data,
33
- });
34
- } catch (error) {
35
- return dispatch({
36
- type: TASK_BULK_SEARCH_FAILURE,
37
- result: error,
38
- });
39
- }
40
- };
41
-
42
- export const resetTasks = () => (dispatch) => {
43
- dispatch({
44
- type: RESET_TASKS,
45
- });
46
- };
47
-
48
- export const loadTask = (taskId, extendedParams = {}) => async (dispatch) => {
49
- dispatch({ type: GET_TASK_REQUEST });
50
-
51
- const params = {
52
- ...propsToSnakeCase(extendedParams),
53
- };
54
-
55
- try {
56
- const { data } = await api.get(`/tasks/${taskId}`, {}, params);
57
- return dispatch({
58
- type: GET_TASK_SUCCESS,
59
- response: data,
60
- });
61
- } catch (error) {
62
- return dispatch({
63
- type: GET_TASK_FAILURE,
64
- result: error,
65
- });
66
- }
67
- };
22
+ const getTasks = (key, params = {}) => get({
23
+ key,
24
+ url: `${foremanTasksApi.baseApiPath}/tasks`,
25
+ params: taskBulkSearchParams(params),
26
+ });
68
27
 
69
- const isUnauthorized = (action = {}) => (action.result
70
- && action.result
71
- && action.result.response
72
- && action.result.response.status === 401);
28
+ export const startPollingTasks = (key, taskSearchParams = {}) =>
29
+ withInterval(getTasks(bulkSearchKey(key), taskSearchParams));
73
30
 
31
+ export const stopPollingTasks = key => stopInterval(bulkSearchKey(key));
74
32
 
75
- export const pollBulkSearch = (extendedParams = {}, interval, orgId) =>
76
- async (dispatch, getState) => {
77
- const triggerPolling = (action) => {
78
- const { id } = getState().katello.organization;
79
- if (!isUnauthorized(action)) {
80
- if (id === orgId) {
81
- setTimeout(() => dispatch(pollBulkSearch(extendedParams, interval, orgId)), interval);
82
- }
83
- }
84
- };
85
- const { id, loading } = getState().katello.organization;
86
- if (id === orgId && !loading) {
87
- const dispatchedAction = await dispatch(await bulkSearch(extendedParams));
88
- triggerPolling(dispatchedAction);
89
- return dispatchedAction;
90
- }
33
+ const getTask = (key, task) => get({
34
+ key,
35
+ url: `${foremanTasksApi.baseApiPath}/tasks/${task.id}`,
36
+ });
91
37
 
92
- return dispatch({ type: 'POLLING_IS_SKIPPED' });
93
- };
38
+ export const startPollingTask = (key, task) =>
39
+ withInterval(getTask(pollTaskKey(key), task));
94
40
 
95
- export const pollTaskUntilDone = (taskId, extendedParams = {}, interval, orgId) =>
96
- (dispatch, getState) => new Promise((resolve, reject) => {
97
- const pollUntilDone = (action) => {
98
- const { id, loading } = getState().katello.organization;
99
-
100
- if (isUnauthorized(action) || id !== orgId || loading) {
101
- reject(action.result);
102
- } else if (action.response && action.response.pending) {
103
- // eslint-disable-next-line promise/prefer-await-to-then
104
- setTimeout(() => dispatch(loadTask(taskId, extendedParams)).then(pollUntilDone), interval);
105
- } else {
106
- resolve(action.response);
107
- }
108
- };
109
- // eslint-disable-next-line promise/prefer-await-to-then
110
- return dispatch(loadTask(taskId, extendedParams)).then(pollUntilDone);
111
- });
41
+ export const stopPollingTask = key => stopInterval(pollTaskKey(key));
@@ -0,0 +1,7 @@
1
+ import { selectDoesIntervalExist } from 'foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors';
2
+ import { bulkSearchKey, pollTaskKey } from './helpers';
3
+
4
+ export const selectIsPollingTask = (state, key) => selectDoesIntervalExist(state, pollTaskKey(key));
5
+
6
+ export const selectIsPollingTasks = (state, key) =>
7
+ selectDoesIntervalExist(state, bulkSearchKey(key));
@@ -1,155 +1,18 @@
1
- import axios from 'axios';
2
- import MockAdapter from 'axios-mock-adapter';
3
- import thunk from 'redux-thunk';
4
- import Immutable from 'seamless-immutable';
5
- import configureMockStore from 'redux-mock-store';
6
- import {
7
- bulkSearchSuccessResponse,
8
- bulkSearchSuccessActions,
9
- buildBulkSearchFailureActions,
10
- getTaskSuccessResponse,
11
- getTaskSuccessActions,
12
- buildTaskFailureActions,
13
- getTaskPendingResponse,
14
- getTaskPendingActions,
15
- } from './task.fixtures';
16
-
17
- import { bulkSearch, loadTask, pollTaskUntilDone, pollBulkSearch } from '../TaskActions';
18
-
19
- const mockStore = configureMockStore([thunk]);
20
- const store = mockStore({
21
- tasks: Immutable({}),
22
- katello: { organization: { id: 1, loading: false } },
23
- });
24
- const mockApi = new MockAdapter(axios);
25
-
26
- beforeEach(() => {
27
- store.clearActions();
28
- mockApi.reset();
29
- });
30
-
31
- let originalTimeout;
32
- let setTimeoutSpy;
33
-
34
- beforeEach(() => {
35
- setTimeoutSpy = jest.spyOn(window, 'setTimeout');
36
-
37
- originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
38
- jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
39
- });
40
-
41
- afterEach(() => {
42
- setTimeoutSpy.mockReset();
43
- setTimeoutSpy.mockRestore();
44
-
45
- jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
46
- });
47
-
48
- describe('task actions', () => {
49
- describe('creates TASK_BULK_SEARCH_REQUEST', () => {
50
- const url = '/foreman_tasks/api/tasks';
51
-
52
- it('and then fails with 422', async () => {
53
- mockApi.onGet(url).reply(422);
54
-
55
- await store.dispatch(bulkSearch());
56
- expect(store.getActions()).toEqual(buildBulkSearchFailureActions());
57
- });
58
-
59
- it('and ends with success', async () => {
60
- mockApi.onGet(url).reply(200, bulkSearchSuccessResponse);
61
-
62
- await store.dispatch(bulkSearch());
63
- expect(store.getActions()).toEqual(bulkSearchSuccessActions);
64
- });
65
- });
66
-
67
- describe('creates GET_TASK_REQUEST', () => {
68
- const taskId = 'eb1b6271-8a69-4d98-84fc-bea06ddcc166';
69
- const url = `/foreman_tasks/api/tasks/${taskId}`;
70
-
71
- it('and then fails with 422', async () => {
72
- mockApi.onGet(url).reply(422);
73
-
74
- await store.dispatch(loadTask(taskId));
75
- expect(store.getActions()).toEqual(buildTaskFailureActions());
76
- });
1
+ import { testActionSnapshotWithFixtures } from 'react-redux-test-utils';
2
+ import { getTaskSuccessResponse } from './task.fixtures';
77
3
 
78
- it('and ends with success', async () => {
79
- mockApi.onGet(url).reply(200, getTaskSuccessResponse);
80
-
81
- await store.dispatch(loadTask(taskId));
82
- expect(store.getActions()).toEqual(getTaskSuccessActions);
83
- });
84
- });
85
-
86
- describe('pollTaskUntilDone', () => {
87
- const taskId = 'eb1b6271-8a69-4d98-84fc-bea06ddcc166';
88
- const url = `/foreman_tasks/api/tasks/${taskId}`;
89
-
90
- it("doesn't start polling when the task has finished", async () => {
91
- mockApi.onGet(url).replyOnce(200, getTaskSuccessResponse);
92
-
93
- await store.dispatch(pollTaskUntilDone(taskId, {}, 1, 1));
94
- expect(store.getActions()).toEqual(getTaskSuccessActions);
95
- expect(setTimeoutSpy).toHaveBeenCalledTimes(0);
96
- });
97
-
98
- it('polls until a task is done', async () => {
99
- mockApi
100
- .onGet(url)
101
- .replyOnce(200, getTaskPendingResponse)
102
- .onGet(url)
103
- .replyOnce(200, getTaskPendingResponse)
104
- .onGet(url)
105
- .replyOnce(200, getTaskSuccessResponse);
106
-
107
- const expectedActions = getTaskPendingActions
108
- .concat(getTaskPendingActions)
109
- .concat(getTaskSuccessActions);
110
-
111
- await store.dispatch(pollTaskUntilDone(taskId, {}, 1, 1));
112
- expect(store.getActions()).toEqual(expectedActions);
113
- expect(setTimeoutSpy).toHaveBeenCalledTimes(2);
114
- });
115
-
116
- it('stops polling on unauthorized response', async () => {
117
- mockApi
118
- .onGet(url).replyOnce(200, getTaskPendingResponse)
119
- .onGet(url).replyOnce(401);
120
-
121
- const expectedActions = getTaskPendingActions
122
- .concat(buildTaskFailureActions(401));
123
-
124
- try {
125
- await store.dispatch(pollTaskUntilDone(taskId, {}, 1, 1));
126
- } catch (e) {
127
- expect(store.getActions()).toEqual(expectedActions);
128
- expect(setTimeoutSpy).toHaveBeenCalledTimes(1);
129
- }
130
- });
131
- });
132
-
133
- describe('pollBulkSearch', () => {
134
- const url = '/foreman_tasks/api/tasks';
135
-
136
- it('polls', async () => {
137
- mockApi
138
- .onGet(url)
139
- .replyOnce(200, bulkSearchSuccessResponse);
140
-
141
- await store.dispatch(pollBulkSearch({}, 1, 1));
142
- expect(setTimeoutSpy).toHaveBeenCalledTimes(1);
143
- expect(store.getActions()).toEqual(bulkSearchSuccessActions);
144
- });
145
-
146
- it('stops polling on unauthorized response', async () => {
147
- mockApi
148
- .onGet(url).replyOnce(401);
149
-
150
- await store.dispatch(pollBulkSearch({}, 1, 1));
151
- expect(store.getActions()).toEqual(buildBulkSearchFailureActions(401));
152
- expect(setTimeoutSpy).toHaveBeenCalledTimes(0);
153
- });
154
- });
155
- });
4
+ import {
5
+ startPollingTask,
6
+ stopPollingTask,
7
+ startPollingTasks,
8
+ stopPollingTasks,
9
+ toastTaskFinished,
10
+ } from '../TaskActions';
11
+
12
+ describe('task actions', () => testActionSnapshotWithFixtures({
13
+ 'can search tasks': () => startPollingTasks('TEST'),
14
+ 'can stop searching tasks': () => stopPollingTasks('TEST'),
15
+ 'can poll a task': () => startPollingTask('TEST', { id: '12345' }),
16
+ 'can stop polling a task': () => stopPollingTask('TEST'),
17
+ 'can toast a finished task': () => toastTaskFinished(getTaskSuccessResponse),
18
+ }));