Commit 5b3203f7 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '333163-network-policies-graphql' into 'master'

Migrate network policies fetch to GraphQL

See merge request gitlab-org/gitlab!64546
parents 53bc903b 5d4cb809
<script>
import { GlTable, GlEmptyState, GlButton, GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex';
import { mapState, mapGetters } from 'vuex';
import { PREDEFINED_NETWORK_POLICIES } from 'ee/threat_monitoring/constants';
import createFlash from '~/flash';
import { getTimeago } from '~/lib/utils/datetime_utility';
import { setUrlFragment, mergeUrlParams } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import networkPoliciesQuery from '../graphql/queries/network_policies.query.graphql';
import EnvironmentPicker from './environment_picker.vue';
import PolicyDrawer from './policy_drawer/policy_drawer.vue';
......@@ -18,6 +21,7 @@ export default {
EnvironmentPicker,
PolicyDrawer,
},
inject: ['projectPath'],
props: {
documentationPath: {
type: String,
......@@ -28,26 +32,61 @@ export default {
required: true,
},
},
apollo: {
networkPolicies: {
query: networkPoliciesQuery,
variables() {
return {
fullPath: this.projectPath,
environmentId: this.allEnvironments ? null : this.currentEnvironmentGid,
};
},
update(data) {
const policies = data?.project?.networkPolicies?.nodes ?? [];
const predefined = PREDEFINED_NETWORK_POLICIES.filter(
({ name }) => !policies.some((policy) => name === policy.name),
);
return [...policies, ...predefined];
},
error({ gqlError, networkError }) {
const error =
gqlError?.message ||
networkError?.message ||
s__('NetworkPolicies|Something went wrong, unable to fetch policies');
createFlash({
message: error,
});
},
skip() {
return this.isLoadingEnvironments;
},
},
},
data() {
return { selectedPolicyName: null, initialManifest: null, initialEnforcementStatus: null };
},
computed: {
...mapState('networkPolicies', ['policies', 'isLoadingPolicies']),
...mapState('threatMonitoring', ['currentEnvironmentId', 'allEnvironments']),
...mapGetters('networkPolicies', ['policiesWithDefaults']),
...mapState('threatMonitoring', [
'currentEnvironmentId',
'allEnvironments',
'isLoadingEnvironments',
]),
...mapGetters('threatMonitoring', ['currentEnvironmentGid']),
documentationFullPath() {
return setUrlFragment(this.documentationPath, 'container-network-policy');
},
isLoadingPolicies() {
return this.isLoadingEnvironments || this.$apollo.queries.networkPolicies.loading;
},
hasSelectedPolicy() {
return Boolean(this.selectedPolicyName);
},
selectedPolicy() {
if (!this.hasSelectedPolicy) return null;
return this.policiesWithDefaults.find((policy) => policy.name === this.selectedPolicyName);
return this.networkPolicies.find((policy) => policy.name === this.selectedPolicyName);
},
hasAutoDevopsPolicy() {
return this.policiesWithDefaults.some((policy) => policy.isAutodevops);
return Boolean(this.networkPolicies?.some((policy) => policy.fromAutoDevops));
},
editPolicyPath() {
return this.hasSelectedPolicy
......@@ -75,7 +114,7 @@ export default {
thClass: 'font-weight-bold',
},
{
key: 'creationTimestamp',
key: 'updatedAt',
label: s__('NetworkPolicies|Last modified'),
thClass: 'font-weight-bold',
},
......@@ -86,27 +125,18 @@ export default {
return fields;
},
},
watch: {
currentEnvironmentId(envId) {
this.fetchPolicies(envId);
},
},
created() {
this.fetchPolicies(this.currentEnvironmentId);
},
methods: {
...mapActions('networkPolicies', ['fetchPolicies', 'createPolicy', 'updatePolicy']),
getTimeAgoString(creationTimestamp) {
if (!creationTimestamp) return '';
return getTimeago().format(creationTimestamp);
getTimeAgoString(updatedAt) {
if (!updatedAt) return '';
return getTimeago().format(updatedAt);
},
presentPolicyDrawer(rows) {
if (rows.length === 0) return;
const [selectedPolicy] = rows;
this.selectedPolicyName = selectedPolicy?.name;
this.initialManifest = selectedPolicy?.manifest;
this.initialEnforcementStatus = selectedPolicy?.isEnabled;
this.initialManifest = selectedPolicy?.yaml;
this.initialEnforcementStatus = selectedPolicy?.enabled;
},
deselectPolicy() {
this.selectedPolicyName = null;
......@@ -161,7 +191,7 @@ export default {
<gl-table
ref="policiesTable"
:busy="isLoadingPolicies"
:items="policiesWithDefaults"
:items="networkPolicies"
:fields="fields"
head-variant="white"
stacked="md"
......@@ -175,11 +205,11 @@ export default {
@row-selected="presentPolicyDrawer"
>
<template #cell(status)="value">
{{ value.item.isEnabled ? __('Enabled') : __('Disabled') }}
{{ value.item.enabled ? __('Enabled') : __('Disabled') }}
</template>
<template #cell(creationTimestamp)="value">
{{ getTimeAgoString(value.item.creationTimestamp) }}
<template #cell(updatedAt)="value">
{{ getTimeAgoString(value.item.updatedAt) }}
</template>
<template #empty>
......
......@@ -33,7 +33,7 @@ export default {
},
computed: {
policyKind() {
return getPolicyKind(this.policy);
return getPolicyKind(this.policy?.yaml);
},
policyComponent() {
return policyComponent[this.policyKind] || null;
......@@ -72,7 +72,7 @@ export default {
</div>
</template>
<div v-if="policy">
<component :is="policyComponent" v-if="policyComponent" :value="policy.manifest" />
<component :is="policyComponent" v-if="policyComponent" :value="policy.yaml" />
<div v-else>
<h5>{{ s__('NetworkPolicies|Policy definition') }}</h5>
<p>
......@@ -80,7 +80,7 @@ export default {
</p>
<div class="gl-p-3 gl-bg-gray-50">
<policy-yaml-editor
:value="policy.manifest"
:value="policy.yaml"
data-testid="policy-yaml-editor"
class="network-policy-editor"
/>
......
......@@ -5,8 +5,8 @@ export const INVALID_CURRENT_ENVIRONMENT_NAME = '–';
export const PREDEFINED_NETWORK_POLICIES = [
{
name: 'drop-outbound',
isEnabled: false,
manifest: `---
enabled: false,
yaml: `---
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
......@@ -18,8 +18,8 @@ spec:
},
{
name: 'allow-inbound-http',
isEnabled: false,
manifest: `---
enabled: false,
yaml: `---
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
......
query networkPolicies($fullPath: ID!, $environmentId: EnvironmentID) {
project(fullPath: $fullPath) {
networkPolicies(environmentId: $environmentId) {
nodes {
name
yaml
enabled
fromAutoDevops
updatedAt
}
}
}
}
......@@ -11,6 +11,7 @@ const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(
{},
{
assumeImmutableResults: true,
cacheConfig: {
dataIdFromObject: (object) => {
// eslint-disable-next-line no-underscore-dangle
......
......@@ -8,31 +8,6 @@ export const setEndpoints = ({ commit }, endpoints) => {
commit(types.SET_ENDPOINT, endpoints.networkPoliciesEndpoint);
};
const commitReceivePoliciesError = (commit, data) => {
const error =
data?.error || s__('NetworkPolicies|Something went wrong, unable to fetch policies');
const policies = data?.payload?.length ? data.payload : [];
commit(types.RECEIVE_POLICIES_ERROR, policies);
createFlash({
message: error,
});
};
export const fetchPolicies = ({ state, commit }, environmentId) => {
if (!state.policiesEndpoint) return commitReceivePoliciesError(commit);
commit(types.REQUEST_POLICIES);
const params = environmentId ? { params: { environment_id: environmentId } } : {};
return axios
.get(state.policiesEndpoint, params)
.then(({ data }) => commit(types.RECEIVE_POLICIES_SUCCESS, data))
.catch(({ response }) => {
commitReceivePoliciesError(commit, response?.data);
});
};
const commitPolicyError = (commit, type, payload) => {
const error =
payload?.error || s__('NetworkPolicies|Something went wrong, failed to update policy');
......
import { PREDEFINED_NETWORK_POLICIES } from 'ee/threat_monitoring/constants';
export const policiesWithDefaults = ({ policies }) => {
// Predefined policies that were enabled by users will be present in
// the list of policies we received from the backend. We want to
// filter out enabled predefined policies and only append the ones
// that are not present in a cluster.
const predefined = PREDEFINED_NETWORK_POLICIES.filter(
({ name }) => !policies.some((policy) => name === policy.name),
);
return [...policies, ...predefined];
};
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import state from './state';
export default () => ({
namespaced: true,
actions,
getters,
mutations,
state,
});
export const SET_ENDPOINT = 'SET_ENDPOINT';
export const REQUEST_POLICIES = 'REQUEST_POLICIES';
export const RECEIVE_POLICIES_SUCCESS = 'RECEIVE_POLICIES_SUCCESS';
export const RECEIVE_POLICIES_ERROR = 'RECEIVE_POLICIES_ERROR';
export const REQUEST_CREATE_POLICY = 'REQUEST_CREATE_POLICY';
export const RECEIVE_CREATE_POLICY_SUCCESS = 'RECEIVE_CREATE_POLICY_SUCCESS';
export const RECEIVE_CREATE_POLICY_ERROR = 'RECEIVE_CREATE_POLICY_ERROR';
......
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import * as types from './mutation_types';
const setPolicies = (state, policies) => {
state.policies = policies.map((policy) => convertObjectPropsToCamelCase(policy));
};
export default {
[types.SET_ENDPOINT](state, endpoint) {
state.policiesEndpoint = endpoint;
},
[types.REQUEST_POLICIES](state) {
state.isLoadingPolicies = true;
state.errorLoadingPolicies = false;
},
[types.RECEIVE_POLICIES_SUCCESS](state, policies) {
setPolicies(state, policies);
state.isLoadingPolicies = false;
state.errorLoadingPolicies = false;
},
[types.RECEIVE_POLICIES_ERROR](state, policies = []) {
setPolicies(state, policies);
state.isLoadingPolicies = false;
state.errorLoadingPolicies = true;
},
[types.REQUEST_CREATE_POLICY](state) {
state.isUpdatingPolicy = true;
state.errorUpdatingPolicy = false;
},
[types.RECEIVE_CREATE_POLICY_SUCCESS](state, policy) {
const newPolicy = convertObjectPropsToCamelCase(policy);
state.policies = [...state.policies, newPolicy];
[types.RECEIVE_CREATE_POLICY_SUCCESS](state) {
state.isUpdatingPolicy = false;
state.errorUpdatingPolicy = false;
},
......@@ -41,9 +20,7 @@ export default {
state.isUpdatingPolicy = true;
state.errorUpdatingPolicy = false;
},
[types.RECEIVE_UPDATE_POLICY_SUCCESS](state, { policy, updatedPolicy }) {
const newPolicy = convertObjectPropsToCamelCase(updatedPolicy);
state.policies = state.policies.map((pol) => (pol.name === policy.name ? newPolicy : pol));
[types.RECEIVE_UPDATE_POLICY_SUCCESS](state) {
state.isUpdatingPolicy = false;
state.errorUpdatingPolicy = false;
},
......@@ -55,8 +32,7 @@ export default {
state.isRemovingPolicy = true;
state.errorRemovingPolicy = false;
},
[types.RECEIVE_DELETE_POLICY_SUCCESS](state, { policy }) {
state.policies = state.policies.filter(({ name }) => name !== policy.name);
[types.RECEIVE_DELETE_POLICY_SUCCESS](state) {
state.isRemovingPolicy = false;
state.errorRemovingPolicy = false;
},
......
export default () => ({
policiesEndpoint: '',
policies: [],
isLoadingPolicies: false,
errorLoadingPolicies: false,
isUpdatingPolicy: false,
errorUpdatingPolicy: false,
isRemovingPolicy: false,
......
......@@ -61,7 +61,6 @@ export const setCurrentTimeWindow = ({ commit }, timeWindow) => {
commit(types.SET_CURRENT_TIME_WINDOW, timeWindow.name);
};
export const setAllEnvironments = ({ commit, dispatch }) => {
export const setAllEnvironments = ({ commit }) => {
commit(types.SET_ALL_ENVIRONMENTS);
dispatch(`networkPolicies/fetchPolicies`, null, { root: true });
};
import { INVALID_CURRENT_ENVIRONMENT_NAME } from '../../../constants';
export const currentEnvironmentName = ({ currentEnvironmentId, environments }) => {
const environment = environments.find(({ id }) => id === currentEnvironmentId);
return environment ? environment.name : INVALID_CURRENT_ENVIRONMENT_NAME;
};
export const currentEnvironment = ({ currentEnvironmentId, environments }) =>
environments.find((environment) => environment.id === currentEnvironmentId);
export const currentEnvironmentName = (state, getters) =>
getters.currentEnvironment?.name ?? INVALID_CURRENT_ENVIRONMENT_NAME;
export const currentEnvironmentGid = (state, getters) => getters.currentEnvironment?.global_id;
export const canChangeEnvironment = ({
isLoadingEnvironments,
......
......@@ -14,14 +14,14 @@ export const getContentWrapperHeight = (contentWrapperClass) => {
/**
* Get a policy's type
* @param {Object} policy policy information including a manifest in yaml
* @param {String} yaml policy's YAML manifest
* @returns {String|null} policy type if available
*/
export const getPolicyKind = (policy) => {
if (policy?.manifest?.includes(POLICY_KINDS.ciliumNetwork)) {
export const getPolicyKind = (yaml = '') => {
if (yaml?.includes(POLICY_KINDS.ciliumNetwork)) {
return POLICY_KINDS.ciliumNetwork;
}
if (policy?.manifest?.includes(POLICY_KINDS.scanExecution)) {
if (yaml?.includes(POLICY_KINDS.scanExecution)) {
return POLICY_KINDS.scanExecution;
}
return null;
......
......@@ -6,10 +6,10 @@ exports[`NetworkPolicyList component renders policies table 1`] = `
<table
aria-busy="false"
aria-colcount="3"
aria-describedby="__BVID__181__caption_"
aria-describedby="__BVID__243__caption_"
aria-multiselectable="false"
class="table b-table gl-table table-hover b-table-stacked-md b-table-selectable b-table-select-single"
id="__BVID__181"
id="__BVID__243"
role="table"
>
<!---->
......
import { GlTable, GlDrawer } from '@gitlab/ui';
import { createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
import NetworkPolicyList from 'ee/threat_monitoring/components/network_policy_list.vue';
import networkPoliciesQuery from 'ee/threat_monitoring/graphql/queries/network_policies.query.graphql';
import createStore from 'ee/threat_monitoring/store';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import createMockApolloProvider from 'helpers/mock_apollo_helper';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { networkPolicies } from '../mocks/mock_apollo';
import { mockPoliciesResponse, mockCiliumPolicy } from '../mocks/mock_data';
const mockData = mockPoliciesResponse.map((policy) => convertObjectPropsToCamelCase(policy));
const localVue = createLocalVue();
localVue.use(VueApollo);
const fullPath = 'project/path';
const environments = [
{
id: 2,
global_id: 'gid://gitlab/Environment/2',
},
];
const defaultRequestHandlers = {
networkPolicies: networkPolicies(mockPoliciesResponse),
};
const pendingHandler = jest.fn(() => new Promise(() => {}));
describe('NetworkPolicyList component', () => {
let store;
let wrapper;
let requestHandlers;
const factory = ({ propsData, state, data, provide } = {}) => {
const factory = ({ mountFn = mountExtended, propsData, state, data, handlers } = {}) => {
store = createStore();
Object.assign(store.state.networkPolicies, {
isLoadingPolicies: false,
policies: mockData,
...state,
});
store.state.threatMonitoring.environments = environments;
requestHandlers = {
...defaultRequestHandlers,
...handlers,
};
jest.spyOn(store, 'dispatch').mockImplementation(() => Promise.resolve());
wrapper = mountExtended(NetworkPolicyList, {
wrapper = mountFn(NetworkPolicyList, {
propsData: {
documentationPath: 'documentation_path',
newPolicyPath: '/policies/new',
......@@ -29,8 +50,14 @@ describe('NetworkPolicyList component', () => {
},
data,
store,
provide,
provide: {
projectPath: fullPath,
},
apolloProvider: createMockApolloProvider([
[networkPoliciesQuery, requestHandlers.networkPolicies],
]),
stubs: { PolicyDrawer: GlDrawer },
localVue,
});
};
......@@ -58,25 +85,40 @@ describe('NetworkPolicyList component', () => {
expect(button.exists()).toBe(true);
});
it('fetches policies', () => {
expect(store.dispatch).toHaveBeenCalledWith('networkPolicies/fetchPolicies', -1);
describe('initial state', () => {
beforeEach(() => {
factory({
mountFn: shallowMountExtended,
handlers: {
networkPolicies: pendingHandler,
},
});
});
it('fetches policies', () => {
expect(requestHandlers.networkPolicies).toHaveBeenCalledWith({
fullPath,
});
});
it("sets table's loading state", () => {
expect(findPoliciesTable().attributes('busy')).toBe('true');
});
});
it('fetches policies on environment change', async () => {
store.dispatch.mockReset();
await store.commit('threatMonitoring/SET_CURRENT_ENVIRONMENT_ID', 2);
expect(store.dispatch).toHaveBeenCalledWith('networkPolicies/fetchPolicies', 2);
expect(requestHandlers.networkPolicies).toHaveBeenCalledTimes(2);
expect(requestHandlers.networkPolicies.mock.calls[1][0]).toEqual({
fullPath: 'project/path',
environmentId: environments[0].global_id,
});
});
describe('given selected policy is a cilium policy', () => {
beforeEach(() => {
factory({
data: () => ({ selectedPolicyName: 'policy' }),
state: {
policies: [mockCiliumPolicy],
},
});
findPoliciesTable().vm.$emit('row-selected', [mockCiliumPolicy]);
});
it('renders the new policy drawer', () => {
......@@ -121,13 +163,7 @@ describe('NetworkPolicyList component', () => {
describe('given there is a selected policy', () => {
beforeEach(() => {
factory({
data: () => ({
selectedPolicyName: 'policy',
initialManifest: mockData[0].manifest,
initialEnforcementStatus: mockData[0].isEnabled,
}),
});
findPoliciesTable().vm.$emit('row-selected', [mockPoliciesResponse[0]]);
});
it('renders opened editor drawer', () => {
......@@ -153,11 +189,15 @@ describe('NetworkPolicyList component', () => {
describe('given autodevops selected policy', () => {
beforeEach(() => {
const policies = mockPoliciesResponse;
policies[0].isAutodevops = true;
const autoDevOpsPolicy = {
...mockPoliciesResponse[0],
name: 'auto-devops',
fromAutoDevops: true,
};
factory({
state: { policies },
data: () => ({ selectedPolicyName: 'policy' }),
handlers: {
networkPolicies: networkPolicies([autoDevOpsPolicy]),
},
});
});
......
......@@ -66,7 +66,7 @@ describe('PolicyDrawer component', () => {
it('renders network policy editor with manifest', () => {
const policyEditor = findPolicyEditor();
expect(policyEditor.exists()).toBe(true);
expect(policyEditor.attributes('value')).toBe(mockGenericPolicy.manifest);
expect(policyEditor.attributes('value')).toBe(mockGenericPolicy.yaml);
});
itRendersEditButton();
......
......@@ -23,7 +23,7 @@ describe('ScanExecutionPolicy component', () => {
describe('supported YAML', () => {
beforeEach(() => {
factory({ propsData: { value: mockScanExecutionPolicy.manifest } });
factory({ propsData: { value: mockScanExecutionPolicy.yaml } });
});
it('does render the policy description', () => {
......
......@@ -27,3 +27,14 @@ export const getAlertDetailsQueryErrorMessage =
export const erroredGetAlertDetailsQuerySpy = jest.fn().mockResolvedValue({
errors: [{ message: getAlertDetailsQueryErrorMessage }],
});
export const networkPolicies = (nodes) =>
jest.fn().mockResolvedValue({
data: {
project: {
networkPolicies: {
nodes,
},
},
},
});
......@@ -18,8 +18,7 @@ export const mockEnvironmentsResponse = {
export const mockPoliciesResponse = [
{
name: 'policy',
namespace: 'production',
manifest: `---
yaml: `---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
......@@ -36,15 +35,16 @@ spec:
- namespaceSelector:
matchLabels:
project: myproject`,
creation_timestamp: '2020-04-14T00:08:30Z',
is_enabled: true,
updatedAt: '2020-04-14T00:08:30Z',
enabled: true,
fromAutoDevops: false,
},
];
export const mockCiliumPolicy = {
name: 'policy',
creationTimestamp: new Date('2021-06-07T00:00:00.000Z'),
manifest: `apiVersion: cilium.io/v2
updatedAt: new Date('2021-06-07T00:00:00.000Z'),
yaml: `apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: policy
......@@ -54,8 +54,8 @@ spec:
export const mockScanExecutionPolicy = {
name: 'Scheduled DAST scan',
creationTimestamp: new Date('2021-06-07T00:00:00.000Z'),
manifest: `---
updatedAt: new Date('2021-06-07T00:00:00.000Z'),
yaml: `---
name: Enforce DAST in every pipeline
description: This policy enforces pipeline configuration to have a job with DAST scan
enabled: true
......
......@@ -9,8 +9,6 @@ import httpStatus from '~/lib/utils/http_status';
import { joinPaths } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import { mockPoliciesResponse } from '../../../mocks/mock_data';
jest.mock('~/flash');
const networkPoliciesEndpoint = 'networkPoliciesEndpoint';
......@@ -48,118 +46,6 @@ describe('Network Policy actions', () => {
));
});
describe('fetchPolicies', () => {
describe('on success', () => {
beforeEach(() => {
mock
.onGet(networkPoliciesEndpoint, {
params: { environment_id: environmentId },
})
.replyOnce(httpStatus.OK, mockPoliciesResponse);
});
it('should dispatch the request and success actions', () =>
testAction(
actions.fetchPolicies,
environmentId,
state,
[
{ type: types.REQUEST_POLICIES },
{
type: types.RECEIVE_POLICIES_SUCCESS,
payload: mockPoliciesResponse,
},
],
[],
));
describe('without environment id', () => {
beforeEach(() => {
mock.onGet(networkPoliciesEndpoint, null).replyOnce(httpStatus.OK, mockPoliciesResponse);
});
it('should dispatch the request and success actions', () =>
testAction(
actions.fetchPolicies,
null,
state,
[
{ type: types.REQUEST_POLICIES },
{
type: types.RECEIVE_POLICIES_SUCCESS,
payload: mockPoliciesResponse,
},
],
[],
));
});
});
describe('on error', () => {
describe('without payload', () => {
const error = { error: 'foo' };
beforeEach(() => {
mock.onGet(networkPoliciesEndpoint).replyOnce(500, error);
});
it('should dispatch the request, error actions and updates payload', () =>
testAction(
actions.fetchPolicies,
environmentId,
state,
[{ type: types.REQUEST_POLICIES }, { type: types.RECEIVE_POLICIES_ERROR, payload: [] }],
[],
).then(() => {
expect(createFlash).toHaveBeenCalled();
}));
});
describe('with payload', () => {
const payload = { error: 'foo', payload: [policy] };
beforeEach(() => {
mock.onGet(networkPoliciesEndpoint).replyOnce(500, payload);
});
it('should dispatch the request, error actions and updates payload', () =>
testAction(
actions.fetchPolicies,
environmentId,
state,
[
{ type: types.REQUEST_POLICIES },
{ type: types.RECEIVE_POLICIES_ERROR, payload: [policy] },
],
[],
).then(() => {
expect(createFlash).toHaveBeenCalled();
}));
});
});
describe('with an empty endpoint', () => {
beforeEach(() => {
state.policiesEndpoint = '';
});
it('should dispatch RECEIVE_POLICES_ERROR', () =>
testAction(
actions.fetchPolicies,
environmentId,
state,
[
{
type: types.RECEIVE_POLICIES_ERROR,
payload: [],
},
],
[],
).then(() => {
expect(createFlash).toHaveBeenCalled();
}));
});
});
describe('createPolicy', () => {
const createdPolicy = { name: 'policy', manifest: 'bar', isEnabled: true };
......
import * as getters from 'ee/threat_monitoring/store/modules/network_policies/getters';
import createState from 'ee/threat_monitoring/store/modules/network_policies/state';
describe('networkPolicies module getters', () => {
let state;
beforeEach(() => {
state = createState();
});
describe('policiesWithDefaults', () => {
describe('without policies in the state', () => {
it('returns predefined policies', () => {
expect(getters.policiesWithDefaults(state).map(({ name }) => name)).toEqual([
'drop-outbound',
'allow-inbound-http',
]);
});
});
describe('with policies in the state', () => {
beforeEach(() => {
state.policies = [{ name: 'user-policy' }];
});
it('returns user owned and predefined policies', () => {
expect(getters.policiesWithDefaults(state).map(({ name }) => name)).toEqual([
'user-policy',
'drop-outbound',
'allow-inbound-http',
]);
});
describe('with deployed predefined policy', () => {
beforeEach(() => {
state.policies = [{ name: 'user-policy' }, { name: 'drop-outbound' }];
});
it('returns user policies and a single predefined policy', () => {
expect(getters.policiesWithDefaults(state).map(({ name }) => name)).toEqual([
'user-policy',
'drop-outbound',
'allow-inbound-http',
]);
});
});
});
});
});
......@@ -15,46 +15,6 @@ describe('Network Policies mutations', () => {
});
});
describe(types.REQUEST_POLICIES, () => {
beforeEach(() => {
mutations[types.REQUEST_POLICIES](state);
});
it('sets isLoadingPolicies to true and sets errorLoadingPolicies to false', () => {
expect(state.isLoadingPolicies).toBe(true);
expect(state.errorLoadingPolicies).toBe(false);
});
});
describe(types.RECEIVE_POLICIES_SUCCESS, () => {
let policies;
beforeEach(() => {
policies = [{ id: 1, name: 'production' }];
mutations[types.RECEIVE_POLICIES_SUCCESS](state, policies);
});
it('sets policies to the payload', () => {
expect(state.policies).toEqual(expect.objectContaining(policies));
});
it('sets isLoadingPolicies to false and sets errorLoadingPolicies to false', () => {
expect(state.isLoadingPolicies).toBe(false);
expect(state.errorLoadingPolicies).toBe(false);
});
});
describe(types.RECEIVE_POLICIES_ERROR, () => {
beforeEach(() => {
mutations[types.RECEIVE_POLICIES_ERROR](state);
});
it('sets isLoadingPolicies to false and sets errorLoadingPolicies to true', () => {
expect(state.isLoadingPolicies).toBe(false);
expect(state.errorLoadingPolicies).toBe(true);
});
});
describe(types.REQUEST_CREATE_POLICY, () => {
beforeEach(() => {
mutations[types.REQUEST_CREATE_POLICY](state);
......@@ -67,14 +27,8 @@ describe('Network Policies mutations', () => {
});
describe(types.RECEIVE_CREATE_POLICY_SUCCESS, () => {
const policy = { id: 1, name: 'production', manifest: 'foo' };
beforeEach(() => {
mutations[types.RECEIVE_CREATE_POLICY_SUCCESS](state, policy);
});
it('adds a policy to the store', () => {
expect(state.policies).toEqual(expect.objectContaining([policy]));
mutations[types.RECEIVE_CREATE_POLICY_SUCCESS](state);
});
it('sets isUpdatingPolicy to false and sets errorUpdatingPolicy to false', () => {
......@@ -106,20 +60,8 @@ describe('Network Policies mutations', () => {
});
describe(types.RECEIVE_UPDATE_POLICY_SUCCESS, () => {
const policy = { id: 1, name: 'production', manifest: 'foo' };
const updatedPolicy = { id: 1, name: 'production', manifest: 'bar' };
beforeEach(() => {
state.policies.push(policy);
mutations[types.RECEIVE_UPDATE_POLICY_SUCCESS](state, {
policy,
updatedPolicy,
});
});
it('replaces policies with the updatedPolicy', () => {
expect(state.policies).not.toEqual(expect.objectContaining(policy));
expect(state.policies).toEqual(expect.objectContaining([updatedPolicy]));
mutations[types.RECEIVE_UPDATE_POLICY_SUCCESS](state);
});
it('sets isUpdatingPolicy to false and sets errorUpdatingPolicy to false', () => {
......
......@@ -221,12 +221,6 @@ describe('Threat Monitoring actions', () => {
describe('setAllEnvironments', () => {
it('commits the SET_ALL_ENVIRONMENTS mutation and dispatches Network Policy fetch action', () =>
testAction(
actions.setAllEnvironments,
null,
state,
[{ type: types.SET_ALL_ENVIRONMENTS }],
[{ type: 'networkPolicies/fetchPolicies', payload: null }],
));
testAction(actions.setAllEnvironments, null, state, [{ type: types.SET_ALL_ENVIRONMENTS }]));
});
});
......@@ -9,20 +9,53 @@ describe('threatMonitoring module getters', () => {
state = createState();
});
describe('currentEnvironmentName', () => {
describe.each`
context | currentEnvironmentId | environments | expectedName
${'no environments'} | ${1} | ${[]} | ${INVALID_CURRENT_ENVIRONMENT_NAME}
${'a non-existent environment id'} | ${2} | ${[{ id: 1 }]} | ${INVALID_CURRENT_ENVIRONMENT_NAME}
${'an existing environment id'} | ${3} | ${[{ id: 3, name: 'foo' }]} | ${'foo'}
`('given $context', ({ currentEnvironmentId, environments, expectedName }) => {
beforeEach(() => {
state.currentEnvironmentId = currentEnvironmentId;
state.environments = environments;
});
describe('currentEnvironment', () => {
beforeEach(() => {
state.environments = [{ id: 1 }, { id: 2 }];
});
it('returns the current environment given a valid ID', () => {
state.currentEnvironmentId = 2;
expect(getters.currentEnvironment(state)).toEqual({ id: 2 });
});
it('returns undefined if the environment can not be found', () => {
state.currentEnvironmentId = 3;
expect(getters.currentEnvironment(state)).toBe(undefined);
});
});
describe.each`
context | currentEnvironmentId | environments | expectedName | expectedGid
${'no environments'} | ${1} | ${[]} | ${INVALID_CURRENT_ENVIRONMENT_NAME} | ${undefined}
${'a non-existent environment id'} | ${2} | ${[{ id: 1 }]} | ${INVALID_CURRENT_ENVIRONMENT_NAME} | ${undefined}
${'an existing environment id'} | ${3} | ${[{ id: 3, name: 'foo', global_id: 'gid://gitlab/Environment/3' }]} | ${'foo'} | ${'gid://gitlab/Environment/3'}
`('given $context', ({ currentEnvironmentId, environments, expectedName, expectedGid }) => {
let mockedGetters;
beforeEach(() => {
state.currentEnvironmentId = currentEnvironmentId;
state.environments = environments;
mockedGetters = {
currentEnvironment: {
id: currentEnvironmentId,
global_id: expectedGid,
name: expectedName,
},
};
});
describe('currentEnvironmentName', () => {
it('returns the expected name', () => {
expect(getters.currentEnvironmentName(state)).toBe(expectedName);
expect(getters.currentEnvironmentName(state, mockedGetters)).toBe(expectedName);
});
});
describe('currentEnvironmentGid', () => {
it('returns the expected global ID', () => {
expect(getters.currentEnvironmentGid(state, mockedGetters)).toBe(expectedGid);
});
});
});
......
......@@ -32,12 +32,11 @@ describe('Threat Monitoring Utils', () => {
describe('getPolicyKind', () => {
it.each`
input | output
${{}} | ${null}
${{ manifest: '' }} | ${null}
${{ manifest: 'ciliumNetworkPolicy' }} | ${null}
${{ manifest: mockL3Manifest }} | ${POLICY_KINDS.ciliumNetwork}
${{ manifest: mockDastScanExecutionManifest }} | ${POLICY_KINDS.scanExecution}
input | output
${''} | ${null}
${'ciliumNetworkPolicy'} | ${null}
${mockL3Manifest} | ${POLICY_KINDS.ciliumNetwork}
${mockDastScanExecutionManifest} | ${POLICY_KINDS.scanExecution}
`('returns $output when used on $input', ({ input, output }) => {
expect(getPolicyKind(input)).toBe(output);
});
......
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