]>
Commit | Line | Data |
---|---|---|
e306af50 TL |
1 | import { FormControl } from '@angular/forms'; |
2 | ||
f6b5b4d7 TL |
3 | import * as _ from 'lodash'; |
4 | ||
5 | import { configureTestBed, Mocks } from '../../../testing/unit-test-helper'; | |
e306af50 | 6 | import { CrushNode } from '../models/crush-node'; |
e306af50 TL |
7 | import { CrushNodeSelectionClass } from './crush.node.selection.class'; |
8 | ||
9 | describe('CrushNodeSelectionService', () => { | |
f6b5b4d7 | 10 | const nodes = Mocks.getCrushMap(); |
e306af50 | 11 | |
f6b5b4d7 | 12 | let service: CrushNodeSelectionClass; |
e306af50 TL |
13 | let controls: { |
14 | root: FormControl; | |
15 | failure: FormControl; | |
16 | device: FormControl; | |
17 | }; | |
18 | ||
e306af50 TL |
19 | // Object contains functions to get something |
20 | const get = { | |
f6b5b4d7 | 21 | nodeByName: (name: string): CrushNode => nodes.find((node) => node.name === name), |
e306af50 TL |
22 | nodesByNames: (names: string[]): CrushNode[] => names.map(get.nodeByName) |
23 | }; | |
24 | ||
25 | // Expects that are used frequently | |
26 | const assert = { | |
e306af50 TL |
27 | formFieldValues: (root: CrushNode, failureDomain: string, device: string) => { |
28 | expect(controls.root.value).toEqual(root); | |
29 | expect(controls.failure.value).toBe(failureDomain); | |
30 | expect(controls.device.value).toBe(device); | |
31 | }, | |
32 | valuesOnRootChange: ( | |
33 | rootName: string, | |
34 | expectedFailureDomain: string, | |
35 | expectedDevice: string | |
36 | ) => { | |
37 | const node = get.nodeByName(rootName); | |
38 | controls.root.setValue(node); | |
39 | assert.formFieldValues(node, expectedFailureDomain, expectedDevice); | |
f6b5b4d7 TL |
40 | }, |
41 | failureDomainNodes: ( | |
42 | failureDomains: { [failureDomain: string]: CrushNode[] }, | |
43 | expected: { [failureDomains: string]: string[] | CrushNode[] } | |
44 | ) => { | |
45 | expect(Object.keys(failureDomains)).toEqual(Object.keys(expected)); | |
46 | Object.keys(failureDomains).forEach((key) => { | |
47 | if (_.isString(expected[key][0])) { | |
48 | expect(failureDomains[key]).toEqual(get.nodesByNames(expected[key] as string[])); | |
49 | } else { | |
50 | expect(failureDomains[key]).toEqual(expected[key]); | |
51 | } | |
52 | }); | |
e306af50 TL |
53 | } |
54 | }; | |
55 | ||
56 | configureTestBed({ | |
57 | providers: [CrushNodeSelectionClass] | |
58 | }); | |
59 | ||
60 | beforeEach(() => { | |
61 | controls = { | |
62 | root: new FormControl(null), | |
63 | failure: new FormControl(''), | |
64 | device: new FormControl('') | |
65 | }; | |
66 | // Normally this should be extended by the class using it | |
67 | service = new CrushNodeSelectionClass(); | |
68 | // Therefore to get it working correctly use "this" instead of "service" | |
f6b5b4d7 | 69 | service.initCrushNodeSelection(nodes, controls.root, controls.failure, controls.device); |
e306af50 TL |
70 | }); |
71 | ||
72 | it('should be created', () => { | |
73 | expect(service).toBeTruthy(); | |
f6b5b4d7 | 74 | expect(nodes.length).toBe(12); |
e306af50 TL |
75 | }); |
76 | ||
77 | describe('lists', () => { | |
78 | afterEach(() => { | |
79 | // The available buckets should not change | |
80 | expect(service.buckets).toEqual( | |
81 | get.nodesByNames(['default', 'hdd-rack', 'mix-host', 'ssd-host', 'ssd-rack']) | |
82 | ); | |
83 | }); | |
84 | ||
85 | it('has the following lists after init', () => { | |
f6b5b4d7 TL |
86 | assert.failureDomainNodes(service.failureDomains, { |
87 | host: ['ssd-host', 'mix-host'], | |
88 | osd: ['osd.1', 'osd.0', 'osd.2'], | |
89 | rack: ['hdd-rack', 'ssd-rack'], | |
90 | 'osd-rack': ['osd2.0', 'osd2.1', 'osd3.0', 'osd3.1'] | |
91 | }); | |
e306af50 TL |
92 | expect(service.devices).toEqual(['hdd', 'ssd']); |
93 | }); | |
94 | ||
95 | it('has the following lists after selection of ssd-host', () => { | |
96 | controls.root.setValue(get.nodeByName('ssd-host')); | |
f6b5b4d7 TL |
97 | assert.failureDomainNodes(service.failureDomains, { |
98 | // Not host as it only exist once | |
99 | osd: ['osd.1', 'osd.0', 'osd.2'] | |
100 | }); | |
e306af50 TL |
101 | expect(service.devices).toEqual(['ssd']); |
102 | }); | |
103 | ||
104 | it('has the following lists after selection of mix-host', () => { | |
105 | controls.root.setValue(get.nodeByName('mix-host')); | |
106 | expect(service.devices).toEqual(['hdd', 'ssd']); | |
f6b5b4d7 TL |
107 | assert.failureDomainNodes(service.failureDomains, { |
108 | rack: ['hdd-rack', 'ssd-rack'], | |
109 | 'osd-rack': ['osd2.0', 'osd2.1', 'osd3.0', 'osd3.1'] | |
110 | }); | |
e306af50 TL |
111 | }); |
112 | }); | |
113 | ||
114 | describe('selection', () => { | |
115 | it('selects the first root after init automatically', () => { | |
116 | assert.formFieldValues(get.nodeByName('default'), 'osd-rack', ''); | |
117 | }); | |
118 | ||
119 | it('should select all values automatically by selecting "ssd-host" as root', () => { | |
120 | assert.valuesOnRootChange('ssd-host', 'osd', 'ssd'); | |
121 | }); | |
122 | ||
123 | it('selects automatically the most common failure domain', () => { | |
124 | // Select mix-host as mix-host has multiple failure domains (osd-rack and rack) | |
125 | assert.valuesOnRootChange('mix-host', 'osd-rack', ''); | |
126 | }); | |
127 | ||
128 | it('should override automatic selections', () => { | |
129 | assert.formFieldValues(get.nodeByName('default'), 'osd-rack', ''); | |
130 | assert.valuesOnRootChange('ssd-host', 'osd', 'ssd'); | |
131 | assert.valuesOnRootChange('mix-host', 'osd-rack', ''); | |
132 | }); | |
133 | ||
134 | it('should not override manual selections if possible', () => { | |
135 | controls.failure.setValue('rack'); | |
136 | controls.failure.markAsDirty(); | |
137 | controls.device.setValue('ssd'); | |
138 | controls.device.markAsDirty(); | |
139 | assert.valuesOnRootChange('mix-host', 'rack', 'ssd'); | |
140 | }); | |
141 | ||
142 | it('should preselect device by domain selection', () => { | |
143 | controls.failure.setValue('osd'); | |
144 | assert.formFieldValues(get.nodeByName('default'), 'osd', 'ssd'); | |
145 | }); | |
146 | }); | |
147 | ||
148 | describe('get available OSDs count', () => { | |
149 | it('should have 4 available OSDs with the default selection', () => { | |
150 | expect(service.deviceCount).toBe(4); | |
151 | }); | |
152 | ||
153 | it('should reduce available OSDs to 2 if a device type is set', () => { | |
154 | controls.device.setValue('ssd'); | |
155 | controls.device.markAsDirty(); | |
156 | expect(service.deviceCount).toBe(2); | |
157 | }); | |
158 | ||
159 | it('should show 3 OSDs when selecting "ssd-host"', () => { | |
160 | assert.valuesOnRootChange('ssd-host', 'osd', 'ssd'); | |
161 | expect(service.deviceCount).toBe(3); | |
162 | }); | |
163 | }); | |
f6b5b4d7 TL |
164 | |
165 | describe('search tree', () => { | |
166 | it('returns the following list after searching for mix-host', () => { | |
167 | const subNodes = CrushNodeSelectionClass.search(nodes, 'mix-host'); | |
168 | expect(subNodes).toEqual( | |
169 | get.nodesByNames([ | |
170 | 'mix-host', | |
171 | 'hdd-rack', | |
172 | 'osd2.0', | |
173 | 'osd2.1', | |
174 | 'ssd-rack', | |
175 | 'osd3.0', | |
176 | 'osd3.1' | |
177 | ]) | |
178 | ); | |
179 | }); | |
180 | ||
181 | it('returns the following list after searching for mix-host with SSDs', () => { | |
182 | const subNodes = CrushNodeSelectionClass.search(nodes, 'mix-host~ssd'); | |
183 | expect(subNodes.map((n) => n.name)).toEqual(['mix-host', 'ssd-rack', 'osd3.0', 'osd3.1']); | |
184 | }); | |
185 | ||
186 | it('returns an empty array if node can not be found', () => { | |
187 | expect(CrushNodeSelectionClass.search(nodes, 'not-there')).toEqual([]); | |
188 | }); | |
189 | ||
190 | it('returns the following list after searching for mix-host failure domains', () => { | |
191 | const subNodes = CrushNodeSelectionClass.search(nodes, 'mix-host'); | |
192 | assert.failureDomainNodes(CrushNodeSelectionClass.getFailureDomains(subNodes), { | |
193 | host: ['mix-host'], | |
194 | rack: ['hdd-rack', 'ssd-rack'], | |
195 | 'osd-rack': ['osd2.0', 'osd2.1', 'osd3.0', 'osd3.1'] | |
196 | }); | |
197 | }); | |
198 | ||
199 | it('returns the following list after searching for mix-host failure domains for a specific type', () => { | |
200 | const subNodes = CrushNodeSelectionClass.search(nodes, 'mix-host~hdd'); | |
201 | const hddHost = _.cloneDeep(get.nodesByNames(['mix-host'])[0]); | |
202 | hddHost.children = [-4]; | |
203 | assert.failureDomainNodes(CrushNodeSelectionClass.getFailureDomains(subNodes), { | |
204 | host: [hddHost], | |
205 | rack: ['hdd-rack'], | |
206 | 'osd-rack': ['osd2.0', 'osd2.1'] | |
207 | }); | |
208 | const ssdHost = _.cloneDeep(get.nodesByNames(['mix-host'])[0]); | |
209 | ssdHost.children = [-5]; | |
210 | assert.failureDomainNodes( | |
211 | CrushNodeSelectionClass.searchFailureDomains(nodes, 'mix-host~ssd'), | |
212 | { | |
213 | host: [ssdHost], | |
214 | rack: ['ssd-rack'], | |
215 | 'osd-rack': ['osd3.0', 'osd3.1'] | |
216 | } | |
217 | ); | |
218 | }); | |
219 | }); | |
e306af50 | 220 | }); |