931 lines
28 KiB
JavaScript
931 lines
28 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
|
|
import { module, test } from 'qunit';
|
|
import { setupTest } from 'ember-qunit';
|
|
import {
|
|
flattenDataset,
|
|
formatByMonths,
|
|
formatByNamespace,
|
|
homogenizeClientNaming,
|
|
sortMonthsByTimestamp,
|
|
namespaceArrayToObject,
|
|
} from 'core/utils/client-count-utils';
|
|
import { parseAPITimestamp } from 'core/utils/date-formatters';
|
|
import isBefore from 'date-fns/isBefore';
|
|
import isAfter from 'date-fns/isAfter';
|
|
|
|
// import { setupMirage } from 'ember-cli-mirage/test-support';
|
|
// import ENV from 'vault/config/environment';
|
|
// import { formatRFC3339 } from 'date-fns';
|
|
|
|
module('Integration | Util | client count utils', function (hooks) {
|
|
setupTest(hooks);
|
|
// setupMirage(hooks);
|
|
|
|
// TODO: wire up to stubbed API/mirage?
|
|
// hooks.before(function () {
|
|
// ENV['ember-cli-mirage'].handler = 'clients';
|
|
// });
|
|
// hooks.after(function () {
|
|
// ENV['ember-cli-mirage'].handler = null;
|
|
// });
|
|
|
|
/* MONTHS array contains: (update when backend work done on months )
|
|
- one month with only old client naming
|
|
*/
|
|
|
|
const MONTHS = [
|
|
{
|
|
timestamp: '2021-05-01T00:00:00Z',
|
|
counts: {
|
|
distinct_entities: 25,
|
|
non_entity_tokens: 25,
|
|
clients: 50,
|
|
},
|
|
namespaces: [
|
|
{
|
|
namespace_id: 'root',
|
|
namespace_path: '',
|
|
counts: {
|
|
distinct_entities: 13,
|
|
non_entity_tokens: 7,
|
|
clients: 20,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 8,
|
|
non_entity_tokens: 0,
|
|
clients: 8,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
non_entity_tokens: 7,
|
|
clients: 7,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
namespace_id: 's07UR',
|
|
namespace_path: 'ns1/',
|
|
counts: {
|
|
distinct_entities: 5,
|
|
non_entity_tokens: 5,
|
|
clients: 10,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
non_entity_tokens: 5,
|
|
clients: 5,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 5,
|
|
non_entity_tokens: 0,
|
|
clients: 5,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
new_clients: {
|
|
counts: {
|
|
distinct_entities: 3,
|
|
non_entity_tokens: 2,
|
|
clients: 5,
|
|
},
|
|
namespaces: [
|
|
{
|
|
namespace_id: 'root',
|
|
namespace_path: '',
|
|
counts: {
|
|
distinct_entities: 3,
|
|
non_entity_tokens: 2,
|
|
clients: 5,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 3,
|
|
non_entity_tokens: 0,
|
|
clients: 3,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
non_entity_tokens: 2,
|
|
clients: 2,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
timestamp: '2021-10-01T00:00:00Z',
|
|
counts: {
|
|
distinct_entities: 20,
|
|
entity_clients: 20,
|
|
non_entity_tokens: 20,
|
|
non_entity_clients: 20,
|
|
clients: 40,
|
|
},
|
|
namespaces: [
|
|
{
|
|
namespace_id: 'root',
|
|
namespace_path: '',
|
|
counts: {
|
|
distinct_entities: 8,
|
|
entity_clients: 8,
|
|
non_entity_tokens: 7,
|
|
non_entity_clients: 7,
|
|
clients: 15,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 8,
|
|
entity_clients: 8,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 8,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 7,
|
|
non_entity_clients: 7,
|
|
clients: 7,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
namespace_id: 's07UR',
|
|
namespace_path: 'ns1/',
|
|
counts: {
|
|
distinct_entities: 5,
|
|
entity_clients: 5,
|
|
non_entity_tokens: 5,
|
|
non_entity_clients: 5,
|
|
clients: 10,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 5,
|
|
non_entity_clients: 5,
|
|
clients: 5,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 5,
|
|
entity_clients: 5,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 5,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
new_clients: {
|
|
counts: {
|
|
distinct_entities: 3,
|
|
entity_clients: 3,
|
|
non_entity_tokens: 2,
|
|
non_entity_clients: 2,
|
|
clients: 5,
|
|
},
|
|
namespaces: [
|
|
{
|
|
namespace_id: 'root',
|
|
namespace_path: '',
|
|
counts: {
|
|
distinct_entities: 3,
|
|
entity_clients: 3,
|
|
non_entity_tokens: 2,
|
|
non_entity_clients: 2,
|
|
clients: 5,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 3,
|
|
entity_clients: 3,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 3,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 2,
|
|
non_entity_clients: 2,
|
|
clients: 2,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
timestamp: '2021-09-01T00:00:00Z',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 17,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 18,
|
|
clients: 35,
|
|
},
|
|
namespaces: [
|
|
{
|
|
namespace_id: 'oImjk',
|
|
namespace_path: 'ns2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 5,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 5,
|
|
clients: 10,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 5,
|
|
clients: 5,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 5,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 5,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
namespace_id: 'root',
|
|
namespace_path: '',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 2,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 3,
|
|
clients: 5,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 3,
|
|
clients: 3,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 2,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 2,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
namespace_id: 's07UR',
|
|
namespace_path: 'ns1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 3,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 2,
|
|
clients: 5,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 3,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 3,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 2,
|
|
clients: 2,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
new_clients: {
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 10,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 10,
|
|
clients: 20,
|
|
},
|
|
namespaces: [
|
|
{
|
|
namespace_id: 'oImjk',
|
|
namespace_path: 'ns2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 5,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 5,
|
|
clients: 10,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 5,
|
|
clients: 5,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 5,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 5,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
namespace_id: 'root',
|
|
namespace_path: '',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 2,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 3,
|
|
clients: 5,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 3,
|
|
clients: 3,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 2,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 2,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
namespace_id: 's07UR',
|
|
namespace_path: 'ns1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 3,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 2,
|
|
clients: 5,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 3,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 0,
|
|
clients: 3,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 0,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 2,
|
|
clients: 2,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
},
|
|
];
|
|
|
|
const BY_NAMESPACE = [
|
|
{
|
|
namespace_id: '96OwG',
|
|
namespace_path: 'test-ns/',
|
|
counts: {
|
|
distinct_entities: 18290,
|
|
entity_clients: 18290,
|
|
non_entity_tokens: 18738,
|
|
non_entity_clients: 18738,
|
|
clients: 37028,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'path-1',
|
|
counts: {
|
|
distinct_entities: 6403,
|
|
entity_clients: 6403,
|
|
non_entity_tokens: 6300,
|
|
non_entity_clients: 6300,
|
|
clients: 12703,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'path-2',
|
|
counts: {
|
|
distinct_entities: 5699,
|
|
entity_clients: 5699,
|
|
non_entity_tokens: 6777,
|
|
non_entity_clients: 6777,
|
|
clients: 12476,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'path-3',
|
|
counts: {
|
|
distinct_entities: 6188,
|
|
entity_clients: 6188,
|
|
non_entity_tokens: 5661,
|
|
non_entity_clients: 5661,
|
|
clients: 11849,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
namespace_id: 'root',
|
|
namespace_path: '',
|
|
counts: {
|
|
distinct_entities: 19099,
|
|
entity_clients: 19099,
|
|
non_entity_tokens: 17781,
|
|
non_entity_clients: 17781,
|
|
clients: 36880,
|
|
},
|
|
mounts: [
|
|
{
|
|
mount_path: 'path-3',
|
|
counts: {
|
|
distinct_entities: 6863,
|
|
entity_clients: 6863,
|
|
non_entity_tokens: 6801,
|
|
non_entity_clients: 6801,
|
|
clients: 13664,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'path-2',
|
|
counts: {
|
|
distinct_entities: 6047,
|
|
entity_clients: 6047,
|
|
non_entity_tokens: 5957,
|
|
non_entity_clients: 5957,
|
|
clients: 12004,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'path-1',
|
|
counts: {
|
|
distinct_entities: 6189,
|
|
entity_clients: 6189,
|
|
non_entity_tokens: 5023,
|
|
non_entity_clients: 5023,
|
|
clients: 11212,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up2/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 50,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 23,
|
|
clients: 73,
|
|
},
|
|
},
|
|
{
|
|
mount_path: 'auth/up1/',
|
|
counts: {
|
|
distinct_entities: 0,
|
|
entity_clients: 25,
|
|
non_entity_tokens: 0,
|
|
non_entity_clients: 15,
|
|
clients: 40,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const EMPTY_MONTHS = [
|
|
{
|
|
timestamp: '2021-06-01T00:00:00Z',
|
|
counts: null,
|
|
namespaces: null,
|
|
new_clients: null,
|
|
},
|
|
{
|
|
timestamp: '2021-07-01T00:00:00Z',
|
|
counts: null,
|
|
namespaces: null,
|
|
new_clients: null,
|
|
},
|
|
];
|
|
|
|
const SOME_OBJECT = { foo: 'bar' };
|
|
|
|
test('formatByMonths: formats the months array', async function (assert) {
|
|
assert.expect(103);
|
|
const keyNameAssertions = (object, objectName) => {
|
|
const objectKeys = Object.keys(object);
|
|
assert.false(objectKeys.includes('counts'), `${objectName} doesn't include 'counts' key`);
|
|
assert.true(objectKeys.includes('clients'), `${objectName} includes 'clients' key`);
|
|
assert.true(objectKeys.includes('entity_clients'), `${objectName} includes 'entity_clients' key`);
|
|
assert.true(
|
|
objectKeys.includes('non_entity_clients'),
|
|
`${objectName} includes 'non_entity_clients' key`
|
|
);
|
|
};
|
|
const assertClientCounts = (object, originalObject) => {
|
|
const newObjectKeys = ['clients', 'entity_clients', 'non_entity_clients'];
|
|
const originalKeys = Object.keys(originalObject.counts).includes('entity_clients')
|
|
? newObjectKeys
|
|
: ['clients', 'distinct_entities', 'non_entity_tokens'];
|
|
|
|
newObjectKeys.forEach((key, i) => {
|
|
assert.strictEqual(
|
|
object[key],
|
|
originalObject.counts[originalKeys[i]],
|
|
`${object.month} ${key} equal original counts`
|
|
);
|
|
});
|
|
};
|
|
|
|
const formattedMonths = formatByMonths(MONTHS);
|
|
assert.notEqual(formattedMonths, MONTHS, 'does not modify original array');
|
|
|
|
formattedMonths.forEach((month) => {
|
|
const originalMonth = MONTHS.find((m) => month.month === parseAPITimestamp(m.timestamp, 'M/yy'));
|
|
// if originalMonth is found (not undefined) then the formatted month has an accurate, parsed timestamp
|
|
assert.ok(originalMonth, `month has parsed timestamp of ${month.month}`);
|
|
assert.ok(month.namespaces_by_key, `month includes 'namespaces_by_key' key`);
|
|
|
|
keyNameAssertions(month, 'formatted month');
|
|
assertClientCounts(month, originalMonth);
|
|
|
|
assert.ok(month.new_clients.month, 'new clients key has a month key');
|
|
keyNameAssertions(month.new_clients, 'formatted month new_clients');
|
|
assertClientCounts(month.new_clients, originalMonth.new_clients);
|
|
|
|
month.namespaces.forEach((namespace) => keyNameAssertions(namespace, 'namespace within month'));
|
|
month.new_clients.namespaces.forEach((namespace) =>
|
|
keyNameAssertions(namespace, 'new client namespaces within month')
|
|
);
|
|
});
|
|
|
|
// method fails gracefully
|
|
const expected = [
|
|
{
|
|
counts: null,
|
|
month: '6/21',
|
|
namespaces: [],
|
|
namespaces_by_key: {},
|
|
new_clients: {
|
|
month: '6/21',
|
|
namespaces: [],
|
|
timestamp: '2021-06-01T00:00:00Z',
|
|
},
|
|
timestamp: '2021-06-01T00:00:00Z',
|
|
},
|
|
{
|
|
counts: null,
|
|
month: '7/21',
|
|
namespaces: [],
|
|
namespaces_by_key: {},
|
|
new_clients: {
|
|
month: '7/21',
|
|
namespaces: [],
|
|
timestamp: '2021-07-01T00:00:00Z',
|
|
},
|
|
timestamp: '2021-07-01T00:00:00Z',
|
|
},
|
|
];
|
|
assert.strictEqual(formatByMonths(SOME_OBJECT), SOME_OBJECT, 'it returns if arg is not an array');
|
|
assert.propEqual(expected, formatByMonths(EMPTY_MONTHS), 'it does not error with null months');
|
|
assert.ok(formatByMonths([...EMPTY_MONTHS, ...MONTHS]), 'it does not error with combined data');
|
|
});
|
|
|
|
test('formatByNamespace: formats namespace arrays with and without mounts', async function (assert) {
|
|
assert.expect(102);
|
|
const keyNameAssertions = (object, objectName) => {
|
|
const objectKeys = Object.keys(object);
|
|
assert.false(objectKeys.includes('counts'), `${objectName} doesn't include 'counts' key`);
|
|
assert.true(objectKeys.includes('label'), `${objectName} includes 'label' key`);
|
|
assert.true(objectKeys.includes('clients'), `${objectName} includes 'clients' key`);
|
|
assert.true(objectKeys.includes('entity_clients'), `${objectName} includes 'entity_clients' key`);
|
|
assert.true(
|
|
objectKeys.includes('non_entity_clients'),
|
|
`${objectName} includes 'non_entity_clients' key`
|
|
);
|
|
};
|
|
const keyValueAssertions = (object, pathName, originalObject) => {
|
|
const keysToAssert = ['clients', 'entity_clients', 'non_entity_clients'];
|
|
assert.strictEqual(object.label, originalObject[pathName], `${pathName} matches label`);
|
|
|
|
keysToAssert.forEach((key) => {
|
|
assert.strictEqual(object[key], originalObject.counts[key], `number of ${key} equal original`);
|
|
});
|
|
};
|
|
|
|
const formattedNamespaces = formatByNamespace(BY_NAMESPACE);
|
|
assert.notEqual(formattedNamespaces, MONTHS, 'does not modify original array');
|
|
|
|
formattedNamespaces.forEach((namespace) => {
|
|
const origNamespace = BY_NAMESPACE.find((ns) => ns.namespace_path === namespace.label);
|
|
keyNameAssertions(namespace, 'formatted namespace');
|
|
keyValueAssertions(namespace, 'namespace_path', origNamespace);
|
|
|
|
namespace.mounts.forEach((mount) => {
|
|
const origMount = origNamespace.mounts.find((m) => m.mount_path === mount.label);
|
|
keyNameAssertions(mount, 'formatted mount');
|
|
keyValueAssertions(mount, 'mount_path', origMount);
|
|
});
|
|
});
|
|
|
|
const nsWithoutMounts = {
|
|
namespace_id: '96OwG',
|
|
namespace_path: 'no-mounts-ns/',
|
|
counts: {
|
|
distinct_entities: 18290,
|
|
entity_clients: 18290,
|
|
non_entity_tokens: 18738,
|
|
non_entity_clients: 18738,
|
|
clients: 37028,
|
|
},
|
|
mounts: [],
|
|
};
|
|
|
|
const formattedNsWithoutMounts = formatByNamespace([nsWithoutMounts])[0];
|
|
keyNameAssertions(formattedNsWithoutMounts, 'namespace without mounts');
|
|
keyValueAssertions(formattedNsWithoutMounts, 'namespace_path', nsWithoutMounts);
|
|
assert.strictEqual(formattedNsWithoutMounts.mounts.length, 0, 'formatted namespace has no mounts');
|
|
|
|
assert.strictEqual(formatByNamespace(SOME_OBJECT), SOME_OBJECT, 'it returns if arg is not an array');
|
|
});
|
|
|
|
test('homogenizeClientNaming: homogenizes key names when both old and new keys exist, or just old key names', async function (assert) {
|
|
assert.expect(168);
|
|
const keyNameAssertions = (object, objectName) => {
|
|
const objectKeys = Object.keys(object);
|
|
assert.false(
|
|
objectKeys.includes('distinct_entities'),
|
|
`${objectName} doesn't include 'distinct_entities' key`
|
|
);
|
|
assert.false(
|
|
objectKeys.includes('non_entity_tokens'),
|
|
`${objectName} doesn't include 'non_entity_tokens' key`
|
|
);
|
|
assert.true(objectKeys.includes('entity_clients'), `${objectName} includes 'entity_clients' key`);
|
|
assert.true(
|
|
objectKeys.includes('non_entity_clients'),
|
|
`${objectName} includes 'non_entity_clients' key`
|
|
);
|
|
};
|
|
|
|
const transformedMonths = [...MONTHS];
|
|
transformedMonths.forEach((month) => {
|
|
month.counts = homogenizeClientNaming(month.counts);
|
|
keyNameAssertions(month.counts, 'month counts');
|
|
|
|
month.new_clients.counts = homogenizeClientNaming(month.new_clients.counts);
|
|
keyNameAssertions(month.new_clients.counts, 'month new counts');
|
|
|
|
month.namespaces.forEach((ns) => {
|
|
ns.counts = homogenizeClientNaming(ns.counts);
|
|
keyNameAssertions(ns.counts, 'namespace counts');
|
|
|
|
ns.mounts.forEach((mount) => {
|
|
mount.counts = homogenizeClientNaming(mount.counts);
|
|
keyNameAssertions(mount.counts, 'mount counts');
|
|
});
|
|
});
|
|
|
|
month.new_clients.namespaces.forEach((ns) => {
|
|
ns.counts = homogenizeClientNaming(ns.counts);
|
|
keyNameAssertions(ns.counts, 'namespace new counts');
|
|
|
|
ns.mounts.forEach((mount) => {
|
|
mount.counts = homogenizeClientNaming(mount.counts);
|
|
keyNameAssertions(mount.counts, 'mount new counts');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
test('flattenDataset: removes the counts key and flattens the dataset', async function (assert) {
|
|
assert.expect(22);
|
|
const flattenedNamespace = flattenDataset(BY_NAMESPACE[0]);
|
|
const flattenedMount = flattenDataset(BY_NAMESPACE[0].mounts[0]);
|
|
const flattenedMonth = flattenDataset(MONTHS[0]);
|
|
const flattenedNewMonthClients = flattenDataset(MONTHS[0].new_clients);
|
|
const objectNullCounts = { counts: null, foo: 'bar' };
|
|
|
|
const keyNameAssertions = (object, objectName) => {
|
|
const objectKeys = Object.keys(object);
|
|
assert.false(objectKeys.includes('counts'), `${objectName} doesn't include 'counts' key`);
|
|
assert.true(objectKeys.includes('clients'), `${objectName} includes 'clients' key`);
|
|
assert.true(objectKeys.includes('entity_clients'), `${objectName} includes 'entity_clients' key`);
|
|
assert.true(
|
|
objectKeys.includes('non_entity_clients'),
|
|
`${objectName} includes 'non_entity_clients' key`
|
|
);
|
|
};
|
|
|
|
keyNameAssertions(flattenedNamespace, 'namespace object');
|
|
keyNameAssertions(flattenedMount, 'mount object');
|
|
keyNameAssertions(flattenedMonth, 'month object');
|
|
keyNameAssertions(flattenedNewMonthClients, 'month new_clients object');
|
|
|
|
assert.strictEqual(
|
|
flattenDataset(SOME_OBJECT),
|
|
SOME_OBJECT,
|
|
"it returns original object if counts key doesn't exist"
|
|
);
|
|
|
|
assert.strictEqual(
|
|
flattenDataset(objectNullCounts),
|
|
objectNullCounts,
|
|
'it returns original object if counts are null'
|
|
);
|
|
|
|
assert.propEqual(
|
|
['some array'],
|
|
flattenDataset(['some array']),
|
|
'it fails gracefully if an array is passed in'
|
|
);
|
|
assert.strictEqual(flattenDataset(null), null, 'it fails gracefully if null is passed in');
|
|
assert.strictEqual(
|
|
flattenDataset('some string'),
|
|
'some string',
|
|
'it fails gracefully if a string is passed in'
|
|
);
|
|
assert.propEqual(
|
|
new Object(),
|
|
flattenDataset(new Object()),
|
|
'it fails gracefully if an empty object is passed in'
|
|
);
|
|
});
|
|
|
|
test('sortMonthsByTimestamp: sorts timestamps chronologically, oldest to most recent', async function (assert) {
|
|
assert.expect(4);
|
|
const sortedMonths = sortMonthsByTimestamp(MONTHS);
|
|
assert.ok(
|
|
isBefore(parseAPITimestamp(sortedMonths[0].timestamp), parseAPITimestamp(sortedMonths[1].timestamp)),
|
|
'first timestamp date is earlier than second'
|
|
);
|
|
assert.ok(
|
|
isAfter(parseAPITimestamp(sortedMonths[2].timestamp), parseAPITimestamp(sortedMonths[1].timestamp)),
|
|
'third timestamp date is later second'
|
|
);
|
|
assert.notEqual(sortedMonths[1], MONTHS[1], 'it does not modify original array');
|
|
assert.strictEqual(sortedMonths[0], MONTHS[0], 'it does not modify original array');
|
|
});
|
|
|
|
test('namespaceArrayToObject: transforms data without modifying original', async function (assert) {
|
|
assert.expect(30);
|
|
|
|
const assertClientCounts = (object, originalObject) => {
|
|
const valuesToCheck = ['clients', 'entity_clients', 'non_entity_clients'];
|
|
|
|
valuesToCheck.forEach((key) => {
|
|
assert.strictEqual(object[key], originalObject[key], `${key} equal original counts`);
|
|
});
|
|
};
|
|
const totalClientsByNamespace = formatByNamespace(MONTHS[1].namespaces);
|
|
const newClientsByNamespace = formatByNamespace(MONTHS[1].new_clients.namespaces);
|
|
|
|
const byNamespaceKeyObject = namespaceArrayToObject(
|
|
totalClientsByNamespace,
|
|
newClientsByNamespace,
|
|
'10/21'
|
|
);
|
|
|
|
assert.propEqual(
|
|
totalClientsByNamespace,
|
|
formatByNamespace(MONTHS[1].namespaces),
|
|
'it does not modify original array'
|
|
);
|
|
assert.propEqual(
|
|
newClientsByNamespace,
|
|
formatByNamespace(MONTHS[1].new_clients.namespaces),
|
|
'it does not modify original array'
|
|
);
|
|
|
|
const namespaceKeys = Object.keys(byNamespaceKeyObject);
|
|
namespaceKeys.forEach((nsKey) => {
|
|
const newNsObject = byNamespaceKeyObject[nsKey];
|
|
const originalNsData = totalClientsByNamespace.find((ns) => ns.label === nsKey);
|
|
assertClientCounts(newNsObject, originalNsData);
|
|
const mountKeys = Object.keys(newNsObject.mounts_by_key);
|
|
mountKeys.forEach((mKey) => {
|
|
const mountData = originalNsData.mounts.find((m) => m.label === mKey);
|
|
assertClientCounts(newNsObject.mounts_by_key[mKey], mountData);
|
|
});
|
|
});
|
|
|
|
namespaceKeys.forEach((nsKey) => {
|
|
const newNsObject = byNamespaceKeyObject[nsKey];
|
|
const originalNsData = newClientsByNamespace.find((ns) => ns.label === nsKey);
|
|
if (!originalNsData) return;
|
|
assertClientCounts(newNsObject.new_clients, originalNsData);
|
|
const mountKeys = Object.keys(newNsObject.mounts_by_key);
|
|
|
|
mountKeys.forEach((mKey) => {
|
|
const mountData = originalNsData.mounts.find((m) => m.label === mKey);
|
|
assertClientCounts(newNsObject.mounts_by_key[mKey].new_clients, mountData);
|
|
});
|
|
});
|
|
|
|
assert.propEqual(
|
|
{},
|
|
namespaceArrayToObject(null, null, '10/21'),
|
|
'returns an empty object when totalClientsByNamespace = null'
|
|
);
|
|
});
|
|
});
|