mirror of
https://github.com/hashicorp/vault.git
synced 2026-06-09 08:55:13 -04:00
refactor mirage
This commit is contained in:
parent
c7e97d007d
commit
65a4c5b103
7 changed files with 183 additions and 9346 deletions
|
|
@ -113,7 +113,10 @@ export default class Dashboard extends Component {
|
|||
// on init, date is automatically pulled from license start date and user hasn't queried anything yet
|
||||
message = 'Your license start date is';
|
||||
}
|
||||
if (isAfter(activityStartDateObject, queryStartDateObject)) {
|
||||
if (
|
||||
isAfter(activityStartDateObject, queryStartDateObject) &&
|
||||
!isSameMonth(activityStartDateObject, queryStartDateObject)
|
||||
) {
|
||||
return `${message} ${parseAPITimestamp(this.startMonthTimestamp, 'MMMM yyyy')}.
|
||||
We only have data from ${parseAPITimestamp(this.getActivityResponse.startTime, 'MMMM yyyy')},
|
||||
and that is what is being shown here.`;
|
||||
|
|
@ -237,7 +240,7 @@ export default class Dashboard extends Component {
|
|||
// new client data for horizontal bar chart
|
||||
get newClientAttribution() {
|
||||
// new client attribution only available in a single, historical month (not a date range or current month)
|
||||
if (this.isDateRange) return null;
|
||||
if (this.isDateRange || this.isCurrentMonth) return null;
|
||||
|
||||
if (this.selectedNamespace) {
|
||||
return this.newClientCounts?.mounts || null;
|
||||
|
|
|
|||
|
|
@ -72,17 +72,18 @@ export default class RunningTotal extends Component {
|
|||
|
||||
get showSingleMonth() {
|
||||
if (this.args.lineChartData?.length === 1) {
|
||||
const totalData = this.args.runningTotals;
|
||||
const monthData = this.args?.lineChartData[0];
|
||||
return {
|
||||
total: {
|
||||
total: monthData.clients,
|
||||
entityClients: monthData.entity_clients,
|
||||
nonEntityClients: monthData.non_entity_clients,
|
||||
total: totalData.clients,
|
||||
entityClients: totalData.entity_clients,
|
||||
nonEntityClients: totalData.non_entity_clients,
|
||||
},
|
||||
new: {
|
||||
total: monthData.new_clients.clients,
|
||||
entityClients: monthData.new_clients.entity_clients,
|
||||
nonEntityClients: monthData.new_clients.non_entity_clients,
|
||||
total: monthData.new_clients.clients || 0,
|
||||
entityClients: monthData.new_clients.entity_clients || 0,
|
||||
nonEntityClients: monthData.new_clients.non_entity_clients || 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,6 @@
|
|||
// add all handlers here
|
||||
// individual lookup done in mirage config
|
||||
import base from './base';
|
||||
import activity from './activity';
|
||||
import clients from './clients';
|
||||
import db from './db';
|
||||
import kms from './kms';
|
||||
|
|
@ -10,4 +9,4 @@ import mfaLogin from './mfa-login';
|
|||
import oidcConfig from './oidc-config';
|
||||
import hcpLink from './hcp-link';
|
||||
|
||||
export { base, activity, clients, db, kms, mfaConfig, mfaLogin, oidcConfig, hcpLink };
|
||||
export { base, clients, db, kms, mfaConfig, mfaLogin, oidcConfig, hcpLink };
|
||||
|
|
|
|||
|
|
@ -10,16 +10,16 @@ import { create } from 'ember-cli-page-object';
|
|||
import ss from 'vault/tests/pages/components/search-select';
|
||||
import { clickTrigger } from 'ember-power-select/test-support/helpers';
|
||||
import { ARRAY_OF_MONTHS } from 'core/utils/date-formatters';
|
||||
import { formatNumber } from 'core/helpers/format-number';
|
||||
|
||||
const searchSelect = create(ss);
|
||||
|
||||
const NEW_DATE = new Date();
|
||||
const LAST_MONTH = startOfMonth(subMonths(NEW_DATE, 1));
|
||||
const COUNTS_START = subMonths(NEW_DATE, 12); // pretend vault user started cluster 1 year ago
|
||||
const CURRENT_DATE = new Date();
|
||||
const LAST_MONTH = startOfMonth(subMonths(CURRENT_DATE, 1));
|
||||
const COUNTS_START = subMonths(CURRENT_DATE, 12); // pretend vault user started cluster 1 year ago
|
||||
|
||||
// for testing, we're in the middle of a license/billing period
|
||||
const LICENSE_START = startOfMonth(subMonths(NEW_DATE, 6));
|
||||
|
||||
const LICENSE_START = startOfMonth(subMonths(CURRENT_DATE, 6));
|
||||
// upgrade happened 1 month after license start
|
||||
const UPGRADE_DATE = addMonths(LICENSE_START, 1);
|
||||
|
||||
|
|
@ -31,6 +31,10 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
ENV['ember-cli-mirage'].handler = 'clients';
|
||||
});
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.store = this.owner.lookup('service:store');
|
||||
});
|
||||
|
||||
hooks.after(function () {
|
||||
ENV['ember-cli-mirage'].handler = null;
|
||||
});
|
||||
|
|
@ -80,18 +84,17 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
assert.dom(SELECTORS.filterBar).doesNotExist('Does not show filter bar');
|
||||
});
|
||||
|
||||
test('visiting history tab config on and data with mounts', async function (assert) {
|
||||
test('visiting dashboard tab config on and data with mounts', async function (assert) {
|
||||
assert.expect(8);
|
||||
await visit('/vault/clients/dashboard');
|
||||
assert.strictEqual(currentURL(), '/vault/clients/dashboard');
|
||||
|
||||
assert
|
||||
.dom(SELECTORS.dateDisplay)
|
||||
.hasText(format(LICENSE_START, 'MMMM yyyy'), 'billing start month is correctly parsed from license');
|
||||
assert
|
||||
.dom(SELECTORS.rangeDropdown)
|
||||
.hasText(
|
||||
`${format(LICENSE_START, 'MMM yyyy')} - ${format(NEW_DATE, 'MMM yyyy')}`,
|
||||
`${format(LICENSE_START, 'MMM yyyy')} - ${format(CURRENT_DATE, 'MMM yyyy')}`,
|
||||
'Date range shows dates correctly parsed activity response'
|
||||
);
|
||||
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area');
|
||||
|
|
@ -111,8 +114,6 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
|
||||
test('updates correctly when querying date ranges', async function (assert) {
|
||||
assert.expect(26);
|
||||
// TODO CMB: wire up dynamically generated activity to mirage clients handler
|
||||
// const activity = generateActivityResponse(5, LICENSE_START, LAST_MONTH);
|
||||
await visit('/vault/clients/dashboard');
|
||||
assert.strictEqual(currentURL(), '/vault/clients/dashboard');
|
||||
// query for single, historical month with no new counts
|
||||
|
|
@ -167,7 +168,7 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
// query custom end month
|
||||
await click(SELECTORS.rangeDropdown);
|
||||
await click('[data-test-show-calendar]');
|
||||
if (parseInt(find('[data-test-display-year]').innerText) < NEW_DATE.getFullYear()) {
|
||||
if (parseInt(find('[data-test-display-year]').innerText) < CURRENT_DATE.getFullYear()) {
|
||||
await click('[data-test-next-year]');
|
||||
}
|
||||
await click(find(`[data-test-calendar-month=${ARRAY_OF_MONTHS[LAST_MONTH.getMonth() - 2]}]`));
|
||||
|
|
@ -190,7 +191,7 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
// query for single, historical month
|
||||
await click(SELECTORS.rangeDropdown);
|
||||
await click('[data-test-show-calendar]');
|
||||
if (parseInt(find('[data-test-display-year]').innerText) < NEW_DATE.getFullYear()) {
|
||||
if (parseInt(find('[data-test-display-year]').innerText) < CURRENT_DATE.getFullYear()) {
|
||||
await click('[data-test-next-year]');
|
||||
}
|
||||
await click(find(`[data-test-calendar-month=${ARRAY_OF_MONTHS[UPGRADE_DATE.getMonth()]}]`));
|
||||
|
|
@ -207,7 +208,6 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
// reset to billing period
|
||||
await click('[data-test-popup-menu-trigger]');
|
||||
await click('[data-test-current-billing-period]');
|
||||
|
||||
// query month older than count start date
|
||||
await click('[data-test-start-date-editor] button');
|
||||
await click(SELECTORS.yearDropdown);
|
||||
|
|
@ -221,8 +221,8 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
);
|
||||
});
|
||||
|
||||
test('filters correctly on history with full data', async function (assert) {
|
||||
assert.expect(19);
|
||||
test('dashboard filters correctly with full data', async function (assert) {
|
||||
assert.expect(21);
|
||||
await visit('/vault/clients/dashboard');
|
||||
assert.strictEqual(currentURL(), '/vault/clients/dashboard', 'clients/dashboard URL is correct');
|
||||
assert.dom(SELECTORS.dashboardActiveTab).hasText('Dashboard', 'dashboard tab is active');
|
||||
|
|
@ -231,43 +231,73 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
.exists('Shows running totals with monthly breakdown charts');
|
||||
assert.dom(SELECTORS.attributionBlock).exists('Shows attribution area');
|
||||
assert.dom(SELECTORS.monthlyUsageBlock).exists('Shows monthly usage block');
|
||||
const response = await this.store.peekRecord('clients/activity', 'some-activity-id');
|
||||
|
||||
// FILTER BY NAMESPACE
|
||||
await clickTrigger();
|
||||
await searchSelect.options.objectAt(0).click();
|
||||
|
||||
await settled();
|
||||
const topNamespace = response.byNamespace[0];
|
||||
const topMount = topNamespace.mounts[0];
|
||||
assert.ok(true, 'Filter by first namespace');
|
||||
assert.strictEqual(
|
||||
find(SELECTORS.selectedNs).innerText.toLowerCase(),
|
||||
topNamespace.label,
|
||||
'selects top namespace'
|
||||
);
|
||||
assert.dom('[data-test-top-attribution]').includesText('Top auth method');
|
||||
assert.dom('[data-test-running-total-entity]').includesText('23,326', 'total entity clients is accurate');
|
||||
assert
|
||||
.dom('[data-test-running-total-nonentity]')
|
||||
.includesText('17,826', 'total non-entity clients is accurate');
|
||||
assert.dom('[data-test-attribution-clients]').includesText('10,142', 'top attribution clients accurate');
|
||||
.dom('[data-test-running-total-entity] p')
|
||||
.includesText(`${formatNumber([topNamespace.entity_clients])}`, 'total entity clients is accurate');
|
||||
assert
|
||||
.dom('[data-test-running-total-nonentity] p')
|
||||
.includesText(
|
||||
`${formatNumber([topNamespace.non_entity_clients])}`,
|
||||
'total non-entity clients is accurate'
|
||||
);
|
||||
assert
|
||||
.dom('[data-test-attribution-clients] p')
|
||||
.includesText(`${formatNumber([topMount.clients])}`, 'top attribution clients accurate');
|
||||
|
||||
// FILTER BY AUTH METHOD
|
||||
await clickTrigger();
|
||||
await searchSelect.options.objectAt(0).click();
|
||||
await settled();
|
||||
assert.ok(true, 'Filter by first auth method');
|
||||
assert.dom('[data-test-running-total-entity]').includesText('6,508', 'total entity clients is accurate');
|
||||
assert.strictEqual(
|
||||
find(SELECTORS.selectedAuthMount).innerText.toLowerCase(),
|
||||
topMount.label,
|
||||
'selects top mount'
|
||||
);
|
||||
assert
|
||||
.dom('[data-test-running-total-nonentity]')
|
||||
.includesText('3,634', 'total non-entity clients is accurate');
|
||||
.dom('[data-test-running-total-entity] p')
|
||||
.includesText(`${formatNumber([topMount.entity_clients])}`, 'total entity clients is accurate');
|
||||
assert
|
||||
.dom('[data-test-running-total-nonentity] p')
|
||||
.includesText(`${formatNumber([topMount.non_entity_clients])}`, 'total non-entity clients is accurate');
|
||||
assert.dom(SELECTORS.attributionBlock).doesNotExist('Does not show attribution block');
|
||||
|
||||
await click('#namespace-search-select [data-test-selected-list-button="delete"]');
|
||||
assert.ok(true, 'Remove namespace filter without first removing auth method filter');
|
||||
assert.dom('[data-test-top-attribution]').includesText('Top namespace');
|
||||
assert
|
||||
.dom('[data-test-attribution-clients]')
|
||||
.hasTextContaining('41,152', 'top attribution clients back to unfiltered value');
|
||||
assert
|
||||
.dom('[data-test-running-total-entity]')
|
||||
.hasTextContaining('98,289', 'total entity clients is back to unfiltered value');
|
||||
.hasTextContaining(
|
||||
`${formatNumber([response.total.entity_clients])}`,
|
||||
'total entity clients is back to unfiltered value'
|
||||
);
|
||||
assert
|
||||
.dom('[data-test-running-total-nonentity]')
|
||||
.hasTextContaining('96,412', 'total non-entity clients is back to unfiltered value');
|
||||
.hasTextContaining(
|
||||
`${formatNumber([formatNumber([response.total.non_entity_clients])])}`,
|
||||
'total non-entity clients is back to unfiltered value'
|
||||
);
|
||||
assert
|
||||
.dom('[data-test-attribution-clients]')
|
||||
.hasTextContaining(
|
||||
`${formatNumber([topNamespace.clients])}`,
|
||||
'top attribution clients back to unfiltered value'
|
||||
);
|
||||
});
|
||||
|
||||
test('shows warning if upgrade happened within license period', async function (assert) {
|
||||
|
|
@ -312,8 +342,8 @@ module('Acceptance | client counts dashboard tab', function (hooks) {
|
|||
|
||||
test('Shows empty if license start date is current month', async function (assert) {
|
||||
// TODO cmb update to reflect new behavior
|
||||
const licenseStart = NEW_DATE;
|
||||
const licenseEnd = addMonths(NEW_DATE, 12);
|
||||
const licenseStart = CURRENT_DATE;
|
||||
const licenseEnd = addMonths(CURRENT_DATE, 12);
|
||||
this.server.get('sys/license/status', function () {
|
||||
return {
|
||||
request_id: 'my-license-request-id',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { addMonths, differenceInCalendarMonths, formatRFC3339, startOfMonth } from 'date-fns';
|
||||
import { Response } from 'miragejs';
|
||||
|
||||
/** Scenarios
|
||||
|
|
@ -32,6 +31,8 @@ export const SELECTORS = {
|
|||
runningTotalMonthStats: '[data-test-running-total="single-month-stats"]',
|
||||
runningTotalMonthlyCharts: '[data-test-running-total="monthly-charts"]',
|
||||
monthlyUsageBlock: '[data-test-monthly-usage]',
|
||||
selectedAuthMount: 'div#auth-method-search-select [data-test-selected-option] div',
|
||||
selectedNs: 'div#namespace-search-select [data-test-selected-option] div',
|
||||
};
|
||||
|
||||
export const CHART_ELEMENTS = {
|
||||
|
|
@ -74,187 +75,3 @@ export function overrideResponse(httpStatus, data) {
|
|||
}
|
||||
return new Response(200, { 'Content-Type': 'application/json' }, JSON.stringify(data));
|
||||
}
|
||||
|
||||
function generateNamespaceBlock(idx = 0, skipMounts = false) {
|
||||
let mountCount = 1;
|
||||
const nsBlock = {
|
||||
namespace_id: `${idx}UUID`,
|
||||
namespace_path: `${idx}/namespace`,
|
||||
counts: {
|
||||
clients: mountCount * 15,
|
||||
entity_clients: mountCount * 5,
|
||||
non_entity_clients: mountCount * 10,
|
||||
distinct_entities: mountCount * 5,
|
||||
non_entity_tokens: mountCount * 10,
|
||||
},
|
||||
};
|
||||
if (!skipMounts) {
|
||||
mountCount = Math.floor((Math.random() + idx) * 20);
|
||||
const mounts = [];
|
||||
Array.from(Array(mountCount)).forEach((v, index) => {
|
||||
mounts.push({
|
||||
mount_path: `auth/authid${index}`,
|
||||
counts: {
|
||||
clients: 5,
|
||||
entity_clients: 3,
|
||||
non_entity_clients: 2,
|
||||
distinct_entities: 3,
|
||||
non_entity_tokens: 2,
|
||||
},
|
||||
});
|
||||
});
|
||||
nsBlock.mounts = mounts;
|
||||
}
|
||||
return nsBlock;
|
||||
}
|
||||
|
||||
function generateCounts(max, arrayLength) {
|
||||
function randomBetween(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
var result = [];
|
||||
var sum = 0;
|
||||
for (var i = 0; i < arrayLength - 1; i++) {
|
||||
result[i] = randomBetween(1, max - (arrayLength - i - 1) - sum);
|
||||
sum += result[i];
|
||||
}
|
||||
result[arrayLength - 1] = max - sum;
|
||||
return result.sort((a, b) => b - a);
|
||||
}
|
||||
|
||||
function generateMonths(startDate, endDate, hasNoData = false) {
|
||||
const numberOfMonths = differenceInCalendarMonths(endDate, startDate) + 1;
|
||||
const months = [];
|
||||
|
||||
for (let i = 0; i < numberOfMonths; i++) {
|
||||
if (hasNoData) {
|
||||
months.push({
|
||||
timestamp: formatRFC3339(startOfMonth(addMonths(startDate, i))),
|
||||
counts: null,
|
||||
namespace: null,
|
||||
new_clients: null,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const namespaces = Array.from(Array(5)).map((v, idx) => {
|
||||
return generateNamespaceBlock(idx);
|
||||
});
|
||||
const clients = numberOfMonths * 5 + i * 5;
|
||||
const [entity_clients, non_entity_clients] = generateCounts(clients, 2);
|
||||
const counts = {
|
||||
clients,
|
||||
entity_clients,
|
||||
non_entity_clients,
|
||||
distinct_entities: entity_clients,
|
||||
non_entity_tokens: non_entity_clients,
|
||||
};
|
||||
const new_counts = 5 + i;
|
||||
const [new_entity, new_non_entity] = generateCounts(new_counts, 2);
|
||||
months.push({
|
||||
timestamp: formatRFC3339(startOfMonth(addMonths(startDate, i))),
|
||||
counts,
|
||||
namespaces,
|
||||
new_clients: {
|
||||
counts: {
|
||||
distinct_entities: new_entity,
|
||||
entity_clients: new_entity,
|
||||
non_entity_tokens: new_non_entity,
|
||||
non_entity_clients: new_non_entity,
|
||||
clients: new_counts,
|
||||
},
|
||||
namespaces,
|
||||
},
|
||||
});
|
||||
}
|
||||
return months;
|
||||
}
|
||||
|
||||
export function generateActivityResponse(nsCount = 1, startDate, endDate) {
|
||||
if (nsCount === 0) {
|
||||
return {
|
||||
request_id: 'some-activity-id',
|
||||
data: {
|
||||
start_time: formatRFC3339(startDate),
|
||||
end_time: formatRFC3339(endDate),
|
||||
total: {
|
||||
clients: 0,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
},
|
||||
by_namespace: [
|
||||
{
|
||||
namespace_id: `root`,
|
||||
namespace_path: '',
|
||||
counts: {
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
clients: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
months: generateMonths(startDate, endDate, false),
|
||||
},
|
||||
};
|
||||
}
|
||||
const namespaces = Array.from(Array(nsCount)).map((v, idx) => {
|
||||
return generateNamespaceBlock(idx);
|
||||
});
|
||||
return {
|
||||
request_id: 'some-activity-id',
|
||||
data: {
|
||||
start_time: formatRFC3339(startDate),
|
||||
end_time: formatRFC3339(endDate),
|
||||
total: {
|
||||
clients: 999,
|
||||
entity_clients: 666,
|
||||
non_entity_clients: 333,
|
||||
},
|
||||
by_namespace: namespaces,
|
||||
months: generateMonths(startDate, endDate),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function generateCurrentMonthResponse(namespaceCount, skipMounts = false, configEnabled = true) {
|
||||
if (!configEnabled) {
|
||||
return {
|
||||
data: { id: 'no-data' },
|
||||
};
|
||||
}
|
||||
if (!namespaceCount) {
|
||||
return {
|
||||
request_id: 'monthly-response-id',
|
||||
data: {
|
||||
by_namespace: [],
|
||||
clients: 0,
|
||||
distinct_entities: 0,
|
||||
entity_clients: 0,
|
||||
non_entity_clients: 0,
|
||||
non_entity_tokens: 0,
|
||||
months: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
// generate by_namespace data
|
||||
const by_namespace = Array.from(Array(namespaceCount)).map((ns, idx) =>
|
||||
generateNamespaceBlock(idx, skipMounts)
|
||||
);
|
||||
const counts = by_namespace.reduce(
|
||||
(prev, curr) => {
|
||||
return {
|
||||
clients: prev.clients + curr.counts.clients,
|
||||
entity_clients: prev.entity_clients + curr.counts.entity_clients,
|
||||
non_entity_clients: prev.non_entity_clients + curr.counts.non_entity_clients,
|
||||
};
|
||||
},
|
||||
{ clients: 0, entity_clients: 0, non_entity_clients: 0 }
|
||||
);
|
||||
return {
|
||||
request_id: 'monthly-response-id',
|
||||
data: {
|
||||
by_namespace,
|
||||
...counts,
|
||||
months: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue