Skip to content

Commit

Permalink
NAS-123468: Refactoring Sysctl table (#8609)
Browse files Browse the repository at this point in the history
  • Loading branch information
denysbutenko authored Aug 19, 2023
1 parent dbbe0f1 commit 761377a
Show file tree
Hide file tree
Showing 95 changed files with 662 additions and 85 deletions.
2 changes: 1 addition & 1 deletion src/app/interfaces/api/api-call-directory.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ export interface ApiCallDirectory {

// Tunable
'tunable.tunable_type_choices': { params: void; response: Choices };
'tunable.query': { params: QueryParams<Tunable>; response: Tunable };
'tunable.query': { params: QueryParams<Tunable>; response: Tunable[] };

// FTP
'ftp.update': { params: [FtpConfigUpdate]; response: FtpConfig };
Expand Down
1 change: 1 addition & 0 deletions src/app/interfaces/tunable.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Tunable {
type: TunableType;
value: string;
var: string;
orig_value?: string;
}

export type TunableCreate = Omit<Tunable, 'id'>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class TunableFormComponent implements OnInit {
complete: () => {
this.isFormLoading = false;
this.cdr.markForCheck();
this.slideInRef.close();
this.slideInRef.close(true);
},
error: (error) => {
this.isFormLoading = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<ng-template ixPageHeader>
<ix-page-title-header>
<ix-search-input (search)="onListFiltered($event)"></ix-search-input>

<button mat-button ixTest="add-tunable" [color]="'primary'" (click)="doAdd()">
{{ 'Add' | translate }}
</button>
</ix-page-title-header>
</ng-template>

<ix-table2
class="table"
[ix-table2-empty]="!dataProvider.rows.length"
[emptyConfig]="emptyConfig.defaultEmptyConfig(emptyType$ | async)"
>
<thead
ix-table-head
[columns]="columns"
[dataProvider]="dataProvider"
></thead>
<tbody
ix-table-body
[columns]="columns"
[dataProvider]="dataProvider"
>
<ng-template
ix-table-cell
[columnIndex]="5"
[dataProvider]="dataProvider"
let-tunable
>
<div class="actions">
<button
mat-icon-button
[ixTest]="['edit', tunable.id]"
(click)="doEdit(tunable)"
>
<ix-icon name="mdi-pencil"></ix-icon>
</button>
<button
mat-icon-button
[ixTest]="['delete', tunable.id]"
(click)="doDelete(tunable)"
>
<ix-icon name="mdi-delete"></ix-icon>
</button>
</div>
</ng-template>
</tbody>
</ix-table2>
<ix-table-pager [dataProvider]="dataProvider"></ix-table-pager>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
:host {
display: block;
}

.actions {
display: flex;
justify-content: flex-end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatButtonHarness } from '@angular/material/button/testing';
import { Spectator } from '@ngneat/spectator';
import { createComponentFactory, mockProvider } from '@ngneat/spectator/jest';
import { of } from 'rxjs';
import { fakeSuccessfulJob } from 'app/core/testing/utils/fake-job.utils';
import {
mockWebsocket, mockCall, mockJob,
} from 'app/core/testing/utils/mock-websocket.utils';
import { Tunable } from 'app/interfaces/tunable.interface';
import { IxIconHarness } from 'app/modules/ix-icon/ix-icon.harness';
import { IxTable2Harness } from 'app/modules/ix-table2/components/ix-table2/ix-table2.harness';
import { IxTable2Module } from 'app/modules/ix-table2/ix-table2.module';
import { TunableFormComponent } from 'app/pages/system/advanced/sysctl/tunable-form/tunable-form.component';
import { TunableListComponent } from 'app/pages/system/advanced/sysctl/tunable-list/tunable-list.component';
import { DialogService } from 'app/services/dialog.service';
import { IxSlideInService } from 'app/services/ix-slide-in.service';

describe('TunableListComponent', () => {
let spectator: Spectator<TunableListComponent>;
let loader: HarnessLoader;
let table: IxTable2Harness;

const tunables = [
{
id: 1,
type: 'ZFS',
var: 'zfs_dirty_data_max_max',
value: '12884901888',
orig_value: '4294967296',
comment: 'Generated by autotune',
enabled: true,
},
{
id: 2,
type: 'ZFS',
var: 'zfs_arc_max',
value: '121227934924',
orig_value: '0',
comment: 'Generated by autotune',
enabled: true,
},
{
id: 3,
type: 'ZFS',
var: 'l2arc_noprefetch',
value: '0',
orig_value: '1',
comment: 'Generated by autotune',
enabled: true,
},
{
id: 4,
type: 'ZFS',
var: 'l2arc_write_max',
value: '10000000',
orig_value: '8388608',
comment: 'Generated by autotune',
enabled: true,
},
{
id: 5,
type: 'ZFS',
var: 'l2arc_write_boost',
value: '40000000',
orig_value: '8388608',
comment: 'Generated by autotune',
enabled: true,
},
{
id: 6,
type: 'ZFS',
var: 'zfs_vdev_sync_write_max_active',
value: '67108864',
orig_value: '10',
comment: 'Generated by autotune',
enabled: true,
},
{
id: 12,
type: 'SYSCTL',
var: 'kernel.hostname',
value: 'truenas',
orig_value: 'truenas',
comment: 'Description text',
enabled: true,
},
{
id: 13,
type: 'SYSCTL',
var: 'kernel.watchdog',
value: '1',
orig_value: '1',
comment: 'Woof woof',
enabled: true,
},
] as Tunable[];

const createComponent = createComponentFactory({
component: TunableListComponent,
imports: [IxTable2Module],
declarations: [],
providers: [
mockProvider(IxSlideInService, {
onClose$: of(),
open: jest.fn(() => ({ slideInClosed$: of(true) })),
}),
mockProvider(DialogService, {
confirm: jest.fn(() => of(true)),
}),
mockWebsocket([
mockCall('core.get_jobs'),
mockCall('tunable.query', tunables),
mockJob('tunable.delete', fakeSuccessfulJob()),
]),
],
});

beforeEach(async () => {
spectator = createComponent();
loader = TestbedHarnessEnvironment.loader(spectator.fixture);
table = await loader.getHarness(IxTable2Harness);
});

it('should show table rows', async () => {
const expectedRows = [
['Variable', 'Value', 'Type', 'Description', 'Enabled', ''],
['kernel.hostname', 'truenas', 'SYSCTL', 'Description text', 'Yes', ''],
['kernel.watchdog', '1', 'SYSCTL', 'Woof woof', 'Yes', ''],
['l2arc_noprefetch', '0', 'ZFS', 'Generated by autotune', 'Yes', ''],
['l2arc_write_boost', '40000000', 'ZFS', 'Generated by autotune', 'Yes', ''],
['l2arc_write_max', '10000000', 'ZFS', 'Generated by autotune', 'Yes', ''],
['zfs_arc_max', '121227934924', 'ZFS', 'Generated by autotune', 'Yes', ''],
['zfs_dirty_data_max_max', '12884901888', 'ZFS', 'Generated by autotune', 'Yes', ''],
['zfs_vdev_sync_write_max_active', '67108864', 'ZFS', 'Generated by autotune', 'Yes', ''],
];

const cells = await table.getCellTexts();
expect(cells).toEqual(expectedRows);
});

it.skip('shows add form when Add button is pressed', async () => {

Check warning on line 143 in src/app/pages/system/advanced/sysctl/tunable-list/tunable-list.component.spec.ts

View workflow job for this annotation

GitHub Actions / Validate code style

Disabled test
const addButton = await loader.getHarness(MatButtonHarness.with({ text: 'Add' }));
await addButton.click();

expect(spectator.inject(IxSlideInService).open).toHaveBeenCalledWith(TunableFormComponent, {});
});

it('shows edit form with an existing sysctl when Edit button is pressed', async () => {
const editIcon = await loader.getHarness(IxIconHarness.with({ name: 'mdi-pencil' }));
await editIcon.click();

expect(spectator.inject(IxSlideInService).open).toHaveBeenCalledWith(TunableFormComponent, {
data: {
comment: 'Description text',
enabled: true,
id: 12,
orig_value: 'truenas',
type: 'SYSCTL',
value: 'truenas',
var: 'kernel.hostname',
},
});
});

it('shows confirmation when Delete button is pressed', async () => {
const deleteIcon = await loader.getHarness(IxIconHarness.with({ name: 'mdi-delete' }));
await deleteIcon.click();

expect(spectator.inject(DialogService).confirm).toHaveBeenCalledWith({
buttonText: 'Delete',
message: 'Are you sure you want to delete "kernel.hostname"?',
title: 'Delete Sysctl',
});
});
});
Loading

0 comments on commit 761377a

Please sign in to comment.