Skip to content

Commit

Permalink
[Upgrade Assistant] Add checkpoint feature to Overview page (elastic#…
Browse files Browse the repository at this point in the history
  • Loading branch information
sabarasaba committed Oct 26, 2021
1 parent 2aefe8c commit c9aa4fc
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
]);
};

const setLoadDeprecationLogsCountResponse = (
response?: { count: number },
error?: ResponseError
) => {
const status = error ? error.statusCode || 400 : 200;
const body = error ? error : response;

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

const setUpdateDeprecationLoggingResponse = (
response?: DeprecationLoggingStatus,
error?: ResponseError
Expand Down Expand Up @@ -102,6 +116,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
setUpgradeMlSnapshotResponse,
setDeleteMlSnapshotResponse,
setUpgradeMlSnapshotStatusResponse,
setLoadDeprecationLogsCountResponse,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,29 @@ describe('Overview - Fix deprecation logs step', () => {

expect(exists('fetchLoggingError')).toBe(true);
});

test('It doesnt show external links and deprecations count when toggle is disabled', async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: false,
isDeprecationLoggingEnabled: false,
});

await act(async () => {
testBed = await setupOverviewPage();
});

const { exists, component } = testBed;

component.update();

expect(exists('externalLinksTitle')).toBe(false);
expect(exists('deprecationsCountTitle')).toBe(false);
});
});

describe('Step 2 - Analyze logs', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({
isDeprecationLogIndexingEnabled: true,
isDeprecationLoggingEnabled: true,
});
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
});

test('Has a link to see logs in observability app', async () => {
Expand Down Expand Up @@ -151,4 +166,97 @@ describe('Overview - Fix deprecation logs step', () => {
expect(find('viewDiscoverLogs').props().href).toBe('/discover/logs');
});
});

describe('Step 3 - Resolve log issues', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadDeprecationLoggingResponse(getLoggingResponse(true));
});

test('With deprecation warnings', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});

await act(async () => {
testBed = await setupOverviewPage();
});

const { find, exists, component } = testBed;

component.update();

expect(exists('hasWarningsCallout')).toBe(true);
expect(find('hasWarningsCallout').text()).toContain('10');
});

test('No deprecation warnings', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 0,
});

await act(async () => {
testBed = await setupOverviewPage();
});

const { find, exists, component } = testBed;

component.update();

expect(exists('noWarningsCallout')).toBe(true);
expect(find('noWarningsCallout').text()).toContain('No deprecation warnings');
});

test('Handles errors and can retry', async () => {
const error = {
statusCode: 500,
error: 'Internal server error',
message: 'Internal server error',
};

httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse(undefined, error);

await act(async () => {
testBed = await setupOverviewPage();
});

const { exists, actions, component } = testBed;

component.update();

expect(exists('errorCallout')).toBe(true);

httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 0,
});

await actions.clickRetryButton();

expect(exists('noWarningsCallout')).toBe(true);
});

test('Allows user to reset last stored date', async () => {
httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 10,
});

await act(async () => {
testBed = await setupOverviewPage();
});

const { exists, actions, component } = testBed;

component.update();

expect(exists('hasWarningsCallout')).toBe(true);
expect(exists('resetLastStoredDate')).toBe(true);

httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({
count: 0,
});

await actions.clickResetButton();

expect(exists('noWarningsCallout')).toBe(true);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,30 @@ const createActions = (testBed: TestBed) => {
component.update();
};

const clickRetryButton = async () => {
const { find, component } = testBed;

await act(async () => {
find('retryButton').simulate('click');
});

component.update();
};

const clickResetButton = async () => {
const { find, component } = testBed;

await act(async () => {
find('resetLastStoredDate').simulate('click');
});

component.update();
};

return {
clickDeprecationToggle,
clickRetryButton,
clickResetButton,
};
};

Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/upgrade_assistant/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ export const API_BASE_PATH = '/api/upgrade_assistant';

export const DEPRECATION_WARNING_UPPER_LIMIT = 999999;
export const DEPRECATION_LOGS_SOURCE_ID = 'deprecation_logs';
export const DEPRECATION_LOGS_INDEX = '.logs-deprecation.elasticsearch-default';
export const DEPRECATION_LOGS_INDEX_PATTERN = '.logs-deprecation.elasticsearch-default';

export const DEPRECATION_LOGS_COUNT_POLL_INTERVAL_MS = 60000;
2 changes: 1 addition & 1 deletion x-pack/plugins/upgrade_assistant/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"configPath": ["xpack", "upgrade_assistant"],
"requiredPlugins": ["management", "discover", "data", "licensing", "features", "infra", "share"],
"optionalPlugins": ["usageCollection", "cloud"],
"requiredBundles": ["esUiShared", "kibanaReact"]
"requiredBundles": ["esUiShared", "kibanaReact", "kibanaUtils"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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 React, { FunctionComponent, useState } from 'react';
import moment from 'moment-timezone';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n/react';

import { i18n } from '@kbn/i18n';
import { EuiCallOut, EuiButton, EuiLoadingContent } from '@elastic/eui';
import { useAppContext } from '../../../../app_context';
import { Storage } from '../../../../../shared_imports';

const LS_SETTING_ID = 'kibana.upgradeAssistant.lastCheckpoint';
const localStorage = new Storage(window.localStorage);

const i18nTexts = {
calloutTitle: (warningsCount: number, previousCheck: string) => (
<FormattedMessage
id="xpack.upgradeAssistant.overview.verifyChanges.calloutTitle"
defaultMessage="{warningsCount, plural, =0 {No} other {{warningsCount}}} deprecation {warningsCount, plural, one {warning} other {warnings}} since {previousCheck}"
values={{
warningsCount,
previousCheck: (
<>
<FormattedDate value={previousCheck} year="numeric" month="long" day="2-digit" />{' '}
<FormattedTime value={previousCheck} timeZoneName="short" hour12={false} />
</>
),
}}
/>
),
calloutBody: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.calloutBody', {
defaultMessage:
'Reset the counter after making changes and continue monitoring to verify that you are no longer using deprecated APIs.',
}),
loadingError: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.loadingError', {
defaultMessage: 'An error occurred while retrieving the count of deprecation logs',
}),
retryButton: i18n.translate('xpack.upgradeAssistant.overview.verifyChanges.retryButton', {
defaultMessage: 'Try again',
}),
resetCounterButton: i18n.translate(
'xpack.upgradeAssistant.overview.verifyChanges.resetCounterButton',
{
defaultMessage: 'Reset counter',
}
),
};

const getPreviousCheckpointDate = () => {
const storedValue = moment(localStorage.get(LS_SETTING_ID));

if (storedValue.isValid()) {
return storedValue.toISOString();
}

const now = moment().toISOString();
localStorage.set(LS_SETTING_ID, now);

return now;
};

export const DeprecationsCountCheckpoint: FunctionComponent = () => {
const { api } = useAppContext();
const [previousCheck, setPreviousCheck] = useState(getPreviousCheckpointDate());
const { data, error, isLoading, resendRequest, isInitialRequest } = api.getDeprecationLogsCount(
previousCheck
);

const warningsCount = data?.count || 0;
const calloutTint = warningsCount > 0 ? 'warning' : 'success';
const calloutIcon = warningsCount > 0 ? 'alert' : 'check';
const calloutTestId = warningsCount > 0 ? 'hasWarningsCallout' : 'noWarningsCallout';

const onResetClick = () => {
const now = moment().toISOString();

setPreviousCheck(now);
localStorage.set(LS_SETTING_ID, now);
};

if (isInitialRequest && isLoading) {
return <EuiLoadingContent lines={6} />;
}

if (error) {
return (
<EuiCallOut
title={i18nTexts.loadingError}
color="danger"
iconType="alert"
data-test-subj="errorCallout"
>
<p>
{error.statusCode} - {error.message}
</p>
<EuiButton color="danger" onClick={resendRequest} data-test-subj="retryButton">
{i18nTexts.retryButton}
</EuiButton>
</EuiCallOut>
);
}

return (
<EuiCallOut
title={i18nTexts.calloutTitle(warningsCount, previousCheck)}
color={calloutTint}
iconType={calloutIcon}
data-test-subj={calloutTestId}
>
<p>{i18nTexts.calloutBody}</p>
<EuiButton color={calloutTint} onClick={onResetClick} data-test-subj="resetLastStoredDate">
{i18nTexts.resetCounterButton}
</EuiButton>
</EuiCallOut>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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.
*/

export { DeprecationsCountCheckpoint } from './deprecations_count_checkpoint';
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { EuiText, EuiSpacer, EuiPanel, EuiCallOut } from '@elastic/eui';
import type { EuiStepProps } from '@elastic/eui/src/components/steps/step';

import { ExternalLinks } from './external_links';
import { DeprecationsCountCheckpoint } from './deprecations_count_checkpoint';
import { useDeprecationLogging } from './use_deprecation_logging';
import { DeprecationLoggingToggle } from './deprecation_logging_toggle';

Expand All @@ -25,6 +26,12 @@ const i18nTexts = {
analyzeTitle: i18n.translate('xpack.upgradeAssistant.overview.analyzeTitle', {
defaultMessage: 'Analyze deprecation logs',
}),
deprecationsCountCheckpointTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle',
{
defaultMessage: 'Resolve deprecation issues and verify your changes',
}
),
onlyLogWritingEnabledTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningTitle',
{
Expand Down Expand Up @@ -70,11 +77,18 @@ const FixLogsStep: FunctionComponent = () => {
{state.isDeprecationLogIndexingEnabled && (
<>
<EuiSpacer size="xl" />
<EuiText>
<EuiText data-test-subj="externalLinksTitle">
<h4>{i18nTexts.analyzeTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<ExternalLinks />

<EuiSpacer size="xl" />
<EuiText data-test-subj="deprecationsCountTitle">
<h4>{i18nTexts.deprecationsCountCheckpointTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<DeprecationsCountCheckpoint />
</>
)}
</>
Expand Down
Loading

0 comments on commit c9aa4fc

Please sign in to comment.