Skip to content

Commit

Permalink
NAS-131802: Error with some dataset paths in pool creation (#10897)
Browse files Browse the repository at this point in the history
  • Loading branch information
undsoft authored Oct 21, 2024
1 parent c88d84b commit 93d1b7f
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ <h1 mat-dialog-title>{{ 'Create Dataset' | translate }}</h1>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
}
</div>
<div mat-dialog-content>
<form [formGroup]="form">
<ix-input
formControlName="name"
[label]="'Name' | translate"
[required]="true"
></ix-input>
</form>
</div>
<form [formGroup]="form">
<ix-input
formControlName="name"
[label]="'Name' | translate"
[required]="true"
></ix-input>
</form>
<ix-form-actions mat-dialog-actions class="form-actions">
<button mat-button matDialogClose ixTest="cancel">{{ 'Cancel' | translate }}</button>
<button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,52 +34,70 @@ describe('CreateDatasetDialogComponent', () => {
mockCall('pool.dataset.create', { name: 'created_dataset' } as Dataset),
]),
mockProvider(MatDialogRef),
{
provide: MAT_DIALOG_DATA,
useValue: {
parentId: 'pool/parent-dataset',
dataset: { acltype: DatasetAclType.Nfsv4 } as DatasetCreate,
},
},
],
});

beforeEach(() => {
spectator = createComponent();
function setupTest(parentId = 'pool/parent-dataset'): void {
spectator = createComponent({
providers: [
{
provide: MAT_DIALOG_DATA,
useValue: {
parentId,
dataset: { acltype: DatasetAclType.Nfsv4 } as DatasetCreate,
},
},
],
});
loader = TestbedHarnessEnvironment.loader(spectator.fixture);
});
}

it('checks validation error when dataset name already in use', async () => {
const datasetName = await loader.getHarness(IxInputHarness.with({ label: 'Name' }));
const form = await loader.getHarness(IxFormHarness);
await form.fillForm({
Name: 'SoMe_DaTaSeT',
});
describe('normal operation', () => {
beforeEach(() => setupTest());

expect(await datasetName.getErrorText()).toBe('The name "some_dataset" is already in use.');
it('checks validation error when dataset name already in use', async () => {
const datasetName = await loader.getHarness(IxInputHarness.with({ label: 'Name' }));
const form = await loader.getHarness(IxFormHarness);
await form.fillForm({
Name: 'SoMe_DaTaSeT',
});

await form.fillForm({
Name: 'new_some_dataset',
});
expect(await datasetName.getErrorText()).toBe('');
});
expect(await datasetName.getErrorText()).toBe('The name "some_dataset" is already in use.');

it('creates new dataset when Create button is pressed', async () => {
const form = await loader.getHarness(IxFormHarness);
await form.fillForm({
Name: 'new_dataset',
await form.fillForm({
Name: 'new_some_dataset',
});
expect(await datasetName.getErrorText()).toBe('');
});

const createButton = await loader.getHarness(MatButtonHarness.with({ text: 'Create' }));
await createButton.click();
it('creates new dataset when Create button is pressed', async () => {
const form = await loader.getHarness(IxFormHarness);
await form.fillForm({
Name: 'new_dataset',
});

const createButton = await loader.getHarness(MatButtonHarness.with({ text: 'Create' }));
await createButton.click();

expect(spectator.inject(WebSocketService).call).toHaveBeenCalledWith('pool.dataset.create', [{
name: 'parent_name/new_dataset',
acltype: DatasetAclType.Nfsv4,
}]);

expect(spectator.inject(MatDialogRef).close).toHaveBeenCalledWith({
name: 'created_dataset',
});
});
});

expect(spectator.inject(WebSocketService).call).toHaveBeenCalledWith('pool.dataset.create', [{
name: 'parent_name/new_dataset',
acltype: DatasetAclType.Nfsv4,
}]);
describe('special cases', () => {
it('loads correct parent dataset even if parent id was passed in with leading slash', () => {
setupTest('/pool/parent-dataset-with-slash/');

expect(spectator.inject(MatDialogRef).close).toHaveBeenCalledWith({
name: 'created_dataset',
expect(spectator.inject(WebSocketService).call).toHaveBeenCalledWith(
'pool.dataset.query',
[[['id', '=', '/pool/parent-dataset-with-slash']]],
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { MatProgressBar } from '@angular/material/progress-bar';
import { FormBuilder } from '@ngneat/reactive-forms';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { TranslateModule } from '@ngx-translate/core';
import { BehaviorSubject } from 'rxjs';
import { BehaviorSubject, tap } from 'rxjs';
import { nameValidatorRegex } from 'app/constants/name-validator.constant';
import { RequiresRolesDirective } from 'app/directives/requires-roles/requires-roles.directive';
import { DatasetCaseSensitivity } from 'app/enums/dataset.enum';
Expand Down Expand Up @@ -104,13 +104,27 @@ export class CreateDatasetDialogComponent implements OnInit {

loadParentDataset(): void {
this.isLoading$.next(true);
this.ws.call('pool.dataset.query', [[['id', '=', this.data.parentId]]])
.pipe(untilDestroyed(this)).subscribe((parent) => {
const normalizedParentId = this.data.parentId.replace(/\/$/, '');
this.ws.call('pool.dataset.query', [[['id', '=', normalizedParentId]]]).pipe(
tap((parent) => {
if (!parent.length) {
throw new Error(`Parent dataset ${normalizedParentId} not found`);
}
}),
untilDestroyed(this),
).subscribe({
next: (parent) => {
this.isLoading$.next(false);
this.parent = parent[0];
this.cdr.markForCheck();
this.addNameValidators();
});
},
error: (error) => {
this.isLoading$.next(false);
this.dialog.error(this.errorHandler.parseError(error));
this.dialogRef.close(false);
},
});
}

private addNameValidators(): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
<h1 matDialogTitle>{{ 'Manual S.M.A.R.T. Test' | translate }}</h1>

<form
class="ix-form-container"
[formGroup]="form"
(submit)="onSubmit()"
>
<div class="disks-list">
@if (selectedDisksWithSmartSupport.length) {
@if (isSubmitted()) {
<div class="prompt">{{ 'Running manual test(s) on disk(s):' }}</div>
} @else {
<div class="prompt">{{ 'Run manual test(s) on disk(s):' }}</div>
}
<ul class="disks">
@for (disk of selectedDisksWithSmartSupport; track disk.name) {
<ix-test-progress-row
[disk]="disk"
[testType]="form.value.type"
[loading]="isSubmitted()"
[testStartError]="disk.error"
[testStarted]="startedTests()"
></ix-test-progress-row>
}
</ul>
}
@if (selectedDisksWithoutSmartSupport.length) {
<div class="prompt">
{{ 'These disks do not support S.M.A.R.T. tests:' | translate }}
</div>
<ul class="disks">
@for (disk of selectedDisksWithoutSmartSupport; track disk) {
<li>
<div class="list-item">
<span>{{ disk.name }} ({{ disk.serial }})</span>
</div>
</li>
}
</ul>
<form
class="ix-form-container"
[formGroup]="form"
(submit)="onSubmit()"
>
<div class="disks-list">
@if (selectedDisksWithSmartSupport.length) {
@if (isSubmitted()) {
<div class="prompt">{{ 'Running manual test(s) on disk(s):' }}</div>
} @else {
<div class="prompt">{{ 'Run manual test(s) on disk(s):' }}</div>
}
</div>
<ul class="disks">
@for (disk of selectedDisksWithSmartSupport; track disk.name) {
<ix-test-progress-row
[disk]="disk"
[testType]="form.value.type"
[loading]="isSubmitted()"
[testStartError]="disk.error"
[testStarted]="startedTests()"
></ix-test-progress-row>
}
</ul>
}
@if (selectedDisksWithoutSmartSupport.length) {
<div class="prompt">
{{ 'These disks do not support S.M.A.R.T. tests:' | translate }}
</div>
<ul class="disks">
@for (disk of selectedDisksWithoutSmartSupport; track disk) {
<li>
<div class="list-item">
<span>{{ disk.name }} ({{ disk.serial }})</span>
</div>
</li>
}
</ul>
}
</div>

@if (!isSubmitted()) {
<ix-select
formControlName="type"
[required]="true"
[label]="'Type' | translate"
[options]="testTypes$"
></ix-select>
}
<ix-form-actions>
@if (!isSubmitted()) {
<ix-select
formControlName="type"
[required]="true"
[label]="'Type' | translate"
[options]="testTypes$"
></ix-select>
<button mat-button type="button" ixTest="cancel" [matDialogClose]="false">
{{ 'Cancel' | translate }}
</button>

<button
*ixRequiresRoles="[Role.FullAdmin]"
mat-button
type="submit"
color="primary"
ixTest="start-test"
[disabled]="form.invalid || !selectedDisksWithSmartSupport.length"
>
{{ 'Start' | translate }}
</button>
} @else {
<button
mat-button
type="button"
ixTest="minimize"
[matDialogClose]="false"
>
{{ 'Continue in background' | translate }}
</button>
}
<ix-form-actions>
@if (!isSubmitted()) {
<button mat-button type="button" ixTest="cancel" [matDialogClose]="false">
{{ 'Cancel' | translate }}
</button>

<button
*ixRequiresRoles="[Role.FullAdmin]"
mat-button
type="submit"
color="primary"
ixTest="start-test"
[disabled]="form.invalid || !selectedDisksWithSmartSupport.length"
>
{{ 'Start' | translate }}
</button>
} @else {
<button
mat-button
type="button"
ixTest="minimize"
[matDialogClose]="false"
>
{{ 'Continue in background' | translate }}
</button>
}

</ix-form-actions>
</form>
</ix-form-actions>
</form>

0 comments on commit 93d1b7f

Please sign in to comment.