Commit 1228a9ea authored by Brandon Labuschagne's avatar Brandon Labuschagne

Merge branch 'led/fe-usage-quotas-refactor-2' into 'master'

Move namespace storage_counter to new usage_quotas folder

See merge request gitlab-org/gitlab!75514
parents e6e8b81d d5fd3f9c
import SeatUsageApp from 'ee/seat_usage';
import storageCounter from 'ee/storage_counter';
import initNamespaceStorage from 'ee/usage_quotas/storage/init_namespace_storage';
import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
import initSearchSettings from '~/search_settings';
......@@ -21,7 +21,7 @@ const initVueApps = () => {
}
if (document.querySelector('#js-storage-counter-app')) {
storageCounter();
initNamespaceStorage();
}
};
......
import ciMinutesUsage from 'ee/ci_minutes_usage';
import storageCounter from 'ee/storage_counter';
import initNamespaceStorage from 'ee/usage_quotas/storage/init_namespace_storage';
import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
if (document.querySelector('#js-storage-counter-app')) {
storageCounter();
initNamespaceStorage();
// eslint-disable-next-line no-new
new LinkedTabs({
......
export const NONE_THRESHOLD = 'none';
export const INFO_THRESHOLD = 'info';
export const WARNING_THRESHOLD = 'warning';
export const ALERT_THRESHOLD = 'alert';
export const ERROR_THRESHOLD = 'error';
export const STORAGE_USAGE_THRESHOLDS = {
[NONE_THRESHOLD]: 0.0,
[INFO_THRESHOLD]: 0.5,
[WARNING_THRESHOLD]: 0.75,
[ALERT_THRESHOLD]: 0.95,
[ERROR_THRESHOLD]: 1.0,
};
export const PROJECTS_PER_PAGE = 20;
import { numberToHumanSize, bytesToKiB } from '~/lib/utils/number_utils';
import { getFormatter, SUPPORTED_FORMATS } from '~/lib/utils/unit_format';
import { STORAGE_USAGE_THRESHOLDS } from './constants';
export function usageRatioToThresholdLevel(currentUsageRatio) {
let currentLevel = Object.keys(STORAGE_USAGE_THRESHOLDS)[0];
Object.keys(STORAGE_USAGE_THRESHOLDS).forEach((thresholdLevel) => {
if (currentUsageRatio >= STORAGE_USAGE_THRESHOLDS[thresholdLevel])
currentLevel = thresholdLevel;
});
return currentLevel;
}
/**
* Formats given bytes to formatted human readable size
*
* We want to display all units above bytes. Hence
* converting bytesToKiB before passing it to
* `getFormatter`
* @param {Number} size size in bytes
* @returns {String}
*/
export const formatUsageSize = (size) => {
const formatDecimalBytes = getFormatter(SUPPORTED_FORMATS.kibibytes);
return formatDecimalBytes(bytesToKiB(size), 1);
};
/**
* Parses each project to add additional purchased data
* equally so that locked projects can be unlocked.
*
* For example, if a group contains the below projects and
* project 2, 3 have exceeded the default 10.0 GB limit.
* 2 and 3 will remain locked until user purchases additional
* data.
*
* Project 1: 7.0GB
* Project 2: 13.0GB Locked
* Project 3: 12.0GB Locked
*
* If user purchases X GB, it will be equally available
* to all the locked projects for further use.
*
* @param {Object} data project
* @param {Number} purchasedStorageRemaining Remaining purchased data in bytes
* @returns {Object}
*/
export const calculateUsedAndRemStorage = (project, purchasedStorageRemaining) => {
// We only consider repo size and lfs object size as of %13.5
const totalCalculatedUsedStorage =
project.statistics.repositorySize + project.statistics.lfsObjectsSize;
// If a project size is above the default limit, then the remaining
// storage value will be calculated on top of the project size as
// opposed to the default limit.
// This
const totalCalculatedStorageLimit =
totalCalculatedUsedStorage > project.actualRepositorySizeLimit
? totalCalculatedUsedStorage + purchasedStorageRemaining
: project.actualRepositorySizeLimit + purchasedStorageRemaining;
return {
...project,
totalCalculatedUsedStorage,
totalCalculatedStorageLimit,
};
};
/**
* Parses projects coming in from GraphQL response
* and patches each project with purchased related
* data
*
* @param {Array} params.projects list of projects
* @param {Number} params.additionalPurchasedStorageSize Amt purchased in bytes
* @param {Number} params.totalRepositorySizeExcess Sum of excess amounts on all projects
* @returns {Array}
*/
export const parseProjects = ({
projects,
additionalPurchasedStorageSize = 0,
totalRepositorySizeExcess = 0,
}) => {
const purchasedStorageRemaining = Math.max(
0,
additionalPurchasedStorageSize - totalRepositorySizeExcess,
);
return projects.nodes.map((project) =>
calculateUsedAndRemStorage(project, purchasedStorageRemaining),
);
};
/**
* This method parses the results from `getStorageCounter`
* call.
*
* `rootStorageStatistics` will be sent as null until an
* event happens to trigger the storage count.
* For that reason we have to verify if `storageSize` is sent or
* if we should render N/A
*
* @param {Object} data graphql result
* @returns {Object}
*/
export const parseGetStorageResults = (data) => {
const {
namespace: {
projects,
storageSizeLimit,
totalRepositorySize,
containsLockedProjects,
totalRepositorySizeExcess,
rootStorageStatistics = {},
actualRepositorySizeLimit,
additionalPurchasedStorageSize,
repositorySizeExcessProjectCount,
},
} = data || {};
const totalUsage = rootStorageStatistics?.storageSize
? numberToHumanSize(rootStorageStatistics.storageSize)
: 'N/A';
return {
projects: {
data: parseProjects({
projects,
additionalPurchasedStorageSize,
totalRepositorySizeExcess,
}),
pageInfo: projects.pageInfo,
},
additionalPurchasedStorageSize,
actualRepositorySizeLimit,
containsLockedProjects,
repositorySizeExcessProjectCount,
totalRepositorySize,
totalRepositorySizeExcess,
totalUsage,
rootStorageStatistics,
limit: storageSizeLimit,
};
};
......@@ -10,16 +10,16 @@ import {
import { parseBoolean } from '~/lib/utils/common_utils';
import UsageGraph from '~/vue_shared/components/storage_counter/usage_graph.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ProjectList from 'ee/usage_quotas/storage/components/project_list.vue';
import { PROJECTS_PER_PAGE } from '../constants';
import query from '../queries/storage.query.graphql';
import query from '../queries/namespace_storage.query.graphql';
import { formatUsageSize, parseGetStorageResults } from '../utils';
import ProjectList from './project_list.vue';
import StorageInlineAlert from './storage_inline_alert.vue';
import TemporaryStorageIncreaseModal from './temporary_storage_increase_modal.vue';
import UsageStatistics from './usage_statistics.vue';
export default {
name: 'StorageCounterApp',
name: 'NamespaceStorageApp',
components: {
GlLink,
GlIcon,
......
......@@ -60,3 +60,19 @@ export const PROJECT_TABLE_LABEL_STORAGE_TYPE = s__('UsageQuota|Storage type');
export const PROJECT_TABLE_LABEL_USAGE = s__('UsageQuota|Usage');
export const SKELETON_LOADER_ROWS = 5;
export const NONE_THRESHOLD = 'none';
export const INFO_THRESHOLD = 'info';
export const WARNING_THRESHOLD = 'warning';
export const ALERT_THRESHOLD = 'alert';
export const ERROR_THRESHOLD = 'error';
export const STORAGE_USAGE_THRESHOLDS = {
[NONE_THRESHOLD]: 0.0,
[INFO_THRESHOLD]: 0.5,
[WARNING_THRESHOLD]: 0.75,
[ALERT_THRESHOLD]: 0.95,
[ERROR_THRESHOLD]: 1.0,
};
export const PROJECTS_PER_PAGE = 20;
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import App from './components/app.vue';
import NamespaceStorageApp from './components/namespace_storage_app.vue';
Vue.use(VueApollo);
......@@ -21,8 +21,8 @@ export default () => {
return new Vue({
el,
apolloProvider,
render(h) {
return h(App, {
render(createElement) {
return createElement(NamespaceStorageApp, {
props: {
namespacePath,
helpPagePath,
......
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
query getStorageCounter(
query getNamespaceStorageStatistics(
$fullPath: ID!
$withExcessStorageData: Boolean = false
$searchTerm: String = ""
......
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { PROJECT_STORAGE_TYPES } from './constants';
import { numberToHumanSize, bytesToKiB } from '~/lib/utils/number_utils';
import { getFormatter, SUPPORTED_FORMATS } from '~/lib/utils/unit_format';
import { PROJECT_STORAGE_TYPES, STORAGE_USAGE_THRESHOLDS } from './constants';
export function usageRatioToThresholdLevel(currentUsageRatio) {
let currentLevel = Object.keys(STORAGE_USAGE_THRESHOLDS)[0];
Object.keys(STORAGE_USAGE_THRESHOLDS).forEach((thresholdLevel) => {
if (currentUsageRatio >= STORAGE_USAGE_THRESHOLDS[thresholdLevel])
currentLevel = thresholdLevel;
});
return currentLevel;
}
/**
* Formats given bytes to formatted human readable size
*
* We want to display all units above bytes. Hence
* converting bytesToKiB before passing it to
* `getFormatter`
* @param {Number} size size in bytes
* @returns {String}
*/
export const formatUsageSize = (size) => {
const formatDecimalBytes = getFormatter(SUPPORTED_FORMATS.kibibytes);
return formatDecimalBytes(bytesToKiB(size), 1);
};
/**
* Parses each project to add additional purchased data
* equally so that locked projects can be unlocked.
*
* For example, if a group contains the below projects and
* project 2, 3 have exceeded the default 10.0 GB limit.
* 2 and 3 will remain locked until user purchases additional
* data.
*
* Project 1: 7.0GB
* Project 2: 13.0GB Locked
* Project 3: 12.0GB Locked
*
* If user purchases X GB, it will be equally available
* to all the locked projects for further use.
*
* @param {Object} data project
* @param {Number} purchasedStorageRemaining Remaining purchased data in bytes
* @returns {Object}
*/
export const calculateUsedAndRemStorage = (project, purchasedStorageRemaining) => {
// We only consider repo size and lfs object size as of %13.5
const totalCalculatedUsedStorage =
project.statistics.repositorySize + project.statistics.lfsObjectsSize;
// If a project size is above the default limit, then the remaining
// storage value will be calculated on top of the project size as
// opposed to the default limit.
// This
const totalCalculatedStorageLimit =
totalCalculatedUsedStorage > project.actualRepositorySizeLimit
? totalCalculatedUsedStorage + purchasedStorageRemaining
: project.actualRepositorySizeLimit + purchasedStorageRemaining;
return {
...project,
totalCalculatedUsedStorage,
totalCalculatedStorageLimit,
};
};
/**
* Parses projects coming in from GraphQL response
* and patches each project with purchased related
* data
*
* @param {Array} params.projects list of projects
* @param {Number} params.additionalPurchasedStorageSize Amt purchased in bytes
* @param {Number} params.totalRepositorySizeExcess Sum of excess amounts on all projects
* @returns {Array}
*/
export const parseProjects = ({
projects,
additionalPurchasedStorageSize = 0,
totalRepositorySizeExcess = 0,
}) => {
const purchasedStorageRemaining = Math.max(
0,
additionalPurchasedStorageSize - totalRepositorySizeExcess,
);
return projects.nodes.map((project) =>
calculateUsedAndRemStorage(project, purchasedStorageRemaining),
);
};
/**
* This method parses the results from `getNamespaceStorageStatistics`
* call.
*
* `rootStorageStatistics` will be sent as null until an
* event happens to trigger the storage count.
* For that reason we have to verify if `storageSize` is sent or
* if we should render N/A
*
* @param {Object} data graphql result
* @returns {Object}
*/
export const parseGetStorageResults = (data) => {
const {
namespace: {
projects,
storageSizeLimit,
totalRepositorySize,
containsLockedProjects,
totalRepositorySizeExcess,
rootStorageStatistics = {},
actualRepositorySizeLimit,
additionalPurchasedStorageSize,
repositorySizeExcessProjectCount,
},
} = data || {};
const totalUsage = rootStorageStatistics?.storageSize
? numberToHumanSize(rootStorageStatistics.storageSize)
: 'N/A';
return {
projects: {
data: parseProjects({
projects,
additionalPurchasedStorageSize,
totalRepositorySizeExcess,
}),
pageInfo: projects.pageInfo,
},
additionalPurchasedStorageSize,
actualRepositorySizeLimit,
containsLockedProjects,
repositorySizeExcessProjectCount,
totalRepositorySize,
totalRepositorySizeExcess,
totalUsage,
rootStorageStatistics,
limit: storageSizeLimit,
};
};
export const getStorageTypesFromProjectStatistics = (projectStatistics, helpLinks = {}) =>
PROJECT_STORAGE_TYPES.reduce((types, currentType) => {
......
import { projects } from 'ee_jest/usage_quotas/storage/mock_data';
export const namespaceData = {
totalUsage: 'N/A',
limit: 10000000,
projects: { data: projects },
};
export const withRootStorageStatistics = {
projects,
limit: 10000000,
totalUsage: 129334601,
containsLockedProjects: true,
repositorySizeExcessProjectCount: 1,
totalRepositorySizeExcess: 2321,
totalRepositorySize: 1002321,
additionalPurchasedStorageSize: 321,
actualRepositorySizeLimit: 1002321,
rootStorageStatistics: {
storageSize: 129334601,
repositorySize: 46012030,
lfsObjectsSize: 4329334601203,
buildArtifactsSize: 1272375,
packagesSize: 123123120,
wikiSize: 1000,
snippetsSize: 10000,
},
};
export const mockGetStorageCounterGraphQLResponse = {
nodes: projects.map((node) => node),
};
import {
usageRatioToThresholdLevel,
formatUsageSize,
parseProjects,
calculateUsedAndRemStorage,
} from 'ee/storage_counter/utils';
import { projects as mockProjectsData } from 'ee_jest/usage_quotas/storage/mock_data';
import { mockGetStorageCounterGraphQLResponse } from './mock_data';
describe('UsageThreshold', () => {
it.each`
usageRatio | expectedLevel
${0} | ${'none'}
${0.4} | ${'none'}
${0.5} | ${'info'}
${0.9} | ${'warning'}
${0.99} | ${'alert'}
${1} | ${'error'}
${1.5} | ${'error'}
`('returns $expectedLevel from $usageRatio', ({ usageRatio, expectedLevel }) => {
expect(usageRatioToThresholdLevel(usageRatio)).toBe(expectedLevel);
});
});
describe('formatUsageSize', () => {
it.each`
input | expected
${0} | ${'0.0KiB'}
${999} | ${'1.0KiB'}
${1000} | ${'1.0KiB'}
${10240} | ${'10.0KiB'}
${1024 * 10 ** 5} | ${'97.7MiB'}
${10 ** 6} | ${'976.6KiB'}
${1024 * 10 ** 6} | ${'976.6MiB'}
${10 ** 8} | ${'95.4MiB'}
${1024 * 10 ** 8} | ${'95.4GiB'}
${10 ** 10} | ${'9.3GiB'}
${10 ** 12} | ${'931.3GiB'}
${10 ** 15} | ${'909.5TiB'}
`('returns $expected from $input', ({ input, expected }) => {
expect(formatUsageSize(input)).toBe(expected);
});
});
describe('calculateUsedAndRemStorage', () => {
it.each`
description | project | purchasedStorageRemaining | totalCalculatedUsedStorage | totalCalculatedStorageLimit
${'project within limit and purchased 0'} | ${mockProjectsData[0]} | ${0} | ${41943} | ${100000}
${'project within limit and purchased 10000'} | ${mockProjectsData[0]} | ${100000} | ${41943} | ${200000}
${'project in warning state and purchased 0'} | ${mockProjectsData[1]} | ${0} | ${0} | ${100000}
${'project in warning state and purchased 10000'} | ${mockProjectsData[1]} | ${100000} | ${0} | ${200000}
${'project in error state and purchased 0'} | ${mockProjectsData[2]} | ${0} | ${419430} | ${419430}
${'project in error state and purchased 10000'} | ${mockProjectsData[2]} | ${100000} | ${419430} | ${519430}
`(
'returns used: $totalCalculatedUsedStorage and remaining: $totalCalculatedStorageLimit storage for $description',
({
project,
purchasedStorageRemaining,
totalCalculatedUsedStorage,
totalCalculatedStorageLimit,
}) => {
const result = calculateUsedAndRemStorage(project, purchasedStorageRemaining);
expect(result.totalCalculatedUsedStorage).toBe(totalCalculatedUsedStorage);
expect(result.totalCalculatedStorageLimit).toBe(totalCalculatedStorageLimit);
},
);
});
describe('parseProjects', () => {
it('ensures all projects have totalCalculatedUsedStorage and totalCalculatedStorageLimit', () => {
const projects = parseProjects({
projects: mockGetStorageCounterGraphQLResponse,
additionalPurchasedStorageSize: 10000,
totalRepositorySizeExcess: 5000,
});
projects.forEach((project) => {
expect(project).toMatchObject({
totalCalculatedUsedStorage: expect.any(Number),
totalCalculatedStorageLimit: expect.any(Number),
});
});
});
});
import { mount } from '@vue/test-utils';
import StorageApp from 'ee/storage_counter/components/app.vue';
import NamespaceStorageApp from 'ee/usage_quotas/storage/components/namespace_storage_app.vue';
import CollapsibleProjectStorageDetail from 'ee/usage_quotas/storage/components/collapsible_project_storage_detail.vue';
import ProjectList from 'ee/usage_quotas/storage/components/project_list.vue';
import StorageInlineAlert from 'ee/storage_counter/components/storage_inline_alert.vue';
import TemporaryStorageIncreaseModal from 'ee/storage_counter/components/temporary_storage_increase_modal.vue';
import UsageStatistics from 'ee/storage_counter/components/usage_statistics.vue';
import { formatUsageSize } from 'ee/storage_counter/utils';
import StorageInlineAlert from 'ee/usage_quotas/storage/components/storage_inline_alert.vue';
import TemporaryStorageIncreaseModal from 'ee/usage_quotas/storage/components/temporary_storage_increase_modal.vue';
import UsageStatistics from 'ee/usage_quotas/storage/components/usage_statistics.vue';
import { formatUsageSize } from 'ee/usage_quotas/storage/utils';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import UsageGraph from '~/vue_shared/components/storage_counter/usage_graph.vue';
import { namespaceData, withRootStorageStatistics } from '../mock_data';
const TEST_LIMIT = 1000;
describe('Storage counter app', () => {
describe('NamespaceStorageApp', () => {
let wrapper;
const findTotalUsage = () => wrapper.find("[data-testid='total-usage']");
......@@ -40,7 +40,7 @@ describe('Storage counter app', () => {
},
};
wrapper = mount(StorageApp, {
wrapper = mount(NamespaceStorageApp, {
propsData: { namespacePath: 'h5bp', helpPagePath: 'help', ...props },
mocks: { $apollo },
directives: {
......@@ -206,13 +206,13 @@ describe('Storage counter app', () => {
// Check for truthiness so we're assured we're not comparing two undefineds
expect(value).toBeTruthy();
expect(value).toEqual(StorageApp.modalId);
expect(value).toEqual(NamespaceStorageApp.modalId);
});
it('renders modal', () => {
expect(wrapper.find(TemporaryStorageIncreaseModal).props()).toEqual({
limit: formatUsageSize(TEST_LIMIT),
modalId: StorageApp.modalId,
modalId: NamespaceStorageApp.modalId,
});
});
});
......
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import StorageInlineAlert from 'ee/storage_counter/components/storage_inline_alert.vue';
import StorageInlineAlert from 'ee/usage_quotas/storage/components/storage_inline_alert.vue';
const GB_IN_BYTES = 1_074_000_000;
const THIRTEEN_GB_IN_BYTES = 13 * GB_IN_BYTES;
......
import { GlModal } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils';
import TemporaryStorageIncreaseModal from 'ee/storage_counter/components/temporary_storage_increase_modal.vue';
import TemporaryStorageIncreaseModal from 'ee/usage_quotas/storage/components/temporary_storage_increase_modal.vue';
const TEST_LIMIT = '8 bytes';
const TEST_MODAL_ID = 'test-modal-id';
......
import { GlButton, GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import UsageStatistics from 'ee/storage_counter/components/usage_statistics.vue';
import UsageStatisticsCard from 'ee/storage_counter/components/usage_statistics_card.vue';
import UsageStatistics from 'ee/usage_quotas/storage/components/usage_statistics.vue';
import UsageStatisticsCard from 'ee/usage_quotas/storage/components/usage_statistics_card.vue';
import { withRootStorageStatistics } from '../mock_data';
describe('Usage Statistics component', () => {
describe('UsageStatistics', () => {
let wrapper;
const createComponent = ({ props = {}, newRouteStoragePurchase = false } = {}) => {
......
......@@ -152,3 +152,34 @@ export const defaultProjectProvideValues = {
projectPath: '/project-path',
helpLinks: projectHelpLinks,
};
export const namespaceData = {
totalUsage: 'N/A',
limit: 10000000,
projects: { data: projects },
};
export const withRootStorageStatistics = {
projects,
limit: 10000000,
totalUsage: 129334601,
containsLockedProjects: true,
repositorySizeExcessProjectCount: 1,
totalRepositorySizeExcess: 2321,
totalRepositorySize: 1002321,
additionalPurchasedStorageSize: 321,
actualRepositorySizeLimit: 1002321,
rootStorageStatistics: {
storageSize: 129334601,
repositorySize: 46012030,
lfsObjectsSize: 4329334601203,
buildArtifactsSize: 1272375,
packagesSize: 123123120,
wikiSize: 1000,
snippetsSize: 10000,
},
};
export const mockGetNamespaceStorageStatisticsGraphQLResponse = {
nodes: projects.map((node) => node),
};
import { parseGetProjectStorageResults } from 'ee/usage_quotas/storage/utils';
import {
usageRatioToThresholdLevel,
formatUsageSize,
parseProjects,
calculateUsedAndRemStorage,
parseGetProjectStorageResults,
} from 'ee/usage_quotas/storage/utils';
import {
projectData,
projects as mockProjectsData,
mockGetProjectStorageStatisticsGraphQLResponse,
mockGetNamespaceStorageStatisticsGraphQLResponse,
defaultProjectProvideValues,
} from './mock_data';
......@@ -35,3 +43,80 @@ describe('parseGetProjectStorageResults', () => {
);
});
});
describe('UsageThreshold', () => {
it.each`
usageRatio | expectedLevel
${0} | ${'none'}
${0.4} | ${'none'}
${0.5} | ${'info'}
${0.9} | ${'warning'}
${0.99} | ${'alert'}
${1} | ${'error'}
${1.5} | ${'error'}
`('returns $expectedLevel from $usageRatio', ({ usageRatio, expectedLevel }) => {
expect(usageRatioToThresholdLevel(usageRatio)).toBe(expectedLevel);
});
});
describe('formatUsageSize', () => {
it.each`
input | expected
${0} | ${'0.0KiB'}
${999} | ${'1.0KiB'}
${1000} | ${'1.0KiB'}
${10240} | ${'10.0KiB'}
${1024 * 10 ** 5} | ${'97.7MiB'}
${10 ** 6} | ${'976.6KiB'}
${1024 * 10 ** 6} | ${'976.6MiB'}
${10 ** 8} | ${'95.4MiB'}
${1024 * 10 ** 8} | ${'95.4GiB'}
${10 ** 10} | ${'9.3GiB'}
${10 ** 12} | ${'931.3GiB'}
${10 ** 15} | ${'909.5TiB'}
`('returns $expected from $input', ({ input, expected }) => {
expect(formatUsageSize(input)).toBe(expected);
});
});
describe('calculateUsedAndRemStorage', () => {
it.each`
description | project | purchasedStorageRemaining | totalCalculatedUsedStorage | totalCalculatedStorageLimit
${'project within limit and purchased 0'} | ${mockProjectsData[0]} | ${0} | ${41943} | ${100000}
${'project within limit and purchased 10000'} | ${mockProjectsData[0]} | ${100000} | ${41943} | ${200000}
${'project in warning state and purchased 0'} | ${mockProjectsData[1]} | ${0} | ${0} | ${100000}
${'project in warning state and purchased 10000'} | ${mockProjectsData[1]} | ${100000} | ${0} | ${200000}
${'project in error state and purchased 0'} | ${mockProjectsData[2]} | ${0} | ${419430} | ${419430}
${'project in error state and purchased 10000'} | ${mockProjectsData[2]} | ${100000} | ${419430} | ${519430}
`(
'returns used: $totalCalculatedUsedStorage and remaining: $totalCalculatedStorageLimit storage for $description',
({
project,
purchasedStorageRemaining,
totalCalculatedUsedStorage,
totalCalculatedStorageLimit,
}) => {
const result = calculateUsedAndRemStorage(project, purchasedStorageRemaining);
expect(result.totalCalculatedUsedStorage).toBe(totalCalculatedUsedStorage);
expect(result.totalCalculatedStorageLimit).toBe(totalCalculatedStorageLimit);
},
);
});
describe('parseProjects', () => {
it('ensures all projects have totalCalculatedUsedStorage and totalCalculatedStorageLimit', () => {
const projects = parseProjects({
projects: mockGetNamespaceStorageStatisticsGraphQLResponse,
additionalPurchasedStorageSize: 10000,
totalRepositorySizeExcess: 5000,
});
projects.forEach((project) => {
expect(project).toMatchObject({
totalCalculatedUsedStorage: expect.any(Number),
totalCalculatedStorageLimit: expect.any(Number),
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment