Merge branch '21891-output-copying-performance'
[arvados.git] / services / workbench2 / src / components / subprocess-progress-bar / subprocess-progress-bar.test.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from "react";
6 import { configure, mount } from "enzyme";
7 import { ServiceRepository, createServices } from "services/services";
8 import { configureStore } from "store/store";
9 import { createBrowserHistory } from "history";
10 import { mockConfig } from 'common/config';
11 import { ApiActions } from "services/api/api-actions";
12 import Axios from "axios";
13 import MockAdapter from "axios-mock-adapter";
14 import { Process } from "store/processes/process";
15 import { ContainerState } from "models/container";
16 import Adapter from "enzyme-adapter-react-16";
17 import { SubprocessProgressBar } from "./subprocess-progress-bar";
18 import { Provider } from "react-redux";
19 import { FilterBuilder } from 'services/api/filter-builder';
20 import { ProcessStatusFilter, buildProcessStatusFilters } from 'store/resource-type-filters/resource-type-filters';
21 import {act} from "react-dom/test-utils";
22 import { updateResources } from 'store/resources/resources-actions';
23
24 configure({ adapter: new Adapter() });
25
26 describe("<SubprocessProgressBar />", () => {
27     const axiosInst = Axios.create({ headers: {} });
28     const axiosMock = new MockAdapter(axiosInst);
29
30     let store;
31     let services: ServiceRepository;
32     const config: any = {};
33     const actions: ApiActions = {
34         progressFn: (id: string, working: boolean) => { },
35         errorFn: (id: string, message: string) => { }
36     };
37     let statusResponse = {
38         [ProcessStatusFilter.COMPLETED]: 0,
39         [ProcessStatusFilter.RUNNING]: 0,
40         [ProcessStatusFilter.FAILED]: 0,
41         [ProcessStatusFilter.QUEUED]: 0,
42     };
43
44     const createMockListFunc = (uuid: string) => jest.fn(async (args) => {
45         const baseFilter = new FilterBuilder().addEqual('requesting_container_uuid', uuid).getFilters();
46
47         const filterResponses = Object.keys(statusResponse)
48             .map(status => ({filters: buildProcessStatusFilters(new FilterBuilder(baseFilter), status).getFilters(), value: statusResponse[status]}));
49
50         const matchedFilter = filterResponses.find(response => response.filters === args.filters);
51         if (matchedFilter) {
52             return { itemsAvailable: matchedFilter.value };
53         } else {
54             return { itemsAvailable: 0 };
55         }
56     });
57
58     beforeEach(() => {
59         services = createServices(mockConfig({}), actions, axiosInst);
60         store = configureStore(createBrowserHistory(), services, config);
61     });
62
63     it("requests subprocess progress stats for stopped processes and displays progress", async () => {
64         // when
65         const containerRequest = {
66             uuid: 'zzzzz-xvhdp-000000000000000',
67             containerUuid: 'zzzzz-dz642-000000000000000',
68         };
69         const process = {
70             container: {
71                 state: ContainerState.COMPLETE,
72             },
73             containerRequest: containerRequest,
74         } as Process;
75         await store.dispatch(updateResources([containerRequest, process]));
76
77         statusResponse = {
78             [ProcessStatusFilter.COMPLETED]: 100,
79             [ProcessStatusFilter.RUNNING]: 200,
80
81             // Combined into failed segment
82             [ProcessStatusFilter.FAILED]: 200,
83             [ProcessStatusFilter.CANCELLED]: 100,
84
85             // Combined into queued segment
86             [ProcessStatusFilter.QUEUED]: 300,
87             [ProcessStatusFilter.ONHOLD]: 100,
88         };
89
90         services.containerRequestService.list = createMockListFunc(process.containerRequest.containerUuid);
91
92         let progressBar;
93         await act(async () => {
94             progressBar = mount(
95                 <Provider store={store}>
96                     <SubprocessProgressBar parentResource={process} />
97                 </Provider>);
98         });
99         await progressBar.update();
100
101         // expects 6 subprocess status list requests
102         const expectedFilters = [
103             ProcessStatusFilter.COMPLETED,
104             ProcessStatusFilter.RUNNING,
105             ProcessStatusFilter.FAILED,
106             ProcessStatusFilter.CANCELLED,
107             ProcessStatusFilter.QUEUED,
108             ProcessStatusFilter.ONHOLD,
109         ].map((state) =>
110             buildProcessStatusFilters(
111                 new FilterBuilder().addEqual(
112                     "requesting_container_uuid",
113                     process.containerRequest.containerUuid
114                 ),
115                 state
116             ).getFilters()
117         );
118
119         expectedFilters.forEach((filter) => {
120             expect(services.containerRequestService.list).toHaveBeenCalledWith({limit: 0, offset: 0, filters: filter});
121         });
122
123         // Verify progress bar with correct degment widths
124         ['10%', '20%', '30%', '40%'].forEach((value, i) => {
125             const styles = progressBar.find('.progress').at(i).props().style;
126             expect(styles).toHaveProperty('width', value);
127         });
128     });
129
130     it("dislays correct progress bar widths with different values", async () => {
131         const containerRequest = {
132             uuid: 'zzzzz-xvhdp-000000000000001',
133             containerUuid: 'zzzzz-dz642-000000000000001',
134         };
135         const process = {
136             container: {
137                 state: ContainerState.COMPLETE,
138             },
139             containerRequest: containerRequest,
140         } as Process;
141         await store.dispatch(updateResources([containerRequest, process]));
142
143         statusResponse = {
144             [ProcessStatusFilter.COMPLETED]: 50,
145             [ProcessStatusFilter.RUNNING]: 55,
146
147             [ProcessStatusFilter.FAILED]: 30,
148             [ProcessStatusFilter.CANCELLED]: 30,
149
150             [ProcessStatusFilter.QUEUED]: 235,
151             [ProcessStatusFilter.ONHOLD]: 100,
152         };
153
154         services.containerRequestService.list = createMockListFunc(process.containerRequest.containerUuid);
155
156         let progressBar;
157         await act(async () => {
158             progressBar = mount(
159                 <Provider store={store}>
160                     <SubprocessProgressBar parentResource={process} />
161                 </Provider>);
162         });
163         await progressBar.update();
164
165         // Verify progress bar with correct degment widths
166         ['10%', '11%', '12%', '67%'].forEach((value, i) => {
167             const styles = progressBar.find('.progress').at(i).props().style;
168             expect(styles).toHaveProperty('width', value);
169         });
170     });
171
172 });