-
Notifications
You must be signed in to change notification settings - Fork 12
/
silos.e2e.ts
416 lines (328 loc) · 14.8 KB
/
silos.e2e.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import { expect, test } from '@playwright/test'
import {
addTlsCert,
chooseFile,
clickRowAction,
closeToast,
expectNotVisible,
expectRowVisible,
expectVisible,
} from './utils'
test('Create silo', async ({ page }) => {
await page.goto('/system/silos')
await expectVisible(page, ['role=heading[name*="Silos"]'])
const table = page.locator('role=table')
await expectRowVisible(table, {
name: 'maze-war',
'Identity mode': 'saml jit',
// not easy to assert this until we can calculate accessible name instead of text content
// discoverable: 'true',
})
await expect(page.getByText('Feb 28, 202312:00 AM')).toBeVisible()
await page.click('role=link[name="New silo"]')
const modal = page.getByRole('dialog', { name: 'Create silo' })
await expect(modal).toBeVisible()
// fill out form
await page.getByRole('textbox', { name: 'Name', exact: true }).fill('other-silo')
await page.getByRole('textbox', { name: 'Description' }).fill('definitely a silo')
const discoverable = page.getByRole('checkbox', { name: 'Discoverable' })
await expect(discoverable).toBeChecked()
await discoverable.click()
await expect(page.getByRole('textbox', { name: 'Admin group name' })).toBeVisible()
await page.getByRole('textbox', { name: 'Admin group name' }).fill('admins')
await page.getByRole('checkbox', { name: 'Grant fleet admin' }).click()
await expect(page.getByRole('textbox', { name: 'Admin group name' })).toHaveValue(
'admins'
)
await expect(page.getByRole('checkbox', { name: 'Grant fleet admin' })).toBeChecked()
await page.getByRole('radio', { name: 'Local only' }).click()
await expect(page.getByRole('textbox', { name: 'Admin group name' })).toBeHidden()
await page.getByRole('radio', { name: 'SAML' }).click()
await expect(page.getByRole('textbox', { name: 'Admin group name' })).toHaveValue('')
await expect(page.getByRole('checkbox', { name: 'Grant fleet admin' })).toBeChecked()
await page.getByRole('textbox', { name: 'Admin group name' }).fill('admins')
////////////////////////////
// QUOTAS
////////////////////////////
const cpuQuota = page.getByRole('textbox', { name: 'CPU quota' })
const decreaseCpuQuota = page.getByRole('button', { name: 'Decrease CPU quota' })
// can't go below zero
await expect(cpuQuota).toHaveValue('0')
await expect(decreaseCpuQuota).toBeDisabled()
await page.getByRole('textbox', { name: 'CPU quota' }).fill('30')
await expect(decreaseCpuQuota).toBeEnabled() // now you can decrease it
await page.getByRole('textbox', { name: 'Memory quota' }).fill('58')
await page.getByRole('textbox', { name: 'Storage quota' }).fill('735')
await page.getByRole('button', { name: 'Create silo' }).click()
// expect error because no TLS cert
await expect(modal.getByText('At least one certificate is required')).toBeVisible()
////////////////////////////
// TLS CERT
////////////////////////////
const openCertModalButton = page.getByRole('button', { name: 'Add TLS certificate' })
await openCertModalButton.click()
const certDialog = page.getByRole('dialog', { name: 'Add TLS certificate' })
const certRequired = certDialog.getByText('Cert is required')
const keyRequired = certDialog.getByText('Key is required')
const nameRequired = certDialog.getByText('Name is required')
await expectNotVisible(page, [certRequired, keyRequired, nameRequired])
const certSubmit = page.getByRole('button', { name: 'Add Certificate' })
await certSubmit.click()
// Validation error for missing name + key and cert files
await expectVisible(page, [certRequired, keyRequired, nameRequired])
await chooseFile(page, page.getByLabel('Cert', { exact: true }), 'small')
await chooseFile(page, page.getByLabel('Key'), 'small')
const certName = certDialog.getByRole('textbox', { name: 'Name' })
await certName.fill('test-cert')
await certSubmit.click()
// Check cert appears in the mini-table
const certCell = page.getByRole('cell', { name: 'test-cert', exact: true })
await expect(certCell).toBeVisible()
// check unique name validation
await openCertModalButton.click()
await certName.fill('test-cert')
await certSubmit.click()
await expect(
certDialog.getByText('A certificate with this name already exists')
).toBeVisible()
// Change the name so it's unique
await certName.fill('test-cert-2')
await chooseFile(page, page.getByLabel('Cert', { exact: true }), 'small')
await chooseFile(page, page.getByLabel('Key'), 'small')
await certSubmit.click()
await expect(page.getByRole('cell', { name: 'test-cert-2', exact: true })).toBeVisible()
// now delete the first
await page.getByRole('button', { name: 'remove cert test-cert', exact: true }).click()
// Cert should not appear after it has been deleted
await expect(certCell).toBeHidden()
await page.click('role=button[name="Create silo"]')
// it's there in the table
await expectRowVisible(table, {
name: 'other-silo',
description: 'definitely a silo',
'Identity mode': 'saml jit',
// discoverable: 'false',
})
const otherSiloCell = page.getByRole('cell', { name: 'other-silo' })
await expect(otherSiloCell).toBeVisible()
// click into detail view and check the fleet role map
await otherSiloCell.getByRole('link').click()
await page.getByRole('tab', { name: 'Fleet roles' }).click()
await expectVisible(page, [
page.getByRole('heading', { name: 'other-silo' }),
page.getByText('Silo adminFleet admin'),
])
await expect(page.getByText('Silo viewerFleet viewer')).toBeHidden()
// now go check the quotas in its entry in the utilization table
await page.getByRole('tab', { name: 'Quotas' }).click()
await expectRowVisible(table, { Resource: 'CPU', Quota: '30 vCPUs' })
await expectRowVisible(table, { Resource: 'Memory', Quota: '58 GiB' })
await expectRowVisible(table, { Resource: 'Storage', Quota: '735 GiB' })
await page.goBack()
// now delete it
await clickRowAction(page, 'other-silo', 'Delete')
await page.getByRole('button', { name: 'Confirm' }).click()
await expect(otherSiloCell).toBeHidden()
})
test('Default silo', async ({ page }) => {
await page.goto('/system/silos')
await page.getByRole('link', { name: 'myriad' }).click()
await expect(page.getByRole('heading', { name: 'myriad' })).toBeVisible()
await page.getByRole('tab', { name: 'Fleet roles' }).click()
await expect(
page.getByText('Silo roles can automatically grant a fleet role.')
).toBeVisible()
await expectNotVisible(page, [
page.getByText('Silo adminFleet admin'),
page.getByText('Silo viewerFleet viewer'),
])
})
test('Identity providers', async ({ page }) => {
await page.goto('/system/silos/maze-war')
await expectVisible(page, ['role=heading[name*=maze-war]'])
await page.getByRole('link', { name: 'mock-idp' }).click()
const dialog = page.getByRole('dialog', { name: 'Identity provider' })
await expect(dialog).toBeVisible()
await expect(page.getByRole('heading', { name: 'mock-idp' })).toBeVisible()
// random stuff that's not in the table
await expect(page.getByText('Entity ID')).toBeVisible()
await expect(page.getByText('Single Logout (SLO) URL')).toBeVisible()
await expect(page.getByRole('textbox', { name: 'Group attribute name' })).toHaveValue(
'groups'
)
await page.getByRole('button', { name: 'Close' }).click()
await expect(dialog).toBeHidden()
// test creating identity provider
await page.getByRole('link', { name: 'New provider' }).click()
await expect(dialog).toBeVisible()
// test login URL preview in name field description
await expect(page.getByText('login page: /login/maze-war/saml/idp-name')).toBeVisible()
const nameField = dialog.getByLabel('Name', { exact: true })
await nameField.fill('test-provider')
// preview updates as you type
await expect(
page.getByText('login page: /login/maze-war/saml/test-provider')
).toBeVisible()
// ACS URL should be populated with generated value
const acsUrlField = dialog.getByLabel('ACS URL', { exact: true })
const acsUrl = 'https://maze-war.sys.placeholder/login/maze-war/saml/test-provider'
await expect(acsUrlField).toHaveValue(acsUrl)
const acsUrlCheckbox = dialog.getByRole('checkbox', { name: 'Use standard ACS URL' })
await expect(acsUrlCheckbox).toBeChecked()
// uncheck the box and change the value
await acsUrlCheckbox.click()
await acsUrlField.fill('https://example.com')
await expect(acsUrlField).toHaveValue('https://example.com')
// re-check the box and verify that the value is regenerated
await acsUrlCheckbox.click()
await expect(acsUrlField).toHaveValue(acsUrl)
await page.getByRole('button', { name: 'Create provider' }).click()
await closeToast(page)
await expect(dialog).toBeHidden()
// new provider should appear in table
await expectRowVisible(page.getByRole('table'), {
name: 'test-provider',
Type: 'saml',
description: '—',
})
await page.getByRole('link', { name: 'test-provider' }).click()
await expect(nameField).toHaveValue('test-provider')
await expect(nameField).toBeDisabled()
await expect(acsUrlField).toHaveValue(acsUrl)
await expect(acsUrlField).toBeDisabled()
})
test('Silo IP pools', async ({ page }) => {
await page.goto('/system/silos/maze-war?tab=ip-pools')
const table = page.getByRole('table')
await expectRowVisible(table, { name: 'ip-pool-1', Default: 'default' })
await expectRowVisible(table, { name: 'ip-pool-2', Default: '' })
await expect(table.getByRole('row')).toHaveCount(3) // header + 2
// clicking on pool goes to pool detail
await page.getByRole('link', { name: 'ip-pool-1' }).click()
await expect(page).toHaveURL('/system/networking/ip-pools/ip-pool-1')
await page.goBack()
// make default
await clickRowAction(page, 'ip-pool-2', 'Make default')
await expect(
page
.getByRole('dialog', { name: 'Confirm change default' })
.getByText(
'Are you sure you want to change the default pool from ip-pool-1 to ip-pool-2?'
)
).toBeVisible()
await page.getByRole('button', { name: 'Confirm' }).click()
await expectRowVisible(table, { name: 'ip-pool-1', Default: '' })
await expectRowVisible(table, { name: 'ip-pool-2', Default: 'default' })
// unlink
await clickRowAction(page, 'ip-pool-1', 'Unlink')
await expect(
page
.getByRole('dialog', { name: 'Confirm unlink pool' })
.getByText('Are you sure you want to unlink ip-pool-1?')
).toBeVisible()
await page.getByRole('button', { name: 'Confirm' }).click()
await expect(page.getByRole('cell', { name: 'ip-pool-1' })).toBeHidden()
await expectRowVisible(table, { name: 'ip-pool-2', Default: 'default' })
// clear default
await clickRowAction(page, 'ip-pool-2', 'Clear default')
await expect(
page
.getByRole('dialog', { name: 'Confirm clear default' })
.getByText('Are you sure you want ip-pool-2 to stop being the default')
).toBeVisible()
await page.getByRole('button', { name: 'Confirm' }).click()
await expectRowVisible(table, { name: 'ip-pool-2', Default: '' })
})
test('Silo IP pools link pool', async ({ page }) => {
await page.goto('/system/silos/maze-war?tab=ip-pools')
const table = page.getByRole('table')
await expectRowVisible(table, { name: 'ip-pool-1', Default: 'default' })
await expectRowVisible(table, { name: 'ip-pool-2', Default: '' })
await expect(table.getByRole('row')).toHaveCount(3) // header + 2
const modal = page.getByRole('dialog', { name: 'Link pool' })
await expect(modal).toBeHidden()
// open link modal
await page.getByRole('button', { name: 'Link pool' }).click()
await expect(modal).toBeVisible()
// close modal works
await page.getByRole('button', { name: 'Close' }).click()
await expect(modal).toBeHidden()
// reopen
await page.getByRole('button', { name: 'Link pool' }).click()
await expect(modal).toBeVisible()
// verify that combobox's "no items match" appears when addNewItems prop is false or missing
await page.getByPlaceholder('Select a pool').fill('x')
await expect(page.getByText('No items match')).toBeVisible()
// select silo in combobox and click link
await page.getByPlaceholder('Select a pool').fill('ip-pool')
await page.getByRole('option', { name: 'ip-pool-3' }).click()
await modal.getByRole('button', { name: 'Link' }).click()
// modal closes and we see the thing in the table
await expect(modal).toBeHidden()
await expectRowVisible(table, { name: 'ip-pool-3', Default: '' })
})
// just a convenient form to test this with because it's tall
test('form scrolls to name field on already exists error', async ({ page }) => {
await page.setViewportSize({ width: 800, height: 400 })
await page.goto('/system/silos-new')
const nameField = page.getByRole('textbox', { name: 'Name', exact: true })
await expect(nameField).toBeInViewport()
await nameField.fill('maze-war')
// scroll all the way down so the name field is not visible
await page
.getByTestId('sidemodal-scroll-container')
.evaluate((el: HTMLElement, to) => el.scrollTo(0, to), 800)
await expect(nameField).not.toBeInViewport()
await addTlsCert(page)
await page.getByRole('button', { name: 'Create silo' }).click()
await expect(nameField).toBeInViewport()
await expect(page.getByText('name already exists').nth(0)).toBeVisible()
})
test('Quotas tab', async ({ page }) => {
await page.goto('/system/silos/maze-war')
await page.getByRole('tab', { name: 'Quotas' }).click()
const table = page.getByRole('table')
await expectRowVisible(table, {
Resource: 'CPU',
Provisioned: '30 vCPUs',
Quota: '50 vCPUs',
})
await expectRowVisible(table, {
Resource: 'Memory',
Provisioned: '234 GiB',
Quota: '300 GiB',
})
await expectRowVisible(table, {
Resource: 'Storage',
Provisioned: '4403.2 GiB',
Quota: '7168 GiB',
})
const sideModal = page.getByRole('dialog', { name: 'Edit quotas' })
const edit = page.getByRole('button', { name: 'Edit quotas' })
const submit = sideModal.getByRole('button', { name: 'Update quotas' })
await edit.click()
await expect(sideModal).toBeVisible()
// test validation on empty field
const memory = page.getByRole('textbox', { name: 'Memory' })
await memory.clear()
await submit.click()
await expect(sideModal.getByText('Memory is required')).toBeVisible()
// try to type in a negative number HAHA YOU CAN'T
await memory.fill('-5')
await expect(memory).toHaveValue('')
// only change one
await memory.fill('50')
await submit.click()
await expect(sideModal).toBeHidden()
// only one changes, the others stay the same
await expectRowVisible(table, { Resource: 'CPU', Quota: '50 vCPUs' })
await expectRowVisible(table, { Resource: 'Memory', Quota: '50 GiB' })
await expectRowVisible(table, { Resource: 'Storage', Quota: '7168 GiB' })
})