Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -107,10 +107,7 @@ describe('Overview - Fix deprecation logs step', () => {

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 +148,105 @@ 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 { find, exists, component } = testBed;

component.update();

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

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

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

component.update();

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 { find, exists, component } = testBed;

component.update();

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

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

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

component.update();

expect(exists('noWarningsCallout')).toBe(true);
});
});
});
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"],
"optionalPlugins": ["usageCollection", "cloud"],
"requiredBundles": ["esUiShared", "kibanaReact"]
"requiredBundles": ["esUiShared", "kibanaReact", "kibanaUtils"]
}
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 { VerifyChanges } from './verify_changes';
import { useDeprecationLogging } from './use_deprecation_logging';
import { DeprecationLoggingToggle } from './deprecation_logging_toggle';

Expand All @@ -25,6 +26,9 @@ const i18nTexts = {
analyzeTitle: i18n.translate('xpack.upgradeAssistant.overview.analyzeTitle', {
defaultMessage: 'Analyze deprecation logs',
}),
verifyChangesTitle: i18n.translate('xpack.upgradeAssistant.overview.verifyChangesTitle', {
defaultMessage: 'Resolve deprecation issues and verify your changes',
}),
onlyLogWritingEnabledTitle: i18n.translate(
'xpack.upgradeAssistant.overview.deprecationLogs.deprecationWarningTitle',
{
Expand Down Expand Up @@ -75,6 +79,13 @@ const FixLogsStep: FunctionComponent = () => {
</EuiText>
<EuiSpacer size="m" />
<ExternalLinks />

<EuiSpacer size="xl" />
<EuiText>
<h4>{i18nTexts.verifyChangesTitle}</h4>
</EuiText>
<EuiSpacer size="m" />
<VerifyChanges />
</>
)}
</>
Expand Down
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 { VerifyChanges } from './verify_changes';
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* 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 useInterval from 'react-use/lib/useInterval';
import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n/react';

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

const POLLING_INTERVAL = 60000;
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 VerifyChanges: FunctionComponent = () => {
const { api } = useAppContext();
const [previousCheck, setPreviousCheck] = useState(getPreviousCheckpointDate());
const { data, error, isLoading, resendRequest } = 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';

useInterval(() => {
resendRequest();
}, POLLING_INTERVAL);

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

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

if (!data && isLoading) {
return (
<EuiFlexGroup>
<EuiFlexItem>
<EuiLoadingContent lines={6} />
</EuiFlexItem>
</EuiFlexGroup>
);
}

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="errorResetButton">
{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>
);
};
10 changes: 10 additions & 0 deletions x-pack/plugins/upgrade_assistant/public/application/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ export class ApiService {
return result;
}

public getDeprecationLogsCount(from: string) {
return this.useRequest<{
count: number;
}>({
path: `${API_BASE_PATH}/deprecation_logging/count`,
method: 'get',
query: { from },
});
}

public async updateIndexSettings(indexName: string, settings: string[]) {
const result = await this.sendRequest({
path: `${API_BASE_PATH}/${indexName}/index_settings`,
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/upgrade_assistant/public/shared_imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export {
GlobalFlyout,
} from '../../../../src/plugins/es_ui_shared/public/';

export { Storage } from '../../../../src/plugins/kibana_utils/public';

export { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public';

export { DataPublicPluginStart } from '../../../../src/plugins/data/public';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
export const createRequestMock = (opts?: {
headers?: any;
params?: Record<string, any>;
query?: Record<string, any>;
body?: Record<string, any>;
}) => {
return Object.assign({ headers: {} }, opts || {});
Expand Down
Loading