Skip to content

Commit

Permalink
[Snapshots + Restore] Fix no snapshots prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
alisonelizabeth authored Jul 15, 2021
1 parent 5fcdb9d commit 8ccf88e
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
setupEnvironment,
pageHelpers,
nextTick,
delay,
getRandomString,
findTestSubject,
} from './helpers';
Expand Down Expand Up @@ -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', () => {
Expand All @@ -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', () => {
Expand Down Expand Up @@ -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 () => {
Expand Down
92 changes: 68 additions & 24 deletions x-pack/plugins/snapshot_restore/server/routes/api/snapshots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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: {},
};

Expand All @@ -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: [
{
Expand Down Expand Up @@ -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: {},
};

Expand All @@ -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'],
Expand Down Expand Up @@ -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: [],
Expand All @@ -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();
});
Expand All @@ -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,
Expand Down Expand Up @@ -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',
Expand Down
29 changes: 20 additions & 9 deletions x-pack/plugins/snapshot_restore/server/routes/api/snapshots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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,
},
Expand Down

0 comments on commit 8ccf88e

Please sign in to comment.