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

feat(OCPADVISOR-71): Show upgrade risks table #547

Merged
merged 11 commits into from
Apr 18, 2023
2 changes: 1 addition & 1 deletion compiled-lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
"undefined": "Undefined",
"unknown": "Unknown",
"upgradeRisks": "Upgrade risks",
"upgradeRisksNotAvailable": "Upgrade Risks are not available",
"upgradeRisksNotAvailable": "Upgrade risks are not available",
"upgradeRisksNotAvailableDesc": "This cluster has gone more than two hours without sending metrics. Check the cluster's web console if you think that this is incorrect.",
"version": "Version",
"veryLow": "Very Low",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"status": "ok",
"upgrade_recommendation": {
"upgrade_risks_predictors": {
"alerts": [
{
"name": "ClusterOperatorDown",
"namespace": "openshift-monitoring",
"severity": "critical"
},
{
"name": "PostDisruptionBudgetLimit",
"namespace": "openshift-etcd",
"severity": "warning"
},
{
"name": "Cluster operators",
"namespace": "openshift-kube-apiserver",
"severity": "info"
}
],
"operator_conditions": [
{
"name": "Version",
"condition": "failing"
},
{
"name": "Node-tuning",
"condition": "degraded",
"reason": "Multiple tasks failed"
}
]
}
}
}
2 changes: 1 addition & 1 deletion src/Components/ClusterTabs/ClusterTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const ClusterTabs = () => {
});

return (
<Card isCompact>
<Card isCompact isPlain>
<CardBody>
<Tabs
activeKey={activeKey}
Expand Down
8 changes: 5 additions & 3 deletions src/Components/UpgradeRisksTable/AlertsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ const AlertsList = () => {
<Tbody>
{alerts.map(({ name, namespace, severity }) => (
<Tr key={name}>
<Td>{name}</Td>
<Td>{ALERTS_SEVERITY_LABEL[severity]}</Td>
<Td>{namespace}</Td>
<Td className="alerts__name">{name}</Td>
<Td className="alerts__severity">
{ALERTS_SEVERITY_LABEL[severity]}
</Td>
<Td className="alerts__namespace">{namespace}</Td>
</Tr>
))}
</Tbody>
Expand Down
6 changes: 3 additions & 3 deletions src/Components/UpgradeRisksTable/ClusterOperatorsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ const ClusterOperatorsList = () => {
<Tbody>
{conditions.map(({ name, condition, reason }) => (
<Tr key={name}>
<Td>{name}</Td>
<Td>
<Td class="operators__name">{name}</Td>
<Td class="operators__status">
<Flex alignItems={{ default: 'alignItemsCenter' }}>
<Icon status="warning">
<ExclamationTriangleIcon />
</Icon>
<b>{CLUSTER_OPERATOR_LABEL[condition]}</b>
</Flex>
</Td>
<Td>{reason || '-'}</Td>
<Td class="operators__message">{reason || '-'}</Td>
</Tr>
))}
</Tbody>
Expand Down
277 changes: 277 additions & 0 deletions src/Components/UpgradeRisksTable/UpgradeRisksTable.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
import React from 'react';
import upgradeRisksFixtures from '../../../cypress/fixtures/api/insights-results-aggregator/v1/clusters/41c30565-b4c9-49f2-a4ce-3277ad22b258/upgrade-risks-prediction.json';
import { TABLE_HEADER } from '../../../cypress/utils/components';
import {
checkEmptyState,
checkTableHeaders,
} from '../../../cypress/utils/table';
import UpgradeRisksTable from './UpgradeRisksTable';

const SEVERITY_MAPPING = {
ikerreyes marked this conversation as resolved.
Show resolved Hide resolved
critical: 'Critical',
warning: 'Warning',
info: 'Info',
};

const SEVERITY_ICON_CLASS_MAPPING = {
critical: 'danger',
warning: 'warning',
info: 'info',
};

export const CLUSTER_OPERATOR_LABEL_MAPPING = {
degraded: 'Degraded',
failing: 'Failing',
available: 'Not Available',
upgradeable: 'Not Upgradeable',
};

const interceptors = {
successful: () =>
cy.intercept(
'GET',
/\/api\/insights-results-aggregator\/v1\/cluster\/.*\/upgrade-risks-prediction/,
{
statusCode: 200,
body: upgradeRisksFixtures,
}
),
'successful, alerts empty': () => {
const fixtures = upgradeRisksFixtures;
fixtures.upgrade_recommendation.upgrade_risks_predictors.alerts = [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will not this modify the inner object for any subsequent uses? Don't we need a copy?

cy.intercept(
'GET',
/\/api\/insights-results-aggregator\/v1\/cluster\/.*\/upgrade-risks-prediction/,
{
statusCode: 200,
body: fixtures,
}
);
},
'successful, empty': () => {
const fixtures = upgradeRisksFixtures;
fixtures.upgrade_recommendation.upgrade_risks_predictors = {
alerts: [],
operator_conditions: [],
};
cy.intercept(
'GET',
/\/api\/insights-results-aggregator\/v1\/cluster\/.*\/upgrade-risks-prediction/,
{
statusCode: 200,
body: fixtures,
}
);
},
'error, not available': () =>
cy.intercept(
'GET',
/\/api\/insights-results-aggregator\/v1\/cluster\/.*\/upgrade-risks-prediction/,
{
statusCode: 503,
}
),
'error, other': () =>
cy.intercept(
'GET',
/\/api\/insights-results-aggregator\/v1\/cluster\/.*\/upgrade-risks-prediction/,
{
statusCode: 500,
}
),
'long responding': () =>
cy.intercept(
'GET',
/\/api\/insights-results-aggregator\/v1\/cluster\/.*\/upgrade-risks-prediction/,
{
delay: 420000,
}
),
};

const CLUSTER_ID = '41c30565-b4c9-49f2-a4ce-3277ad22b258';

const mount = (initialEntries = [`/clusters/${CLUSTER_ID}`]) => {
cy.mountWithContext(<UpgradeRisksTable />, {
path: '/clusters/:clusterId',
routerProps: { initialEntries },
});
};

const TABLE_ROW = '[data-ouia-component-type="PF4/TableRow"]';

describe('successful with some risks', () => {
beforeEach(() => {
interceptors.successful();
mount();
});

it('renders main headers', () => {
cy.get('#upgrade-risks-table');
cy.get(TABLE_HEADER).contains('Name');
cy.get(TABLE_ROW).contains('Alerts firing');
cy.get(TABLE_ROW).contains('Cluster operators');
});

it('shows correct risks number', () => {
cy.get('#alerts-label').should(
'have.text',
`${upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors.alerts.length} upgrade risks`
);
cy.get('#operator-conditions-label').should(
'have.text',
`${upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors.operator_conditions.length} upgrade risks`
);
});

it('shows correct icons', () => {
cy.get('.alerts__header')
.find('.pf-c-icon__content')
.should('have.class', 'pf-m-danger');
cy.get('.operators__header')
.find('.pf-c-icon__content')
.should('have.class', 'pf-m-warning');
});

it('has alerts table', () => {
cy.get('.alerts__content').should('be.visible');
cy.get('.alerts__content').within(() => {
checkTableHeaders(['Name', 'Status', 'Namespace']);
cy.get('tbody')
.find(TABLE_ROW)
.each(($row, index) => {
const alert =
upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors
.alerts[index];
cy.get($row).find('.alerts__name').should('have.text', alert.name);
cy.get($row)
.find('.alerts__severity')
.should('contain.text', SEVERITY_MAPPING[alert.severity]);
cy.get($row)
.find('.alerts__severity .pf-c-icon__content')
.should(
'have.class',
`pf-m-${SEVERITY_ICON_CLASS_MAPPING[alert.severity]}`
);
cy.get($row)
.find('.alerts__namespace')
.should('have.text', alert.namespace);
});
});
});

it('has operator conditions table', () => {
cy.get('.operators__content').should('be.visible');
cy.get('.operators__content').within(() => {
checkTableHeaders(['Name', 'Status', 'Message']);
cy.get('tbody')
.find(TABLE_ROW)
.each(($row, index) => {
const condition =
upgradeRisksFixtures.upgrade_recommendation.upgrade_risks_predictors
.operator_conditions[index];
cy.get($row)
.find('.operators__name')
.should('have.text', condition.name);
cy.get($row)
.find('.operators__status')
.should(
'contain.text',
CLUSTER_OPERATOR_LABEL_MAPPING[condition.condition]
);
cy.get($row)
.find('.operators__status .pf-c-icon__content')
.should('have.class', `pf-m-warning`);
cy.get($row)
.find('.operators__message')
.should('have.text', condition.reason || '-');
});
});
});

it('can hide content', () => {
cy.get('.pf-c-table__toggle button').eq(0).click();
cy.get('.alerts__content').should('not.be.visible');

cy.get('.pf-c-table__toggle button').eq(1).click();
cy.get('.operators__content').should('not.be.visible');
});
});

describe('successful, only cluster operators', () => {
beforeEach(() => {
interceptors['successful, alerts empty']();
mount();
});

it('has alerts hidden', () => {
cy.get('.alerts__content').should('not.exist');
});

it('shows 0 alert risks', () => {
cy.get('#alerts-label').should('have.text', `0 upgrade risks`);
});

it('does not show icon for alerts', () => {
cy.get('.alerts__header').find('.pf-c-icon__content').should('not.exist');
});
});

describe('successful, empty', () => {
beforeEach(() => {
interceptors['successful, empty']();
mount();
});

it('renders empty state', () => {
checkEmptyState('No upgrade risks found for this cluster', true);
});

it('header is present', () => {
checkTableHeaders(['Name']);
});
});

describe('error, service down', () => {
beforeEach(() => {
interceptors['error, not available']();
mount();
});

it('renders empty state', () => {
checkEmptyState('Upgrade risks are not available', true);
});

it('header is present', () => {
checkTableHeaders(['Name']);
});
});

describe('error, other', () => {
beforeEach(() => {
interceptors['error, other']();
mount();
});

it('renders empty state', () => {
// can't apply checkEmptyState since "something went wrong" component doesn't use OUIA id
cy.get('.pf-c-empty-state h4').should('have.text', 'Something went wrong');
cy.get('.pf-c-empty-state__icon').should('be.visible');
});

it('header is present', () => {
checkTableHeaders(['Name']);
});
});

describe('loading', () => {
beforeEach(() => {
interceptors['long responding']();
mount();
});

it('renders spinner', () => {
cy.get('.pf-c-spinner').should('be.visible');
cy.get('#upgrade-risks-table').should('not.exist');
});
});
Loading