Skip to content

Commit

Permalink
Merge pull request #619 from jordojordo/policy-settings-empty-objects
Browse files Browse the repository at this point in the history
Remove empty objects completely from policy during creation
  • Loading branch information
jordojordo authored Feb 26, 2024
2 parents 85c7396 + c153378 commit 8554964
Show file tree
Hide file tree
Showing 24 changed files with 141 additions and 19 deletions.
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ module.exports = {
coverageDirectory: '<rootDir>/coverage/unit',
coverageReporters: ['json', 'text-summary'],
preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
testEnvironment: './tests/unit/FixJSDOMEnvironment.ts',
testEnvironment: './tests/unit/_config_/FixJSDOMEnvironment.ts',
};
16 changes: 14 additions & 2 deletions pkg/kubewarden/utils/object.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import isEmpty from 'lodash/isEmpty';
import isObject from 'lodash/isObject';

export function removeEmptyAttrs(obj: any) {
export function removeEmptyAttrs(obj: any): any {
Object.keys(obj).forEach((key: any) => {
const value = obj[key];

if ( value === undefined || value === null || value === '' || (Array.isArray(value) && !value.length) || (isObject(value) && isEmpty(value)) ) {
// Check for value being empty, null, or an empty array
if ( value === undefined || value === null || value === '' || (Array.isArray(value) && !value.length) ) {
delete obj[key];
} else if ( isObject(value) ) {
// Recursively clean the object
removeEmptyAttrs(value);

// After cleaning, if the object is empty, delete it
if ( isEmpty(value) ) {
delete obj[key];
}
}
});

// Added check: If the parent object is now empty, return null to signal removal
if ( isEmpty(obj) ) {
return null;
}

return obj;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions tests/unit/charts/admission/Admission.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import Settings from '@kubewarden/chart/kubewarden/admission/Settings.vue';
import Questions from '@kubewarden/components/Questions/index.vue';

import { DEFAULT_POLICY, KUBEWARDEN } from '@kubewarden/types';
import policyConfig from '../../templates/policyConfig';
import { question } from '../../templates/questions';
import policyConfig from '@tests/unit/_templates_/policyConfig';
import { question } from '@tests/unit/_templates_/questions';

describe('component: Admission', () => {
it('settings component should be shown when custom policy', () => {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/charts/admission/General.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import General from '@kubewarden/chart/kubewarden/admission/General.vue';
import LabeledSelect from '@shell/components/form/LabeledSelect';
import { RadioGroup } from '@components/Form/Radio';

import policyConfig from '../../templates/policyConfig';
import policyConfig from '@tests/unit/_templates_/policyConfig';

describe('component: General', () => {
it('should display the PolicyServer options if available', () => {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/charts/admission/NamespaceSelector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import NamespaceSelector from '@kubewarden/chart/kubewarden/admission/NamespaceS
import KeyValue from '@shell/components/form/KeyValue';
import MatchExpressions from '@shell/components/form/MatchExpressions';

import policyConfig from '../../templates/policyConfig';
import policyConfig from '@tests/unit/_templates_/policyConfig';

describe('component: NamespaceSelector', () => {
it('matchExpressions should add to the policy namespaceSelector spec', async() => {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/charts/admission/Rules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { KUBEWARDEN } from '@kubewarden/types';
import Rules from '@kubewarden/chart/kubewarden/admission/Rules';
import Rule from '@kubewarden/chart/kubewarden/admission/Rules/Rule.vue';

import policyConfig from '../../templates/policyConfig';
import policyConfig from '@tests/unit/_templates_/policyConfig';

describe('component: Rules', () => {
it('rules should render rule components based on policy config', async() => {
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/components/Dashboard/DashboardView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import DashboardView from '@kubewarden/components/Dashboard/DashboardView.vue';
import DefaultsBanner from '@kubewarden/components/DefaultsBanner';
import ConsumptionGauge from '@shell/components/ConsumptionGauge';

import DEFAULTS_APP from '../../templates/defaultsApp';
import PS_POD from '../../templates/policyServerPod';
import DEFAULTS_APP from '@tests/unit/_templates_/defaultsApp';
import PS_POD from '@tests/unit/_templates_/policyServerPod';

describe('component: DashboardView', () => {
const commonMocks = {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/components/MetricsChecklist.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createWrapper } from '@tests/unit/utils/wrapper';
import { createWrapper } from '@tests/unit/_utils_/wrapper';

import MetricsChecklist from '@kubewarden/components/MetricsChecklist.vue';

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/components/Policies/Create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { describe, expect, it } from '@jest/globals';
import jsyaml from 'js-yaml';

import { KUBEWARDEN } from '@kubewarden/types';
import { createWrapper } from '@tests/unit/utils/wrapper';
import { createWrapper } from '@tests/unit/_utils_/wrapper';

import Create from '@kubewarden/components/Policies/Create.vue';

import policyPackages from '@tests/unit/templates/policyPackages';
import policyPackages from '@tests/unit/_templates_/policyPackages';

function mockParsePackageMetadata(data) {
if (data) {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/components/Policies/PolicyDetail.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ARTIFACTHUB_PKG_ANNOTATION } from '@kubewarden/types';

import { createWrapper } from '@tests/unit/utils/wrapper';
import { createWrapper } from '@tests/unit/_utils_/wrapper';
import PolicyDetail from '@kubewarden/components/Policies/PolicyDetail.vue';

const commonMocks = { $fetchState: { pending: false } };
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/components/Policies/PolicyGrid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { KUBEWARDEN } from '@kubewarden/types';
import PolicyGrid from '@kubewarden/components/Policies/PolicyGrid.vue';
import LabeledSelect from '@shell/components/form/LabeledSelect';

import policyPackages from '../../templates/policyPackages.js';
import schemas from '../../templates/schemas.js';
import policyPackages from '@tests/unit/_templates_/policyPackages.js';
import schemas from '@tests/unit/_templates_/schemas.js';

const defaultComputed = { allSchemas: jest.fn() };
const defaultMocks = {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/components/Questions/QuestionMap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Question from '@kubewarden/components/Questions/index.vue';
import QuestionMap from '@kubewarden/components/Questions/QuestionMap.vue';
import SequenceType from '@kubewarden/components/Questions/SequenceTree.vue';

import { deepMapQuestion } from '../../templates/questions';
import { deepMapQuestion } from '@tests/unit/_templates_/questions';

describe('component: QuestionMap', () => {
it('emits addSeq with question props', () => {
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/components/Questions/SequenceTree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { describe, expect, it } from '@jest/globals';
import Question from '@kubewarden/components/Questions/index.vue';
import SequenceType from '@kubewarden/components/Questions/SequenceTree.vue';

import { question, deepSequenceQuestion } from '../../templates/questions';
import { question, deepSequenceQuestion } from '@tests/unit/_templates_/questions';

function getGroups(flattenedQuestions) {
const map = {};
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/detail/PolicyServer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { describe, expect, it } from '@jest/globals';
import PolicyServer from '@kubewarden/detail/policies.kubewarden.io.policyserver.vue';
import CountGauge from '@shell/components/CountGauge';

import TraceTestData from '../templates/policyTraces';
import TraceTestData from '@tests/unit/_templates_/policyTraces';

const policyGauges = {
Active: {
Expand Down
110 changes: 110 additions & 0 deletions tests/unit/utils/object.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { removeEmptyAttrs } from '@kubewarden/utils/object';

describe('removeEmptyAttrs', () => {
it('should remove attributes that are undefined, null, or empty', () => {
const obj = {
name: 'Test',
value: null,
details: {},
list: [],
nested: {
emptyString: '',
emptyObj: {},
emptyArray: [],
},
};
const cleanedObj = removeEmptyAttrs(obj);

expect(cleanedObj).toEqual({ name: 'Test' });
});

it('should remove deeply nested empty objects', () => {
const obj = { level1: { level2: { level3: {} } } };
const cleanedObj = removeEmptyAttrs(obj);

expect(cleanedObj).toEqual(null);
});

it('should handle arrays and non-object values correctly', () => {
const obj = {
arrayNotEmpty: [1, 2, 3],
stringValue: 'hello',
numberValue: 123,
booleanValue: false,
emptyObject: {},
};
const cleanedObj = removeEmptyAttrs(obj);

expect(cleanedObj).toEqual({
arrayNotEmpty: [1, 2, 3],
stringValue: 'hello',
numberValue: 123,
booleanValue: false,
});
});

it('should remove settings entirely if cpu and memory are empty', () => {
const obj = {
apiVersion: 'policies.kubewarden.io.v1',
kind: 'ClusterAdmissionPolicy',
spec: {
backgroundAudit: true,
policyServer: 'default',
settings: {
cpu: {},
memory: {},
},
},
};
const expectedObj = {
apiVersion: 'policies.kubewarden.io.v1',
kind: 'ClusterAdmissionPolicy',
spec: {
backgroundAudit: true,
policyServer: 'default'
}
};
const cleanedObj = removeEmptyAttrs(obj);

expect(cleanedObj).toEqual(expectedObj);
});

it('should remove the entire object if it becomes empty after cleanup', () => {
const obj = {
spec: {
settings: {
cpu: {},
memory: {},
},
},
};
const cleanedObj = removeEmptyAttrs(obj);

expect(cleanedObj).toEqual(null);
});

it('should remove only the empty memory object while preserving non-empty cpu object', () => {
const obj = {
settings: {
cpu: {
defaultLimit: '100m',
defaultRequest: '100m',
maxLimit: '100m',
},
memory: {},
},
};
const expectedObj = {
settings: {
cpu: {
defaultLimit: '100m',
defaultRequest: '100m',
maxLimit: '100m',
},
},
};
const cleanedObj = removeEmptyAttrs(obj);

expect(cleanedObj).toEqual(expectedObj);
});
});

0 comments on commit 8554964

Please sign in to comment.