1 import { HttpHeaders } from '@angular/common/http';
2 import { HttpClientTestingModule } from '@angular/common/http/testing';
3 import { ComponentFixture, TestBed } from '@angular/core/testing';
5 import _ from 'lodash';
6 import { NgxPipeFunctionModule } from 'ngx-pipe-function';
7 import { ToastrModule } from 'ngx-toastr';
8 import { of } from 'rxjs';
10 import { CephModule } from '~/app/ceph/ceph.module';
11 import { CoreModule } from '~/app/core/core.module';
12 import { CephServiceService } from '~/app/shared/api/ceph-service.service';
13 import { HostService } from '~/app/shared/api/host.service';
14 import { PaginateObservable } from '~/app/shared/api/paginate.model';
15 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
16 import { SharedModule } from '~/app/shared/shared.module';
17 import { configureTestBed } from '~/testing/unit-test-helper';
18 import { ServiceDaemonListComponent } from './service-daemon-list.component';
20 describe('ServiceDaemonListComponent', () => {
21 let component: ServiceDaemonListComponent;
22 let fixture: ComponentFixture<ServiceDaemonListComponent>;
23 let headers: HttpHeaders;
28 container_id: '003c10beafc8c27b635bcdfed1ed832e4c1005be89bb1bb05ad4cc6c2b98e41b',
29 container_image_id: 'e70344c77bcbf3ee389b9bf5128f635cf95f3d59e005c5d8e67fc19bcc74ed23',
30 container_image_name: 'docker.io/ceph/daemon-base:latest-master-devel',
34 version: '15.1.0-1174-g16a11f7',
36 cpu_percentage: '3.54%',
38 status_desc: 'running',
39 last_refresh: '2020-02-25T04:33:26.465699',
41 { created: '2020-02-24T04:33:26.465699' },
42 { created: '2020-02-25T04:33:26.465699' },
43 { created: '2020-02-26T04:33:26.465699' }
48 container_id: 'baeec41a01374b3ed41016d542d19aef4a70d69c27274f271e26381a0cc58e7a',
49 container_image_id: 'e70344c77bcbf3ee389b9bf5128f635cf95f3d59e005c5d8e67fc19bcc74ed23',
50 container_image_name: 'docker.io/ceph/daemon-base:latest-master-devel',
54 version: '15.1.0-1174-g16a11f7',
56 cpu_percentage: '3.54%',
58 status_desc: 'running',
59 last_refresh: '2020-02-25T04:33:26.465822',
64 container_id: '8483de277e365bea4365cee9e1f26606be85c471e4da5d51f57e4b85a42c616e',
65 container_image_id: 'e70344c77bcbf3ee389b9bf5128f635cf95f3d59e005c5d8e67fc19bcc74ed23',
66 container_image_name: 'docker.io/ceph/daemon-base:latest-master-devel',
70 version: '15.1.0-1174-g16a11f7',
72 cpu_percentage: '3.54%',
74 status_desc: 'running',
75 last_refresh: '2020-02-25T04:33:26.465886',
80 container_id: '6ca0574f47e300a6979eaf4e7c283a8c4325c2235ae60358482fc4cd58844a21',
81 container_image_id: 'e70344c77bcbf3ee389b9bf5128f635cf95f3d59e005c5d8e67fc19bcc74ed23',
82 container_image_name: 'docker.io/ceph/daemon-base:latest-master-devel',
86 version: '15.1.0-1174-g16a11f7',
88 cpu_percentage: '3.54%',
90 status_desc: 'running',
91 last_refresh: '2020-02-25T04:33:26.465886',
101 container_image_id: 'e70344c77bcbf3ee389b9bf5128f635cf95f3d59e005c5d8e67fc19bcc74ed23',
102 container_image_name: 'docker.io/ceph/daemon-base:latest-master-devel',
105 last_refresh: '2020-02-25T04:33:26.465699'
107 events: '2021-03-22T07:34:48.582163Z service:osd [INFO] "service was created"'
110 service_type: 'crash',
111 service_name: 'crash',
113 container_image_id: 'e70344c77bcbf3ee389b9bf5128f635cf95f3d59e005c5d8e67fc19bcc74ed23',
114 container_image_name: 'docker.io/ceph/daemon-base:latest-master-devel',
117 last_refresh: '2020-02-25T04:33:26.465766'
119 events: '2021-03-22T07:34:48.582163Z service:osd [INFO] "service was created"'
123 const context = new CdTableFetchDataContext(() => undefined);
125 const getDaemonsByHostname = (hostname?: string) => {
126 return hostname ? _.filter(daemons, { hostname: hostname }) : daemons;
129 const getDaemonsByServiceName = (serviceName?: string) => {
130 return serviceName ? _.filter(daemons, { daemon_type: serviceName }) : daemons;
135 HttpClientTestingModule,
138 NgxPipeFunctionModule,
140 ToastrModule.forRoot()
145 fixture = TestBed.createComponent(ServiceDaemonListComponent);
146 component = fixture.componentInstance;
147 const hostService = TestBed.inject(HostService);
148 const cephServiceService = TestBed.inject(CephServiceService);
149 spyOn(hostService, 'getDaemons').and.callFake(() =>
150 of(getDaemonsByHostname(component.hostname))
152 spyOn(cephServiceService, 'getDaemons').and.callFake(() =>
153 of(getDaemonsByServiceName(component.serviceName))
156 headers = new HttpHeaders().set('X-Total-Count', '2');
157 const paginate_obs = new PaginateObservable<any>(of({ body: services, headers: headers }));
158 spyOn(cephServiceService, 'list').and.returnValue(paginate_obs);
159 context.pageInfo.offset = 0;
160 context.pageInfo.limit = -1;
162 fixture.detectChanges();
165 it('should create', () => {
166 expect(component).toBeTruthy();
169 it('should list daemons by host', () => {
170 component.hostname = 'mon0';
171 component.getDaemons(context);
172 expect(component.daemons.length).toBe(1);
175 it('should list daemons by service', () => {
176 component.serviceName = 'osd';
177 component.getDaemons(context);
178 expect(component.daemons.length).toBe(3);
181 it('should list services', () => {
182 component.getServices(context);
183 expect(component.services.length).toBe(2);
186 it('should not display doc panel if orchestrator is available', () => {
187 expect(component.showDocPanel).toBeFalsy();
190 it('should call daemon action', () => {
191 const daemon = daemons[0];
192 component.selection.selected = [daemon];
193 component['daemonService'].action = jest.fn(() => of());
194 for (const action of ['start', 'stop', 'restart', 'redeploy']) {
195 component.daemonAction(action);
196 expect(component['daemonService'].action).toHaveBeenCalledWith(daemon.daemon_name, action);
200 it('should disable daemon actions', () => {
203 status_desc: 'running'
212 const expectBool = (toExpect: boolean, arg: boolean) => {
213 if (toExpect === true) {
214 expect(arg).toBeTruthy();
216 expect(arg).toBeFalsy();
220 component.selection.selected = [daemon];
221 for (const action of ['start', 'stop', 'restart', 'redeploy']) {
222 expectBool(states[action], component.actionDisabled(action));
225 daemon.status_desc = 'stopped';
226 states.start = false;
228 component.selection.selected = [daemon];
229 for (const action of ['start', 'stop', 'restart', 'redeploy']) {
230 expectBool(states[action], component.actionDisabled(action));
234 it('should disable daemon actions in mgr and mon daemon', () => {
237 status_desc: 'running'
239 for (const action of ['start', 'stop', 'restart', 'redeploy']) {
240 expect(component.actionDisabled(action)).toBeTruthy();
242 daemon.daemon_type = 'mon';
243 for (const action of ['start', 'stop', 'restart', 'redeploy']) {
244 expect(component.actionDisabled(action)).toBeTruthy();
248 it('should disable daemon actions if no selection', () => {
249 component.selection.selected = [];
250 for (const action of ['start', 'stop', 'restart', 'redeploy']) {
251 expect(component.actionDisabled(action)).toBeTruthy();
255 it('should sort daemons events', () => {
256 component.sortDaemonEvents();
257 const daemon = daemons[0];
258 for (let i = 1; i < daemon.events.length; i++) {
259 const t1 = new Date(daemon.events[i - 1].created).getTime();
260 const t2 = new Date(daemon.events[i].created).getTime();
261 expect(t1 >= t2).toBeTruthy();