[Snapshots + Restore] Fix no snapshots prompt

This commit is contained in:
Alison Goryachev 2021-07-15 08:50:17 -04:00 committed by GitHub
parent 5fcdb9d137
commit 8ccf88e3e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 40 deletions

View file

@ -13,7 +13,6 @@ import {
setupEnvironment,
pageHelpers,
nextTick,
delay,
getRandomString,
findTestSubject,
} from './helpers';
@ -409,9 +408,9 @@ describe('<SnapshotRestoreHome />', () => {
await act(async () => {
testBed.actions.selectTab('snapshots');
await delay(100);
testBed.component.update();
});
testBed.component.update();
});
test('should display an empty prompt', () => {
@ -438,9 +437,8 @@ describe('<SnapshotRestoreHome />', () => {
await act(async () => {
testBed.actions.selectTab('snapshots');
await delay(2000);
testBed.component.update();
});
testBed.component.update();
});
test('should display an empty prompt', () => {
@ -477,9 +475,9 @@ describe('<SnapshotRestoreHome />', () => {
await act(async () => {
testBed.actions.selectTab('snapshots');
await delay(2000);
testBed.component.update();
});
testBed.component.update();
});
test('should list them in the table', async () => {

View file

@ -38,6 +38,7 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
const getLifecycleFn = router.getMockApiFn('slm.getLifecycle');
const getSnapshotFn = router.getMockApiFn('snapshot.get');
const deleteSnapshotFn = router.getMockApiFn('snapshot.delete');
const getRepoFn = router.getMockApiFn('snapshot.getRepository');
beforeAll(() => {
registerSnapshotsRoutes({
@ -59,7 +60,7 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
};
test('combines snapshots and their repositories returned from ES', async () => {
const mockSnapshotGetPolicyEsResponse = {
const mockGetPolicyEsResponse = {
fooPolicy: {},
};
@ -70,12 +71,22 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
],
};
getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse });
getLifecycleFn.mockResolvedValue({ body: mockSnapshotGetPolicyEsResponse });
getSnapshotFn.mockResolvedValueOnce({ body: mockGetSnapshotsResponse });
const mockGetRepositoryEsResponse = {
fooRepository: {},
barRepository: {},
// Test that there may be a repository that does not yet have any snapshots associated to it
bazRepository: {},
};
getClusterSettingsFn.mockResolvedValue({
body: mockSnapshotGetManagedRepositoryEsResponse,
});
getLifecycleFn.mockResolvedValue({ body: mockGetPolicyEsResponse });
getRepoFn.mockResolvedValue({ body: mockGetRepositoryEsResponse });
getSnapshotFn.mockResolvedValue({ body: mockGetSnapshotsResponse });
const expectedResponse = {
repositories: ['fooRepository', 'barRepository'],
repositories: ['fooRepository', 'barRepository', 'bazRepository'],
policies: ['fooPolicy'],
snapshots: [
{
@ -104,7 +115,7 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
});
test('returns an error object if ES request contains repository failures', async () => {
const mockSnapshotGetPolicyEsResponse = {
const mockGetPolicyEsResponse = {
fooPolicy: {},
};
@ -119,9 +130,16 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
},
};
getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse });
getLifecycleFn.mockResolvedValue({ body: mockSnapshotGetPolicyEsResponse });
getSnapshotFn.mockResolvedValueOnce({ body: mockGetSnapshotsResponse });
const mockGetRepositoryEsResponse = {
fooRepository: {},
};
getClusterSettingsFn.mockResolvedValue({
body: mockSnapshotGetManagedRepositoryEsResponse,
});
getLifecycleFn.mockResolvedValue({ body: mockGetPolicyEsResponse });
getRepoFn.mockResolvedValue({ body: mockGetRepositoryEsResponse });
getSnapshotFn.mockResolvedValue({ body: mockGetSnapshotsResponse });
const expectedResponse = {
repositories: ['fooRepository'],
@ -150,13 +168,12 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
expect(response).toEqual({ body: expectedResponse });
});
test('returns empty arrays if no snapshots returned from ES', async () => {
const mockSnapshotGetPolicyEsResponse = {};
const mockSnapshotGetRepositoryEsResponse = {};
getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse });
getLifecycleFn.mockResolvedValue({ body: mockSnapshotGetPolicyEsResponse });
getSnapshotFn.mockResolvedValue({ body: mockSnapshotGetRepositoryEsResponse });
test('returns empty arrays if no repositories returned from ES', async () => {
getClusterSettingsFn.mockResolvedValue({
body: mockSnapshotGetManagedRepositoryEsResponse,
});
getLifecycleFn.mockResolvedValue({ body: {} });
getRepoFn.mockResolvedValue({ body: {} });
const expectedResponse = {
snapshots: [],
@ -168,10 +185,33 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
expect(response).toEqual({ body: expectedResponse });
});
test('returns an empty snapshot array if no snapshots returned from ES', async () => {
const mockGetRepositoryEsResponse = {
fooRepository: {},
};
getClusterSettingsFn.mockResolvedValue({
body: mockSnapshotGetManagedRepositoryEsResponse,
});
getLifecycleFn.mockResolvedValue({ body: {} });
getRepoFn.mockResolvedValue({ body: mockGetRepositoryEsResponse });
getSnapshotFn.mockResolvedValue({ body: {} });
const expectedResponse = {
snapshots: [],
repositories: ['fooRepository'],
policies: [],
};
const response = await router.runRequest(mockRequest);
expect(response).toEqual({ body: expectedResponse });
});
test('throws if ES error', async () => {
getClusterSettingsFn.mockRejectedValueOnce(new Error());
getLifecycleFn.mockRejectedValueOnce(new Error());
getSnapshotFn.mockRejectedValueOnce(new Error());
getClusterSettingsFn.mockRejectedValue(new Error());
getLifecycleFn.mockRejectedValue(new Error());
getRepoFn.mockRejectedValue(new Error());
getSnapshotFn.mockRejectedValue(new Error());
await expect(router.runRequest(mockRequest)).rejects.toThrowError();
});
@ -197,12 +237,14 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
};
test('returns snapshot object with repository name if returned from ES', async () => {
const mockSnapshotGetEsResponse = {
const mockGetSnapshotEsResponse = {
snapshots: [{ snapshot, repository }],
};
getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse });
getSnapshotFn.mockResolvedValueOnce({ body: mockSnapshotGetEsResponse });
getClusterSettingsFn.mockResolvedValue({
body: mockSnapshotGetManagedRepositoryEsResponse,
});
getSnapshotFn.mockResolvedValue({ body: mockGetSnapshotEsResponse });
const expectedResponse = {
...defaultSnapshot,
@ -237,8 +279,10 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => {
],
};
getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse });
getSnapshotFn.mockResolvedValueOnce({ body: mockSnapshotGetEsResponse });
getClusterSettingsFn.mockResolvedValue({
body: mockSnapshotGetManagedRepositoryEsResponse,
});
getSnapshotFn.mockResolvedValue({ body: mockSnapshotGetEsResponse });
await expect(router.runRequest(mockRequest)).resolves.toEqual({
body: 'Snapshot not found',

View file

@ -37,6 +37,25 @@ export function registerSnapshotsRoutes({
// Silently swallow error as policy names aren't required in UI
}
let repositories: string[] = [];
try {
const {
body: repositoriesByName,
} = await clusterClient.asCurrentUser.snapshot.getRepository({
repository: '_all',
});
repositories = Object.keys(repositoriesByName);
if (repositories.length === 0) {
return res.ok({
body: { snapshots: [], repositories: [], policies },
});
}
} catch (e) {
return handleEsError({ error: e, response: res });
}
try {
// If any of these repositories 504 they will cost the request significant time.
const { body: fetchedSnapshots } = await clusterClient.asCurrentUser.snapshot.get({
@ -51,24 +70,16 @@ export function registerSnapshotsRoutes({
size: SNAPSHOT_LIST_MAX_SIZE,
});
const allRepos: string[] = [];
// Decorate each snapshot with the repository with which it's associated.
const snapshots = fetchedSnapshots?.snapshots?.map((snapshot) => {
// @ts-expect-error @elastic/elasticsearch "repository" is a new field in the response
allRepos.push(snapshot.repository);
return deserializeSnapshotDetails(snapshot as SnapshotDetailsEs, managedRepository);
});
const uniqueRepos = allRepos.filter((repo, index) => {
return allRepos.indexOf(repo) === index;
});
return res.ok({
body: {
snapshots: snapshots || [],
policies,
repositories: uniqueRepos,
repositories,
// @ts-expect-error @elastic/elasticsearch "failures" is a new field in the response
errors: fetchedSnapshots?.failures,
},