Skip to content

Commit

Permalink
Add tests for UA back up data step on Cloud (#111066)
Browse files Browse the repository at this point in the history
  • Loading branch information
cjcenizal authored Sep 6, 2021
1 parent 55e2488 commit de66029
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,29 @@

import sinon, { SinonFakeServer } from 'sinon';
import { API_BASE_PATH } from '../../../common/constants';
import { ESUpgradeStatus, DeprecationLoggingStatus } from '../../../common/types';
import {
CloudBackupStatus,
ESUpgradeStatus,
DeprecationLoggingStatus,
} from '../../../common/types';
import { ResponseError } from '../../../public/application/lib/api';

// Register helpers to mock HTTP Requests
const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
const setLoadCloudBackupStatusResponse = (
response?: CloudBackupStatus,
error?: ResponseError
) => {
const status = error ? error.statusCode || 400 : 200;
const body = error ? error : response;

server.respondWith('GET', `${API_BASE_PATH}/cloud_backup_status`, [
status,
{ 'Content-Type': 'application/json' },
JSON.stringify(body),
]);
};

const setLoadEsDeprecationsResponse = (response?: ESUpgradeStatus, error?: ResponseError) => {
const status = error ? error.statusCode || 400 : 200;
const body = error ? error : response;
Expand Down Expand Up @@ -109,6 +127,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
};

return {
setLoadCloudBackupStatusResponse,
setLoadEsDeprecationsResponse,
setLoadDeprecationLoggingResponse,
setUpdateDeprecationLoggingResponse,
Expand All @@ -131,8 +150,19 @@ export const init = () => {

const httpRequestsMockHelpers = registerHttpRequestMockHelpers(server);

const setServerAsync = (isAsync: boolean, timeout: number = 200) => {
if (isAsync) {
server.autoRespond = true;
server.autoRespondAfter = 1000;
server.respondImmediately = false;
} else {
server.respondImmediately = true;
}
};

return {
server,
setServerAsync,
httpRequestsMockHelpers,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import { AppContextProvider } from '../../../public/application/app_context';
import { apiService } from '../../../public/application/lib/api';
import { breadcrumbService } from '../../../public/application/lib/breadcrumbs';
import { GlobalFlyout } from '../../../public/shared_imports';
import { AppDependencies } from '../../../public/types';
import { getAppContextMock } from './app_context.mock';
import { init as initHttpRequests } from './http_requests';
import { AppDependencies } from '../../../public/types';

const { GlobalFlyoutProvider } = GlobalFlyout;

Expand All @@ -43,10 +43,11 @@ export const WithAppDependencies = (Comp: any, overrides: Record<string, unknown
};

export const setupEnvironment = () => {
const { server, httpRequestsMockHelpers } = initHttpRequests();
const { server, setServerAsync, httpRequestsMockHelpers } = initHttpRequests();

return {
server,
setServerAsync,
httpRequestsMockHelpers,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,139 @@
* 2.0.
*/

import { act } from 'react-dom/test-utils';

import { setupEnvironment } from '../../helpers';
import { OverviewTestBed, setupOverviewPage } from '../overview.helpers';

describe('Overview - Backup Step', () => {
let testBed: OverviewTestBed;
const { server } = setupEnvironment();
let server: ReturnType<typeof setupEnvironment>['server'];
let setServerAsync: ReturnType<typeof setupEnvironment>['setServerAsync'];
let httpRequestsMockHelpers: ReturnType<typeof setupEnvironment>['httpRequestsMockHelpers'];

beforeEach(async () => {
testBed = await setupOverviewPage();
testBed.component.update();
beforeEach(() => {
({ server, setServerAsync, httpRequestsMockHelpers } = setupEnvironment());
});

afterAll(() => {
afterEach(() => {
server.restore();
});

describe('On-prem', () => {
beforeEach(async () => {
testBed = await setupOverviewPage();
});

test('Shows link to Snapshot and Restore', () => {
const { exists, find } = testBed;
expect(exists('snapshotRestoreLink')).toBe(true);
expect(find('snapshotRestoreLink').props().href).toBe('snapshotAndRestoreUrl');
});
});

describe('On Cloud', () => {
const setupCloudOverviewPage = async () =>
setupOverviewPage({
plugins: {
cloud: {
isCloudEnabled: true,
deploymentUrl: 'deploymentUrl',
},
},
});

describe('initial loading state', () => {
beforeEach(async () => {
// We don't want the request to load backup status to resolve immediately.
setServerAsync(true);
testBed = await setupCloudOverviewPage();
});

afterEach(() => {
setServerAsync(false);
});

test('is rendered', () => {
const { exists } = testBed;
expect(exists('cloudBackupLoading')).toBe(true);
});
});

describe('error state', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadCloudBackupStatusResponse(undefined, {
statusCode: 400,
message: 'error',
});

testBed = await setupCloudOverviewPage();
});

test('is rendered', () => {
const { exists } = testBed;
testBed.component.update();
expect(exists('cloudBackupErrorCallout')).toBe(true);
});

test('lets the user attempt to reload backup status', () => {
const { exists } = testBed;
testBed.component.update();
expect(exists('cloudBackupRetryButton')).toBe(true);
});
});

describe('success state', () => {
describe('when data is backed up', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadCloudBackupStatusResponse({
isBackedUp: true,
lastBackupTime: '2021-08-25T19:59:59.863Z',
});

testBed = await setupCloudOverviewPage();
});

test('renders link to Cloud backups and last backup time ', () => {
const { exists, find } = testBed;
expect(exists('dataBackedUpStatus')).toBe(true);
expect(exists('cloudSnapshotsLink')).toBe(true);
expect(find('dataBackedUpStatus').text()).toContain('Last snapshot created on');
});
});

describe(`when data isn't backed up`, () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadCloudBackupStatusResponse({
isBackedUp: false,
lastBackupTime: undefined,
});

testBed = await setupCloudOverviewPage();
});

test('renders link to Cloud backups and "not backed up" status', () => {
const { exists } = testBed;
expect(exists('dataNotBackedUpStatus')).toBe(true);
expect(exists('cloudSnapshotsLink')).toBe(true);
});
});

test('polls for new status', async () => {
// The behavior we're testing involves state changes over time, so we need finer control over
// timing.
jest.useFakeTimers();
testBed = await setupCloudOverviewPage();
expect(server.requests.length).toBe(4);

// Resolve the polling timeout.
await act(async () => {
jest.runAllTimers();
});

expect(server.requests.length).toBe(5);
jest.useRealTimers();
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const CloudBackup: React.FunctionComponent<Props> = ({
const { isInitialRequest, isLoading, error, data, resendRequest } = cloudBackupStatusResponse;

if (isInitialRequest && isLoading) {
return <EuiLoadingContent lines={3} />;
return <EuiLoadingContent data-test-subj="cloudBackupLoading" lines={3} />;
}

if (error) {
Expand Down Expand Up @@ -66,7 +66,7 @@ export const CloudBackup: React.FunctionComponent<Props> = ({
const lastBackupTime = moment(data!.lastBackupTime).toISOString();

const statusMessage = data!.isBackedUp ? (
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexGroup alignItems="center" gutterSize="s" data-test-subj="dataBackedUpStatus">
<EuiFlexItem grow={false}>
<EuiIcon type="check" color="success" />
</EuiFlexItem>
Expand Down Expand Up @@ -96,7 +96,7 @@ export const CloudBackup: React.FunctionComponent<Props> = ({
</EuiFlexItem>
</EuiFlexGroup>
) : (
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexGroup alignItems="center" gutterSize="s" data-test-subj="dataNotBackedUpStatus">
<EuiFlexItem grow={false}>
<EuiIcon type="alert" color="danger" />
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import expect from '@kbn/expect';

import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const es = getService('es');

const CLOUD_SNAPSHOT_REPOSITORY = 'found-snapshots';

const createCloudRepository = () => {
return es.snapshot
.createRepository({
repository: CLOUD_SNAPSHOT_REPOSITORY,
body: {
type: 'fs',
settings: {
location: '/tmp/cloud-snapshots/',
},
},
verify: false,
})
.then(({ body }) => body);
};

const createCloudSnapshot = (snapshotName: string) => {
return es.snapshot.create({
repository: CLOUD_SNAPSHOT_REPOSITORY,
snapshot: snapshotName,
wait_for_completion: true,
// Configure snapshot so no indices are captured, so the request completes ASAP.
body: {
indices: 'this_index_doesnt_exist',
ignore_unavailable: true,
include_global_state: false,
},
});
};

const deleteCloudSnapshot = (snapshotName: string) => {
return es.snapshot.delete({
repository: CLOUD_SNAPSHOT_REPOSITORY,
snapshot: snapshotName,
});
};

describe('Cloud backup status', () => {
describe('get', () => {
describe('with backups present', () => {
// Needs SnapshotInfo type https://github.com/elastic/elasticsearch-specification/issues/685
let mostRecentSnapshot: any;

before(async () => {
await createCloudRepository();
await createCloudSnapshot('test_snapshot_1');
mostRecentSnapshot = (await createCloudSnapshot('test_snapshot_2')).body.snapshot;
});

after(async () => {
await deleteCloudSnapshot('test_snapshot_1');
await deleteCloudSnapshot('test_snapshot_2');
});

it('returns status based on most recent snapshot', async () => {
const { body: cloudBackupStatus } = await supertest
.get('/api/upgrade_assistant/cloud_backup_status')
.set('kbn-xsrf', 'xxx')
.expect(200);

expect(cloudBackupStatus.isBackedUp).to.be(true);
expect(cloudBackupStatus.lastBackupTime).to.be(mostRecentSnapshot.start_time);
});
});

describe('without backups present', () => {
it('returns not-backed-up status', async () => {
const { body: cloudBackupStatus } = await supertest
.get('/api/upgrade_assistant/cloud_backup_status')
.set('kbn-xsrf', 'xxx')
.expect(200);

expect(cloudBackupStatus.isBackedUp).to.be(false);
expect(cloudBackupStatus.lastBackupTime).to.be(undefined);
});
});
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ import { FtrProviderContext } from '../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('Upgrade Assistant', () => {
loadTestFile(require.resolve('./upgrade_assistant'));
loadTestFile(require.resolve('./cloud_backup_status'));
});
}

0 comments on commit de66029

Please sign in to comment.