Skip to content

Commit

Permalink
NAS-133825 / 25.10 / Update backups only once at the end (#11459)
Browse files Browse the repository at this point in the history
* NAS-133825: Update backups only once at the end

* NAS-133825: Add test case
  • Loading branch information
bvasilenko authored Feb 3, 2025
1 parent 5faee3e commit 5a0a258
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing';
import { Router } from '@angular/router';
import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
import { provideMockStore } from '@ngrx/store/testing';
import { of } from 'rxjs';
import { delay, of, throwError } from 'rxjs';
import { mockCall, mockApi } from 'app/core/testing/utils/mock-api.utils';
import { mockAuth } from 'app/core/testing/utils/mock-auth.utils';
import { JobState } from 'app/enums/job-state.enum';
Expand Down Expand Up @@ -45,6 +45,20 @@ describe('CloudBackupCardComponent', () => {
},
},
} as CloudBackup,
{
id: 2,
description: 'test two',
path: '/mnt/nmnmn',
pre_script: 'your_pre_script',
snapshot: false,
enabled: false,
job: {
state: JobState.Finished,
time_finished: {
$date: new Date().getTime() - 50000,
},
},
} as CloudBackup,
];

const createComponent = createComponentFactory({
Expand Down Expand Up @@ -100,6 +114,7 @@ describe('CloudBackupCardComponent', () => {
const expectedRows = [
['Name', 'Enabled', 'Snapshot', 'State', 'Last Run', ''],
['test one', '', 'No', 'FINISHED', '1 min. ago', ''],
['test two', '', 'No', 'FINISHED', '1 min. ago', ''],
];

const cells = await table.getCellTexts();
Expand Down Expand Up @@ -169,6 +184,54 @@ describe('CloudBackupCardComponent', () => {
);
});

it('sends only one update request when multiple mat-toggle is updated', async () => {
jest.spyOn(spectator.component.dataProvider, 'load').mockImplementation();
jest.spyOn(spectator.inject(ApiService), 'call').mockImplementationOnce((method) => {
if (method === 'cloud_backup.update') {
return of(null).pipe(delay(10));
}
throw new Error(`Unexpected method: ${method}`);
});

const toggle1 = await table.getHarnessInCell(MatSlideToggleHarness, 1, 1);
const toggle2 = await table.getHarnessInCell(MatSlideToggleHarness, 2, 1);

expect(spectator.component.dataProvider.load).toHaveBeenCalledTimes(0);
await Promise.all([toggle1.check(), toggle2.check()]);

expect(spectator.inject(ApiService).call).toHaveBeenCalledWith(
'cloud_backup.update',
[1, { enabled: true }],
);

expect(spectator.inject(ApiService).call).toHaveBeenCalledWith(
'cloud_backup.update',
[2, { enabled: true }],
);
expect(spectator.component.dataProvider.load).toHaveBeenCalledTimes(1);
});

it('shows cloud backup update error', async () => {
jest.spyOn(spectator.inject(ApiService), 'call').mockImplementationOnce((method) => {
if (method === 'cloud_backup.update') {
return throwError(() => ({
jsonrpc: '2.0',
error: {
data: {
reason: 'cloud backup update error',
},
},
}));
}
throw new Error(`Unexpected method: ${method}`);
});

expect(spectator.inject(DialogService).error).not.toHaveBeenCalled();
const toggle = await table.getHarnessInCell(MatSlideToggleHarness, 1, 1);
await toggle.check();
expect(spectator.inject(DialogService).error).toHaveBeenCalled();
});

it('navigates to the details page when View Details button is pressed', async () => {
const router = spectator.inject(Router);
const navigateSpy = jest.spyOn(router, 'navigate').mockImplementation();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AsyncPipe } from '@angular/common';
import {
ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit,
ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, signal,
} from '@angular/core';
import { MatButton } from '@angular/material/button';
import { MatCard } from '@angular/material/card';
Expand Down Expand Up @@ -74,6 +74,7 @@ export class CloudBackupCardComponent implements OnInit {
dataProvider: AsyncDataProvider<CloudBackup>;
readonly requiredRoles = [Role.CloudBackupWrite];
protected readonly searchableElements = replicationListElements;
updatedCount = signal(0);

columns = createTable<CloudBackup>([
textColumn({
Expand Down Expand Up @@ -228,15 +229,22 @@ export class CloudBackupCardComponent implements OnInit {
}

private onChangeEnabledState(cloudBackup: CloudBackup): void {
this.updatedCount.update((count) => count + 1);
this.api
.call('cloud_backup.update', [cloudBackup.id, { enabled: !cloudBackup.enabled } as CloudBackupUpdate])
.pipe(untilDestroyed(this))
.subscribe({
next: () => {
this.getCloudBackups();
this.updatedCount.update((count) => count - 1);
if (!this.updatedCount()) {
this.getCloudBackups();
}
},
error: (err: unknown) => {
this.getCloudBackups();
this.updatedCount.update((count) => count - 1);
if (!this.updatedCount()) {
this.getCloudBackups();
}
this.dialogService.error(this.errorHandler.parseError(err));
},
});
Expand Down

0 comments on commit 5a0a258

Please sign in to comment.