Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fleet] added cardinality agg when counting acks in action_status #141651

Merged
merged 5 commits into from
Sep 26, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -0,0 +1,316 @@
/*
* 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 from 'react';
import { act, render, fireEvent } from '@testing-library/react';
// eslint-disable-next-line @kbn/eslint/module_migration
import { IntlProvider } from 'react-intl';

import { useActionStatus } from '../hooks';
import { useGetAgentPolicies, useStartServices } from '../../../../hooks';

import { AgentActivityFlyout } from './agent_activity_flyout';

jest.mock('../hooks');
jest.mock('../../../../hooks');

const mockUseActionStatus = useActionStatus as jest.Mock;
const mockUseGetAgentPolicies = useGetAgentPolicies as jest.Mock;
const mockUseStartServices = useStartServices as jest.Mock;

describe('AgentActivityFlyout', () => {
const mockOnClose = jest.fn();
const mockOnAbortSuccess = jest.fn();
const mockAbortUpgrade = jest.fn();

beforeEach(() => {
mockOnClose.mockReset();
mockOnAbortSuccess.mockReset();
mockAbortUpgrade.mockReset();
mockUseActionStatus.mockReset();
mockUseGetAgentPolicies.mockReturnValue({
data: {
items: [
{ id: 'policy1', name: 'Policy 1' },
{ id: 'policy2', name: 'Policy 2' },
],
},
});
mockUseStartServices.mockReturnValue({
docLinks: { links: { fleet: { upgradeElasticAgent: 'https://elastic.co' } } },
});
});

beforeEach(() => {
jest.useFakeTimers('modern').setSystemTime(new Date('2022-09-15T10:00:00.000Z'));
});

afterEach(() => {
jest.useRealTimers();
});

const renderComponent = () => {
return render(
<IntlProvider timeZone="UTC" locale="en">
<AgentActivityFlyout
onClose={mockOnClose}
onAbortSuccess={mockOnAbortSuccess}
refreshAgentActivity={false}
/>
</IntlProvider>
);
};

it('should render agent activity for in progress upgrade', () => {
const mockActionStatuses = [
{
actionId: 'action2',
nbAgentsActionCreated: 5,
nbAgentsAck: 0,
version: '8.5.0',
startTime: '2022-09-15T10:00:00.000Z',
type: 'UPGRADE',
nbAgentsActioned: 5,
status: 'IN_PROGRESS',
expiration: '2099-09-16T10:00:00.000Z',
creationTime: '2022-09-15T10:00:00.000Z',
nbAgentsFailed: 0,
},
];
mockUseActionStatus.mockReturnValue({
currentActions: mockActionStatuses,
abortUpgrade: mockAbortUpgrade,
isFirstLoading: true,
});
const result = renderComponent();

expect(result.getByText('Agent activity')).toBeInTheDocument();

expect(
result.container.querySelector('[data-test-subj="upgradeInProgressTitle"]')!.textContent
).toEqual('Upgrading 5 agents to version 8.5.0');
// compare without whitespace, &nbsp; doesn't match
expect(
result.container
.querySelector('[data-test-subj="upgradeInProgressDescription"]')!
.textContent?.replace(/\s/g, '')
).toContain('Started on Sep 15, 2022 10:00 AM. Learn more'.replace(/\s/g, ''));

act(() => {
fireEvent.click(result.getByText('Abort upgrade'));
});

expect(mockAbortUpgrade).toHaveBeenCalled();
});

it('should render agent activity for scheduled upgrade', () => {
const mockActionStatuses = [
{
actionId: 'action2',
nbAgentsActionCreated: 5,
nbAgentsAck: 0,
version: '8.5.0',
startTime: '2022-09-16T10:00:00.000Z',
type: 'UPGRADE',
nbAgentsActioned: 5,
status: 'IN_PROGRESS',
expiration: '2099-09-17T10:00:00.000Z',
creationTime: '2022-09-15T10:00:00.000Z',
nbAgentsFailed: 0,
},
];
mockUseActionStatus.mockReturnValue({
currentActions: mockActionStatuses,
abortUpgrade: mockAbortUpgrade,
isFirstLoading: true,
});
const result = renderComponent();

expect(result.getByText('Agent activity')).toBeInTheDocument();

expect(
result.container.querySelector('[data-test-subj="upgradeInProgressTitle"]')!.textContent
).toEqual('5 agents scheduled to upgrade to version 8.5.0');
expect(
result.container
.querySelector('[data-test-subj="upgradeInProgressDescription"]')!
.textContent?.replace(/\s/g, '')
).toContain('Scheduled for Sep 16, 2022 10:00 AM. Learn more'.replace(/\s/g, ''));

act(() => {
fireEvent.click(result.getByText('Abort upgrade'));
});

expect(mockAbortUpgrade).toHaveBeenCalled();
});

it('should render agent activity for complete upgrade', () => {
const mockActionStatuses = [
{
actionId: 'action3',
nbAgentsActionCreated: 2,
nbAgentsAck: 2,
type: 'UPGRADE',
nbAgentsActioned: 2,
status: 'COMPLETE',
expiration: '2099-09-16T10:00:00.000Z',
creationTime: '2022-09-15T10:00:00.000Z',
nbAgentsFailed: 0,
completionTime: '2022-09-15T12:00:00.000Z',
},
];
mockUseActionStatus.mockReturnValue({
currentActions: mockActionStatuses,
abortUpgrade: mockAbortUpgrade,
isFirstLoading: true,
});
const result = renderComponent();

expect(result.container.querySelector('[data-test-subj="statusTitle"]')!.textContent).toEqual(
'2 agents upgraded'
);
expect(
result.container
.querySelector('[data-test-subj="statusDescription"]')!
.textContent?.replace(/\s/g, '')
).toContain('Completed Sep 15, 2022 12:00 PM'.replace(/\s/g, ''));
});

it('should render agent activity for expired unenroll', () => {
const mockActionStatuses = [
{
actionId: 'action4',
nbAgentsActionCreated: 3,
nbAgentsAck: 0,
type: 'UNENROLL',
nbAgentsActioned: 3,
status: 'EXPIRED',
expiration: '2022-09-14T10:00:00.000Z',
creationTime: '2022-09-15T10:00:00.000Z',
nbAgentsFailed: 0,
},
];
mockUseActionStatus.mockReturnValue({
currentActions: mockActionStatuses,
abortUpgrade: mockAbortUpgrade,
isFirstLoading: true,
});
const result = renderComponent();

expect(result.container.querySelector('[data-test-subj="statusTitle"]')!.textContent).toEqual(
'Agent unenrollment expired'
);
expect(
result.container
.querySelector('[data-test-subj="statusDescription"]')!
.textContent?.replace(/\s/g, '')
).toContain('Expired on Sep 14, 2022 10:00 AM'.replace(/\s/g, ''));
});

it('should render agent activity for cancelled upgrade', () => {
const mockActionStatuses = [
{
actionId: 'action5',
nbAgentsActionCreated: 3,
nbAgentsAck: 0,
startTime: '2022-09-15T10:00:00.000Z',
type: 'UPGRADE',
nbAgentsActioned: 3,
status: 'CANCELLED',
expiration: '2099-09-16T10:00:00.000Z',
creationTime: '2022-09-15T10:00:00.000Z',
nbAgentsFailed: 0,
cancellationTime: '2022-09-15T11:00:00.000Z',
},
];
mockUseActionStatus.mockReturnValue({
currentActions: mockActionStatuses,
abortUpgrade: mockAbortUpgrade,
isFirstLoading: true,
});
const result = renderComponent();

expect(result.container.querySelector('[data-test-subj="statusTitle"]')!.textContent).toEqual(
'Agent upgrade cancelled'
);
expect(
result.container
.querySelector('[data-test-subj="statusDescription"]')!
.textContent?.replace(/\s/g, '')
).toContain('Cancelled on Sep 15, 2022 11:00 AM'.replace(/\s/g, ''));
});

it('should render agent activity for failed reassign', () => {
const mockActionStatuses = [
{
actionId: 'action7',
nbAgentsActionCreated: 1,
nbAgentsAck: 0,
type: 'POLICY_REASSIGN',
nbAgentsActioned: 1,
status: 'FAILED',
expiration: '2099-09-16T10:00:00.000Z',
newPolicyId: 'policy1',
creationTime: '2022-09-15T10:00:00.000Z',
nbAgentsFailed: 1,
completionTime: '2022-09-15T11:00:00.000Z',
},
];
mockUseActionStatus.mockReturnValue({
currentActions: mockActionStatuses,
abortUpgrade: mockAbortUpgrade,
isFirstLoading: true,
});
const result = renderComponent();

expect(result.container.querySelector('[data-test-subj="statusTitle"]')!.textContent).toEqual(
'0 of 1 agent assigned to a new policy'
);
expect(
result.container
.querySelector('[data-test-subj="statusDescription"]')!
.textContent?.replace(/\s/g, '')
).toContain(
'A problem occurred during this operation. Started on Sep 15, 2022 10:00 AM.'.replace(
/\s/g,
''
)
);
});

it('should render agent activity for unknown action', () => {
const mockActionStatuses = [
{
actionId: 'action8',
nbAgentsActionCreated: 3,
nbAgentsAck: 0,
type: 'UNKNOWN',
nbAgentsActioned: 3,
status: 'COMPLETE',
expiration: '2022-09-14T10:00:00.000Z',
creationTime: '2022-09-15T10:00:00.000Z',
completionTime: '2022-09-15T12:00:00.000Z',
nbAgentsFailed: 0,
},
];
mockUseActionStatus.mockReturnValue({
currentActions: mockActionStatuses,
abortUpgrade: mockAbortUpgrade,
isFirstLoading: true,
});
const result = renderComponent();

expect(result.container.querySelector('[data-test-subj="statusTitle"]')!.textContent).toEqual(
'0 of 3 agents actioned'
);
expect(
result.container
.querySelector('[data-test-subj="statusDescription"]')!
.textContent?.replace(/\s/g, '')
).toContain('Completed Sep 15, 2022 12:00 PM'.replace(/\s/g, ''));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export const AgentActivityFlyout: React.FunctionComponent<{
) : null}
{Object.keys(otherDays).map((day) => (
<ActivitySection
key={day}
title={<FormattedDate value={day} year="numeric" month="short" day="2-digit" />}
actions={otherDays[day]}
abortUpgrade={abortUpgrade}
Expand Down Expand Up @@ -215,9 +216,13 @@ const ActivitySection: React.FunctionComponent<{
</EuiPanel>
{actions.map((currentAction) =>
currentAction.type === 'UPGRADE' && currentAction.status === 'IN_PROGRESS' ? (
<UpgradeInProgressActivityItem action={currentAction} abortUpgrade={abortUpgrade} />
<UpgradeInProgressActivityItem
action={currentAction}
abortUpgrade={abortUpgrade}
key={currentAction.actionId}
/>
) : (
<ActivityItem action={currentAction} />
<ActivityItem action={currentAction} key={currentAction.actionId} />
)
)}
</>
Expand Down Expand Up @@ -272,7 +277,7 @@ const inProgressTitle = (action: ActionStatus) => (
defaultMessage="{inProgressText} {nbAgents} {agents} {reassignText}{upgradeText}"
values={{
nbAgents:
action.nbAgentsAck === action.nbAgentsActioned
action.nbAgentsAck >= action.nbAgentsActioned
? action.nbAgentsAck
: action.nbAgentsAck === 0
? action.nbAgentsActioned
Expand Down Expand Up @@ -438,14 +443,19 @@ const ActivityItem: React.FunctionComponent<{ action: ActionStatus }> = ({ actio
<EuiFlexGroup direction="row" gutterSize="m" alignItems="center">
<EuiFlexItem grow={false}>{displayByStatus[action.status].icon}</EuiFlexItem>
<EuiFlexItem>
<EuiText color={displayByStatus[action.status].titleColor}>
<EuiText
color={displayByStatus[action.status].titleColor}
data-test-subj="statusTitle"
>
{displayByStatus[action.status].title}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>
<EuiText color="subdued">{displayByStatus[action.status].description}</EuiText>
<EuiText color="subdued" data-test-subj="statusDescription">
{displayByStatus[action.status].description}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
Expand Down Expand Up @@ -486,7 +496,7 @@ export const UpgradeInProgressActivityItem: React.FunctionComponent<{
{isScheduled ? <EuiIcon type="clock" /> : <EuiLoadingSpinner size="m" />}
</EuiFlexItem>
<EuiFlexItem>
<EuiText color={inProgressTitleColor}>
<EuiText color={inProgressTitleColor} data-test-subj="upgradeInProgressTitle">
{isScheduled && action.startTime ? (
<FormattedMessage
id="xpack.fleet.agentActivityFlyout.scheduleTitle"
Expand All @@ -506,7 +516,7 @@ export const UpgradeInProgressActivityItem: React.FunctionComponent<{
<EuiFlexItem>
<EuiFlexGroup direction="column" alignItems="flexStart">
<EuiFlexItem>
<EuiText color="subdued">
<EuiText color="subdued" data-test-subj="upgradeInProgressDescription">
<p>
{isScheduled && action.startTime ? (
<>
Expand Down Expand Up @@ -541,7 +551,7 @@ export const UpgradeInProgressActivityItem: React.FunctionComponent<{
size="s"
onClick={onClickAbortUpgrade}
isLoading={isAborting}
data-test-subj="currentBulkUpgrade.abortBtn"
data-test-subj="abortBtn"
>
<FormattedMessage
id="xpack.fleet.agentActivityFlyout.abortUpgradeButtom"
Expand Down
Loading