mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +01:00
chore: add tests for new traffic usage functions (#9208)
This PR adds tests to all the TODOs created in https://github.com/Unleash/unleash/pull/9191. Additionally it finally manages to refactor the `toChartData` function.
This commit is contained in:
parent
419d189ddc
commit
bd6a90ffd4
@ -233,7 +233,7 @@ const NewNetworkTrafficUsage: FC = () => {
|
|||||||
|
|
||||||
const traffic = useInstanceTrafficMetrics2(
|
const traffic = useInstanceTrafficMetrics2(
|
||||||
chartDataSelection.grouping,
|
chartDataSelection.grouping,
|
||||||
toDateRange(chartDataSelection),
|
toDateRange(chartDataSelection, currentDate),
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = newToChartData(traffic.usage);
|
const data = newToChartData(traffic.usage);
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
import { type ChartDataSelection, toDateRange } from './chart-data-selection';
|
||||||
|
|
||||||
|
test('daily conversion', () => {
|
||||||
|
const input: ChartDataSelection = {
|
||||||
|
grouping: 'daily',
|
||||||
|
month: '2021-03',
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedOutput = {
|
||||||
|
from: '2021-03-01',
|
||||||
|
to: '2021-03-31',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(toDateRange(input)).toStrictEqual(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('monthly conversion', () => {
|
||||||
|
const now = new Date('2023-06-15');
|
||||||
|
const input: ChartDataSelection = {
|
||||||
|
grouping: 'monthly',
|
||||||
|
monthsBack: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedOutput = {
|
||||||
|
from: '2023-03-01',
|
||||||
|
to: '2023-06-30',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(toDateRange(input, now)).toStrictEqual(expectedOutput);
|
||||||
|
});
|
@ -10,9 +10,9 @@ export type ChartDataSelection =
|
|||||||
monthsBack: number;
|
monthsBack: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo: write test
|
|
||||||
export const toDateRange = (
|
export const toDateRange = (
|
||||||
selection: ChartDataSelection,
|
selection: ChartDataSelection,
|
||||||
|
now = new Date(),
|
||||||
): { from: string; to: string } => {
|
): { from: string; to: string } => {
|
||||||
const fmt = (date: Date) => format(date, 'yyyy-MM-dd');
|
const fmt = (date: Date) => format(date, 'yyyy-MM-dd');
|
||||||
if (selection.grouping === 'daily') {
|
if (selection.grouping === 'daily') {
|
||||||
@ -21,7 +21,6 @@ export const toDateRange = (
|
|||||||
const to = fmt(endOfMonth(month));
|
const to = fmt(endOfMonth(month));
|
||||||
return { from, to };
|
return { from, to };
|
||||||
} else {
|
} else {
|
||||||
const now = new Date();
|
|
||||||
const from = fmt(startOfMonth(subMonths(now, selection.monthsBack)));
|
const from = fmt(startOfMonth(subMonths(now, selection.monthsBack)));
|
||||||
const to = fmt(endOfMonth(now));
|
const to = fmt(endOfMonth(now));
|
||||||
return { from, to };
|
return { from, to };
|
||||||
|
@ -0,0 +1,158 @@
|
|||||||
|
import type { TrafficUsageDataSegmentedCombinedSchema } from 'openapi';
|
||||||
|
import { toChartData } from './chart-functions';
|
||||||
|
import { endpointsInfo } from './endpoint-info';
|
||||||
|
|
||||||
|
describe('toChartData', () => {
|
||||||
|
const dataPoint = (period: string, count: number) => ({
|
||||||
|
period,
|
||||||
|
trafficTypes: [{ count, group: 'successful-requests' }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const fromEndpointInfo = (endpoint: keyof typeof endpointsInfo) => {
|
||||||
|
const info = endpointsInfo[endpoint];
|
||||||
|
return {
|
||||||
|
backgroundColor: info.color,
|
||||||
|
hoverBackgroundColor: info.color,
|
||||||
|
label: info.label,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
test('monthly data conversion', () => {
|
||||||
|
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
||||||
|
grouping: 'monthly',
|
||||||
|
dateRange: {
|
||||||
|
from: '2025-01-01',
|
||||||
|
to: '2025-06-30',
|
||||||
|
},
|
||||||
|
apiData: [
|
||||||
|
{
|
||||||
|
apiPath: '/api/admin',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2025-06', 5),
|
||||||
|
dataPoint('2025-05', 4),
|
||||||
|
dataPoint('2025-02', 6),
|
||||||
|
dataPoint('2025-04', 2),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiPath: '/api/client',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2025-06', 10),
|
||||||
|
dataPoint('2025-01', 7),
|
||||||
|
dataPoint('2025-03', 11),
|
||||||
|
dataPoint('2025-04', 13),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedOutput = {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
data: [0, 6, 0, 2, 4, 5],
|
||||||
|
...fromEndpointInfo('/api/admin'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [7, 0, 11, 13, 0, 10],
|
||||||
|
...fromEndpointInfo('/api/client'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
labels: [
|
||||||
|
'2025-01',
|
||||||
|
'2025-02',
|
||||||
|
'2025-03',
|
||||||
|
'2025-04',
|
||||||
|
'2025-05',
|
||||||
|
'Current month',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(toChartData(input)).toMatchObject(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('daily data conversion', () => {
|
||||||
|
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
||||||
|
grouping: 'daily',
|
||||||
|
dateRange: {
|
||||||
|
from: '2025-01-01',
|
||||||
|
to: '2025-01-31',
|
||||||
|
},
|
||||||
|
apiData: [
|
||||||
|
{
|
||||||
|
apiPath: '/api/admin',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2025-01-01', 5),
|
||||||
|
dataPoint('2025-01-15', 4),
|
||||||
|
dataPoint('2025-01-14', 6),
|
||||||
|
dataPoint('2025-01-06', 2),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiPath: '/api/client',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2025-01-02', 2),
|
||||||
|
dataPoint('2025-01-17', 6),
|
||||||
|
dataPoint('2025-01-19', 4),
|
||||||
|
dataPoint('2025-01-06', 8),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedOutput = {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
5, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 6, 4, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
...fromEndpointInfo('/api/admin'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: [
|
||||||
|
0, 2, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 4,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
],
|
||||||
|
...fromEndpointInfo('/api/client'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
labels: Array.from({ length: 31 }).map((_, index) =>
|
||||||
|
(index + 1).toString(),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(toChartData(input)).toMatchObject(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sorts endpoints according to endpoint data spec', () => {
|
||||||
|
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
||||||
|
grouping: 'daily',
|
||||||
|
dateRange: {
|
||||||
|
from: '2025-01-01',
|
||||||
|
to: '2025-01-31',
|
||||||
|
},
|
||||||
|
apiData: [
|
||||||
|
{ apiPath: '/api/frontend', dataPoints: [] },
|
||||||
|
{ apiPath: '/api/client', dataPoints: [] },
|
||||||
|
{ apiPath: '/api/admin', dataPoints: [] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const expectedOutput = {
|
||||||
|
datasets: [
|
||||||
|
{ label: 'Admin' },
|
||||||
|
{ label: 'Frontend' },
|
||||||
|
{ label: 'Server' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(toChartData(input)).toMatchObject(expectedOutput);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns empty data if traffic is undefined', () => {
|
||||||
|
expect(toChartData(undefined)).toStrictEqual({
|
||||||
|
labels: [],
|
||||||
|
datasets: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -11,113 +11,74 @@ import { formatDay, formatMonth } from './dates';
|
|||||||
import type { ChartDataSelection } from './chart-data-selection';
|
import type { ChartDataSelection } from './chart-data-selection';
|
||||||
export type ChartDatasetType = ChartDataset<'bar'>;
|
export type ChartDatasetType = ChartDataset<'bar'>;
|
||||||
|
|
||||||
// todo: test
|
|
||||||
export const toChartData = (
|
export const toChartData = (
|
||||||
traffic?: TrafficUsageDataSegmentedCombinedSchema,
|
traffic?: TrafficUsageDataSegmentedCombinedSchema,
|
||||||
): { datasets: ChartDatasetType[]; labels: (string | number)[] } => {
|
): { datasets: ChartDatasetType[]; labels: string[] } => {
|
||||||
if (!traffic) {
|
if (!traffic) {
|
||||||
return { labels: [], datasets: [] };
|
return { labels: [], datasets: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (traffic.grouping === 'monthly') {
|
const { newRecord, labels } = getLabelsAndRecords(traffic);
|
||||||
return toMonthlyChartData(traffic);
|
const datasets = traffic.apiData
|
||||||
} else {
|
|
||||||
return toDailyChartData(traffic);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
type SegmentedSchemaApiData =
|
|
||||||
TrafficUsageDataSegmentedCombinedSchema['apiData'][0];
|
|
||||||
|
|
||||||
// todo: integrate filtering `filterData` frontend/src/component/admin/network/NetworkTrafficUsage/util.ts
|
|
||||||
const prepareApiData = (
|
|
||||||
apiData: TrafficUsageDataSegmentedCombinedSchema['apiData'],
|
|
||||||
) =>
|
|
||||||
apiData
|
|
||||||
.filter((item) => item.apiPath in endpointsInfo)
|
|
||||||
.sort(
|
.sort(
|
||||||
(item1: SegmentedSchemaApiData, item2: SegmentedSchemaApiData) =>
|
(item1, item2) =>
|
||||||
endpointsInfo[item1.apiPath].order -
|
endpointsInfo[item1.apiPath].order -
|
||||||
endpointsInfo[item2.apiPath].order,
|
endpointsInfo[item2.apiPath].order,
|
||||||
);
|
)
|
||||||
|
.map((item) => {
|
||||||
const toMonthlyChartData = (
|
const record = newRecord();
|
||||||
traffic: TrafficUsageDataSegmentedCombinedSchema,
|
for (const dataPoint of Object.values(item.dataPoints)) {
|
||||||
): { datasets: ChartDatasetType[]; labels: string[] } => {
|
record[dataPoint.period] = dataPoint.trafficTypes[0].count;
|
||||||
const from = new Date(traffic.dateRange.from);
|
|
||||||
const to = new Date(traffic.dateRange.to);
|
|
||||||
const numMonths = Math.abs(differenceInCalendarMonths(to, from)) + 1;
|
|
||||||
|
|
||||||
const datasets = prepareApiData(traffic.apiData).map(
|
|
||||||
(item: SegmentedSchemaApiData) => {
|
|
||||||
const monthsRec: { [month: string]: number } = {};
|
|
||||||
for (let i = 0; i < numMonths; i++) {
|
|
||||||
monthsRec[formatMonth(addMonths(from, i))] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const month of Object.values(item.dataPoints)) {
|
|
||||||
monthsRec[month.period] = month.trafficTypes[0].count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const epInfo = endpointsInfo[item.apiPath];
|
const epInfo = endpointsInfo[item.apiPath];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
label: epInfo.label,
|
label: epInfo.label,
|
||||||
data: Object.values(monthsRec),
|
data: Object.values(record),
|
||||||
backgroundColor: epInfo.color,
|
backgroundColor: epInfo.color,
|
||||||
hoverBackgroundColor: epInfo.color,
|
hoverBackgroundColor: epInfo.color,
|
||||||
};
|
};
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
return { datasets, labels };
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLabelsAndRecords = (
|
||||||
|
traffic: TrafficUsageDataSegmentedCombinedSchema,
|
||||||
|
) => {
|
||||||
|
if (traffic.grouping === 'monthly') {
|
||||||
|
const from = new Date(traffic.dateRange.from);
|
||||||
|
const to = new Date(traffic.dateRange.to);
|
||||||
|
const numMonths = Math.abs(differenceInCalendarMonths(to, from)) + 1;
|
||||||
|
const monthsRec: { [month: string]: number } = {};
|
||||||
|
for (let i = 0; i < numMonths; i++) {
|
||||||
|
monthsRec[formatMonth(addMonths(from, i))] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
const labels = Array.from({ length: numMonths }).map((_, index) =>
|
const labels = Array.from({ length: numMonths }).map((_, index) =>
|
||||||
index === numMonths - 1
|
index === numMonths - 1
|
||||||
? 'Current month'
|
? 'Current month'
|
||||||
: formatMonth(addMonths(from, index)),
|
: formatMonth(addMonths(from, index)),
|
||||||
);
|
);
|
||||||
|
return { newRecord: () => ({ ...monthsRec }), labels };
|
||||||
return { datasets, labels };
|
} else {
|
||||||
};
|
|
||||||
|
|
||||||
const toDailyChartData = (
|
|
||||||
traffic: TrafficUsageDataSegmentedCombinedSchema,
|
|
||||||
): { datasets: ChartDatasetType[]; labels: number[] } => {
|
|
||||||
const from = new Date(traffic.dateRange.from);
|
const from = new Date(traffic.dateRange.from);
|
||||||
const to = new Date(traffic.dateRange.to);
|
const to = new Date(traffic.dateRange.to);
|
||||||
const numDays = Math.abs(differenceInCalendarDays(to, from)) + 1;
|
const numDays = Math.abs(differenceInCalendarDays(to, from)) + 1;
|
||||||
|
|
||||||
const daysRec: { [day: string]: number } = {};
|
const daysRec: { [day: string]: number } = {};
|
||||||
for (let i = 0; i < numDays; i++) {
|
for (let i = 0; i < numDays; i++) {
|
||||||
daysRec[formatDay(addDays(from, i))] = 0;
|
daysRec[formatDay(addDays(from, i))] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDaysRec = () => ({
|
// simplification: the chart only allows for single, full-month views
|
||||||
...daysRec,
|
// when you use a daily chart, so just use the day of the month as the label
|
||||||
});
|
const labels = Array.from({ length: numDays }).map((_, index) =>
|
||||||
|
(index + 1).toString(),
|
||||||
const datasets = prepareApiData(traffic.apiData).map(
|
|
||||||
(item: SegmentedSchemaApiData) => {
|
|
||||||
const daysRec = getDaysRec();
|
|
||||||
|
|
||||||
for (const day of Object.values(item.dataPoints)) {
|
|
||||||
daysRec[day.period] = day.trafficTypes[0].count;
|
|
||||||
}
|
|
||||||
|
|
||||||
const epInfo = endpointsInfo[item.apiPath];
|
|
||||||
|
|
||||||
return {
|
|
||||||
label: epInfo.label,
|
|
||||||
data: Object.values(daysRec),
|
|
||||||
backgroundColor: epInfo.color,
|
|
||||||
hoverBackgroundColor: epInfo.color,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// simplification: assuming days run in a single month from the 1st onwards
|
return { newRecord: () => ({ ...daysRec }), labels };
|
||||||
const labels = Array.from({ length: numDays }).map((_, index) => index + 1);
|
}
|
||||||
|
|
||||||
return { datasets, labels };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const [lastLabel, ...otherLabels] = Object.values(endpointsInfo)
|
const [lastLabel, ...otherLabels] = Object.values(endpointsInfo)
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
import { generateSelectablePeriodsFromDate } from './selectable-periods';
|
||||||
|
|
||||||
|
test('marks months before May 2024 as unselectable', () => {
|
||||||
|
const now = new Date('2025-01-01');
|
||||||
|
const selectablePeriods = generateSelectablePeriodsFromDate(now);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
selectablePeriods.map(({ key, selectable }) => ({ key, selectable })),
|
||||||
|
).toEqual([
|
||||||
|
{ key: '2025-01', selectable: true },
|
||||||
|
{ key: '2024-12', selectable: true },
|
||||||
|
{ key: '2024-11', selectable: true },
|
||||||
|
{ key: '2024-10', selectable: true },
|
||||||
|
{ key: '2024-09', selectable: true },
|
||||||
|
{ key: '2024-08', selectable: true },
|
||||||
|
{ key: '2024-07', selectable: true },
|
||||||
|
{ key: '2024-06', selectable: true },
|
||||||
|
{ key: '2024-05', selectable: true },
|
||||||
|
{ key: '2024-04', selectable: false },
|
||||||
|
{ key: '2024-03', selectable: false },
|
||||||
|
{ key: '2024-02', selectable: false },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('generates 12 months, including the current month', () => {
|
||||||
|
const now = new Date('2025-01-01');
|
||||||
|
const selectablePeriods = generateSelectablePeriodsFromDate(now);
|
||||||
|
|
||||||
|
expect(selectablePeriods.length).toBe(12);
|
||||||
|
expect(selectablePeriods[0].label).toBe('Current month');
|
||||||
|
});
|
@ -1,4 +1,4 @@
|
|||||||
import { getDaysInMonth, subMonths } from 'date-fns';
|
import { getDaysInMonth } from 'date-fns';
|
||||||
import { currentDate, formatMonth } from './dates';
|
import { currentDate, formatMonth } from './dates';
|
||||||
import { TRAFFIC_MEASUREMENT_START_DATE } from 'utils/traffic-calculations';
|
import { TRAFFIC_MEASUREMENT_START_DATE } from 'utils/traffic-calculations';
|
||||||
|
|
||||||
@ -36,20 +36,23 @@ export const toSelectablePeriod = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo: test
|
export const generateSelectablePeriodsFromDate = (now: Date) => {
|
||||||
const generateSelectablePeriodsFromDate = (now: Date) => {
|
|
||||||
const selectablePeriods = [toSelectablePeriod(now, 'Current month')];
|
const selectablePeriods = [toSelectablePeriod(now, 'Current month')];
|
||||||
for (
|
for (
|
||||||
let subtractMonthCount = 1;
|
let subtractMonthCount = 1;
|
||||||
subtractMonthCount < 12;
|
subtractMonthCount < 12;
|
||||||
subtractMonthCount++
|
subtractMonthCount++
|
||||||
) {
|
) {
|
||||||
const date = subMonths(now, subtractMonthCount);
|
// this complicated calc avoids DST issues
|
||||||
|
const utcYear = now.getUTCFullYear();
|
||||||
|
const utcMonth = now.getUTCMonth();
|
||||||
|
const targetMonth = utcMonth - subtractMonthCount;
|
||||||
|
const targetDate = new Date(Date.UTC(utcYear, targetMonth, 1, 0, 0, 0));
|
||||||
selectablePeriods.push(
|
selectablePeriods.push(
|
||||||
toSelectablePeriod(
|
toSelectablePeriod(
|
||||||
date,
|
targetDate,
|
||||||
undefined,
|
undefined,
|
||||||
date >= TRAFFIC_MEASUREMENT_START_DATE,
|
targetDate >= TRAFFIC_MEASUREMENT_START_DATE,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
calculateEstimatedMonthlyCost,
|
calculateEstimatedMonthlyCost,
|
||||||
calculateOverageCost,
|
calculateOverageCost,
|
||||||
calculateProjectedUsage,
|
calculateProjectedUsage,
|
||||||
|
calculateTotalUsage,
|
||||||
cleanTrafficData,
|
cleanTrafficData,
|
||||||
} from './traffic-calculations';
|
} from './traffic-calculations';
|
||||||
import { toSelectablePeriod } from '../component/admin/network/NetworkTrafficUsage/selectable-periods';
|
import { toSelectablePeriod } from '../component/admin/network/NetworkTrafficUsage/selectable-periods';
|
||||||
@ -146,7 +147,7 @@ describe('traffic overage calculation', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('filtering out unwanted data', () => {
|
describe('filtering out unwanted data', () => {
|
||||||
test('it removes the /edge endpoint data', () => {
|
it('removes the /edge endpoint data', () => {
|
||||||
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
||||||
grouping: 'daily',
|
grouping: 'daily',
|
||||||
dateRange: { from: '2025-02-01', to: '2025-02-28' },
|
dateRange: { from: '2025-02-01', to: '2025-02-28' },
|
||||||
@ -171,7 +172,7 @@ describe('filtering out unwanted data', () => {
|
|||||||
expect(cleanTrafficData(input)).toStrictEqual(expected);
|
expect(cleanTrafficData(input)).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('it removes any data from before the traffic measuring was put in place', () => {
|
it('removes any data from before the traffic measuring was put in place', () => {
|
||||||
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
||||||
grouping: 'monthly',
|
grouping: 'monthly',
|
||||||
dateRange: {
|
dateRange: {
|
||||||
@ -212,3 +213,79 @@ describe('filtering out unwanted data', () => {
|
|||||||
expect(cleanTrafficData(input)).toStrictEqual(expected);
|
expect(cleanTrafficData(input)).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('calculateTotalUsage', () => {
|
||||||
|
const dataPoint = (period: string, count: number) => ({
|
||||||
|
period,
|
||||||
|
trafficTypes: [{ count, group: 'successful-requests' }],
|
||||||
|
});
|
||||||
|
it('calculates total from daily data', () => {
|
||||||
|
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
||||||
|
grouping: 'daily',
|
||||||
|
dateRange: { from: '2025-02-01', to: '2025-02-28' },
|
||||||
|
apiData: [
|
||||||
|
{
|
||||||
|
apiPath: '/api/client',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2024-02-01', 1),
|
||||||
|
dataPoint('2024-02-15', 2),
|
||||||
|
dataPoint('2024-02-07', 3),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiPath: '/api/admin',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2024-02-01', 4),
|
||||||
|
dataPoint('2024-02-15', 5),
|
||||||
|
dataPoint('2024-02-07', 6),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiPath: '/api/frontend',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2024-02-01', 7),
|
||||||
|
dataPoint('2024-02-15', 8),
|
||||||
|
dataPoint('2024-02-07', 9),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(calculateTotalUsage(input)).toBe(45);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calculates total for the most recent month in monthly data', () => {
|
||||||
|
const input: TrafficUsageDataSegmentedCombinedSchema = {
|
||||||
|
grouping: 'monthly',
|
||||||
|
dateRange: { from: '2024-10-01', to: '2025-01-31' },
|
||||||
|
apiData: [
|
||||||
|
{
|
||||||
|
apiPath: '/api/client',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2025-01', 1),
|
||||||
|
dataPoint('2024-12', 2),
|
||||||
|
dataPoint('2024-10', 3),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiPath: '/api/admin',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2025-01', 4),
|
||||||
|
dataPoint('2024-11', 5),
|
||||||
|
dataPoint('2024-10', 6),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiPath: '/api/frontend',
|
||||||
|
dataPoints: [
|
||||||
|
dataPoint('2024-11', 7),
|
||||||
|
dataPoint('2024-12', 8),
|
||||||
|
dataPoint('2024-10', 9),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(calculateTotalUsage(input)).toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
daysInCurrentMonth,
|
daysInCurrentMonth,
|
||||||
} from '../component/admin/network/NetworkTrafficUsage/dates';
|
} from '../component/admin/network/NetworkTrafficUsage/dates';
|
||||||
import type { ChartDatasetType } from '../component/admin/network/NetworkTrafficUsage/chart-functions';
|
import type { ChartDatasetType } from '../component/admin/network/NetworkTrafficUsage/chart-functions';
|
||||||
|
import { format } from 'date-fns';
|
||||||
|
|
||||||
const DEFAULT_TRAFFIC_DATA_UNIT_COST = 5;
|
const DEFAULT_TRAFFIC_DATA_UNIT_COST = 5;
|
||||||
const DEFAULT_TRAFFIC_DATA_UNIT_SIZE = 1_000_000;
|
const DEFAULT_TRAFFIC_DATA_UNIT_SIZE = 1_000_000;
|
||||||
@ -39,13 +40,13 @@ export const cleanTrafficData = (
|
|||||||
return { apiData: cleanedApiData, ...rest };
|
return { apiData: cleanedApiData, ...rest };
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo: extract "currentMonth" into a function argument instead
|
|
||||||
const monthlyTrafficDataToCurrentUsage = (
|
const monthlyTrafficDataToCurrentUsage = (
|
||||||
apiData: TrafficUsageDataSegmentedCombinedSchemaApiDataItem[],
|
apiData: TrafficUsageDataSegmentedCombinedSchemaApiDataItem[],
|
||||||
|
latestMonth: string,
|
||||||
) => {
|
) => {
|
||||||
return apiData.reduce((acc, current) => {
|
return apiData.reduce((acc, current) => {
|
||||||
const currentPoint = current.dataPoints.find(
|
const currentPoint = current.dataPoints.find(
|
||||||
({ period }) => period === currentMonth,
|
({ period }) => period === latestMonth,
|
||||||
);
|
);
|
||||||
const pointUsage =
|
const pointUsage =
|
||||||
currentPoint?.trafficTypes.reduce(
|
currentPoint?.trafficTypes.reduce(
|
||||||
@ -68,9 +69,8 @@ const dailyTrafficDataToCurrentUsage = (
|
|||||||
.reduce((acc, count) => acc + count, 0);
|
.reduce((acc, count) => acc + count, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo: test
|
|
||||||
// Return the total number of requests for the selected month if showing daily
|
// Return the total number of requests for the selected month if showing daily
|
||||||
// data, or the current month if showing monthly data
|
// data, or the total for the most recent month if showing monthly data
|
||||||
export const calculateTotalUsage = (
|
export const calculateTotalUsage = (
|
||||||
data?: TrafficUsageDataSegmentedCombinedSchema,
|
data?: TrafficUsageDataSegmentedCombinedSchema,
|
||||||
): number => {
|
): number => {
|
||||||
@ -78,9 +78,12 @@ export const calculateTotalUsage = (
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const { grouping, apiData } = data;
|
const { grouping, apiData } = data;
|
||||||
return grouping === 'monthly'
|
if (grouping === 'monthly') {
|
||||||
? monthlyTrafficDataToCurrentUsage(apiData)
|
const latestMonth = format(new Date(data.dateRange.to), 'yyyy-MM');
|
||||||
: dailyTrafficDataToCurrentUsage(apiData);
|
return monthlyTrafficDataToCurrentUsage(apiData, latestMonth);
|
||||||
|
} else {
|
||||||
|
return dailyTrafficDataToCurrentUsage(apiData);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const calculateTrafficDataCost = (
|
const calculateTrafficDataCost = (
|
||||||
|
Loading…
Reference in New Issue
Block a user