mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02: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(
 | 
			
		||||
        chartDataSelection.grouping,
 | 
			
		||||
        toDateRange(chartDataSelection),
 | 
			
		||||
        toDateRange(chartDataSelection, currentDate),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
// todo: write test
 | 
			
		||||
export const toDateRange = (
 | 
			
		||||
    selection: ChartDataSelection,
 | 
			
		||||
    now = new Date(),
 | 
			
		||||
): { from: string; to: string } => {
 | 
			
		||||
    const fmt = (date: Date) => format(date, 'yyyy-MM-dd');
 | 
			
		||||
    if (selection.grouping === 'daily') {
 | 
			
		||||
@ -21,7 +21,6 @@ export const toDateRange = (
 | 
			
		||||
        const to = fmt(endOfMonth(month));
 | 
			
		||||
        return { from, to };
 | 
			
		||||
    } else {
 | 
			
		||||
        const now = new Date();
 | 
			
		||||
        const from = fmt(startOfMonth(subMonths(now, selection.monthsBack)));
 | 
			
		||||
        const to = fmt(endOfMonth(now));
 | 
			
		||||
        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';
 | 
			
		||||
export type ChartDatasetType = ChartDataset<'bar'>;
 | 
			
		||||
 | 
			
		||||
// todo: test
 | 
			
		||||
export const toChartData = (
 | 
			
		||||
    traffic?: TrafficUsageDataSegmentedCombinedSchema,
 | 
			
		||||
): { datasets: ChartDatasetType[]; labels: (string | number)[] } => {
 | 
			
		||||
): { datasets: ChartDatasetType[]; labels: string[] } => {
 | 
			
		||||
    if (!traffic) {
 | 
			
		||||
        return { labels: [], datasets: [] };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (traffic.grouping === 'monthly') {
 | 
			
		||||
        return toMonthlyChartData(traffic);
 | 
			
		||||
    } 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)
 | 
			
		||||
    const { newRecord, labels } = getLabelsAndRecords(traffic);
 | 
			
		||||
    const datasets = traffic.apiData
 | 
			
		||||
        .sort(
 | 
			
		||||
            (item1: SegmentedSchemaApiData, item2: SegmentedSchemaApiData) =>
 | 
			
		||||
            (item1, item2) =>
 | 
			
		||||
                endpointsInfo[item1.apiPath].order -
 | 
			
		||||
                endpointsInfo[item2.apiPath].order,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
const toMonthlyChartData = (
 | 
			
		||||
    traffic: TrafficUsageDataSegmentedCombinedSchema,
 | 
			
		||||
): { datasets: ChartDatasetType[]; labels: string[] } => {
 | 
			
		||||
    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;
 | 
			
		||||
        )
 | 
			
		||||
        .map((item) => {
 | 
			
		||||
            const record = newRecord();
 | 
			
		||||
            for (const dataPoint of Object.values(item.dataPoints)) {
 | 
			
		||||
                record[dataPoint.period] = dataPoint.trafficTypes[0].count;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const epInfo = endpointsInfo[item.apiPath];
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                label: epInfo.label,
 | 
			
		||||
                data: Object.values(monthsRec),
 | 
			
		||||
                data: Object.values(record),
 | 
			
		||||
                backgroundColor: epInfo.color,
 | 
			
		||||
                hoverBackgroundColor: epInfo.color,
 | 
			
		||||
            };
 | 
			
		||||
        },
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const labels = Array.from({ length: numMonths }).map((_, index) =>
 | 
			
		||||
        index === numMonths - 1
 | 
			
		||||
            ? 'Current month'
 | 
			
		||||
            : formatMonth(addMonths(from, index)),
 | 
			
		||||
    );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    return { datasets, labels };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const toDailyChartData = (
 | 
			
		||||
const getLabelsAndRecords = (
 | 
			
		||||
    traffic: TrafficUsageDataSegmentedCombinedSchema,
 | 
			
		||||
): { datasets: ChartDatasetType[]; labels: number[] } => {
 | 
			
		||||
    const from = new Date(traffic.dateRange.from);
 | 
			
		||||
    const to = new Date(traffic.dateRange.to);
 | 
			
		||||
    const numDays = Math.abs(differenceInCalendarDays(to, from)) + 1;
 | 
			
		||||
) => {
 | 
			
		||||
    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 daysRec: { [day: string]: number } = {};
 | 
			
		||||
    for (let i = 0; i < numDays; i++) {
 | 
			
		||||
        daysRec[formatDay(addDays(from, i))] = 0;
 | 
			
		||||
        const labels = Array.from({ length: numMonths }).map((_, index) =>
 | 
			
		||||
            index === numMonths - 1
 | 
			
		||||
                ? 'Current month'
 | 
			
		||||
                : formatMonth(addMonths(from, index)),
 | 
			
		||||
        );
 | 
			
		||||
        return { newRecord: () => ({ ...monthsRec }), labels };
 | 
			
		||||
    } else {
 | 
			
		||||
        const from = new Date(traffic.dateRange.from);
 | 
			
		||||
        const to = new Date(traffic.dateRange.to);
 | 
			
		||||
        const numDays = Math.abs(differenceInCalendarDays(to, from)) + 1;
 | 
			
		||||
        const daysRec: { [day: string]: number } = {};
 | 
			
		||||
        for (let i = 0; i < numDays; i++) {
 | 
			
		||||
            daysRec[formatDay(addDays(from, i))] = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // simplification: the chart only allows for single, full-month views
 | 
			
		||||
        // 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(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return { newRecord: () => ({ ...daysRec }), labels };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const getDaysRec = () => ({
 | 
			
		||||
        ...daysRec,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    const labels = Array.from({ length: numDays }).map((_, index) => index + 1);
 | 
			
		||||
 | 
			
		||||
    return { datasets, labels };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 { TRAFFIC_MEASUREMENT_START_DATE } from 'utils/traffic-calculations';
 | 
			
		||||
 | 
			
		||||
@ -36,20 +36,23 @@ export const toSelectablePeriod = (
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// todo: test
 | 
			
		||||
const generateSelectablePeriodsFromDate = (now: Date) => {
 | 
			
		||||
export const generateSelectablePeriodsFromDate = (now: Date) => {
 | 
			
		||||
    const selectablePeriods = [toSelectablePeriod(now, 'Current month')];
 | 
			
		||||
    for (
 | 
			
		||||
        let subtractMonthCount = 1;
 | 
			
		||||
        subtractMonthCount < 12;
 | 
			
		||||
        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(
 | 
			
		||||
            toSelectablePeriod(
 | 
			
		||||
                date,
 | 
			
		||||
                targetDate,
 | 
			
		||||
                undefined,
 | 
			
		||||
                date >= TRAFFIC_MEASUREMENT_START_DATE,
 | 
			
		||||
                targetDate >= TRAFFIC_MEASUREMENT_START_DATE,
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ import {
 | 
			
		||||
    calculateEstimatedMonthlyCost,
 | 
			
		||||
    calculateOverageCost,
 | 
			
		||||
    calculateProjectedUsage,
 | 
			
		||||
    calculateTotalUsage,
 | 
			
		||||
    cleanTrafficData,
 | 
			
		||||
} from './traffic-calculations';
 | 
			
		||||
import { toSelectablePeriod } from '../component/admin/network/NetworkTrafficUsage/selectable-periods';
 | 
			
		||||
@ -146,7 +147,7 @@ describe('traffic overage calculation', () => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('filtering out unwanted data', () => {
 | 
			
		||||
    test('it removes the /edge endpoint data', () => {
 | 
			
		||||
    it('removes the /edge endpoint data', () => {
 | 
			
		||||
        const input: TrafficUsageDataSegmentedCombinedSchema = {
 | 
			
		||||
            grouping: 'daily',
 | 
			
		||||
            dateRange: { from: '2025-02-01', to: '2025-02-28' },
 | 
			
		||||
@ -171,7 +172,7 @@ describe('filtering out unwanted data', () => {
 | 
			
		||||
        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 = {
 | 
			
		||||
            grouping: 'monthly',
 | 
			
		||||
            dateRange: {
 | 
			
		||||
@ -212,3 +213,79 @@ describe('filtering out unwanted data', () => {
 | 
			
		||||
        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,
 | 
			
		||||
} from '../component/admin/network/NetworkTrafficUsage/dates';
 | 
			
		||||
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_SIZE = 1_000_000;
 | 
			
		||||
@ -39,13 +40,13 @@ export const cleanTrafficData = (
 | 
			
		||||
    return { apiData: cleanedApiData, ...rest };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// todo: extract "currentMonth" into a function argument instead
 | 
			
		||||
const monthlyTrafficDataToCurrentUsage = (
 | 
			
		||||
    apiData: TrafficUsageDataSegmentedCombinedSchemaApiDataItem[],
 | 
			
		||||
    latestMonth: string,
 | 
			
		||||
) => {
 | 
			
		||||
    return apiData.reduce((acc, current) => {
 | 
			
		||||
        const currentPoint = current.dataPoints.find(
 | 
			
		||||
            ({ period }) => period === currentMonth,
 | 
			
		||||
            ({ period }) => period === latestMonth,
 | 
			
		||||
        );
 | 
			
		||||
        const pointUsage =
 | 
			
		||||
            currentPoint?.trafficTypes.reduce(
 | 
			
		||||
@ -68,9 +69,8 @@ const dailyTrafficDataToCurrentUsage = (
 | 
			
		||||
        .reduce((acc, count) => acc + count, 0);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// todo: test
 | 
			
		||||
// 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 = (
 | 
			
		||||
    data?: TrafficUsageDataSegmentedCombinedSchema,
 | 
			
		||||
): number => {
 | 
			
		||||
@ -78,9 +78,12 @@ export const calculateTotalUsage = (
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    const { grouping, apiData } = data;
 | 
			
		||||
    return grouping === 'monthly'
 | 
			
		||||
        ? monthlyTrafficDataToCurrentUsage(apiData)
 | 
			
		||||
        : dailyTrafficDataToCurrentUsage(apiData);
 | 
			
		||||
    if (grouping === 'monthly') {
 | 
			
		||||
        const latestMonth = format(new Date(data.dateRange.to), 'yyyy-MM');
 | 
			
		||||
        return monthlyTrafficDataToCurrentUsage(apiData, latestMonth);
 | 
			
		||||
    } else {
 | 
			
		||||
        return dailyTrafficDataToCurrentUsage(apiData);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const calculateTrafficDataCost = (
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user