diff --git a/poem/Poem/api/internal_views/metrics.py b/poem/Poem/api/internal_views/metrics.py index 2074b8148..2aadce9c6 100644 --- a/poem/Poem/api/internal_views/metrics.py +++ b/poem/Poem/api/internal_views/metrics.py @@ -46,11 +46,12 @@ def get(self, request, name=None): if name: metrics = poem_models.Metric.objects.filter(name=name) if metrics.count() == 0: - raise NotFound(status=404, - detail='Metric not found') + raise NotFound(status=404, detail='Metric not found') else: metrics = poem_models.Metric.objects.all() + profiles4metrics = get_metrics_in_profiles(request.tenant) + results = [] for metric in metrics: if metric.probeversion: @@ -88,6 +89,8 @@ def get(self, request, name=None): name=metric.name, mtype=mt.mtype.name, tags=[tag.name for tag in mt.tags.all()], + profiles=profiles4metrics[metric.name] + if metric.name in profiles4metrics else [], probeversion=metric.probeversion if metric.probeversion else "", group=group, description=mt.description, diff --git a/poem/Poem/api/internal_views/metrictemplates.py b/poem/Poem/api/internal_views/metrictemplates.py index 41034fcb7..83c0f19cf 100644 --- a/poem/Poem/api/internal_views/metrictemplates.py +++ b/poem/Poem/api/internal_views/metrictemplates.py @@ -758,7 +758,10 @@ def get(self, request, name=None): return Response({ "id": tag.id, "name": tag.name, - "metrics": sorted([metric.name for metric in metrics]) + "metrics": sorted( + [{"name": metric.name} for metric in metrics], + key=lambda m: m["name"] + ) }) except admin_models.MetricTags.DoesNotExist: @@ -777,7 +780,10 @@ def get(self, request, name=None): data.append({ "id": tag.id, "name": tag.name, - "metrics": sorted([metric.name for metric in metrics]) + "metrics": sorted( + [{"name": metric.name} for metric in metrics], + key=lambda m: m["name"] + ) }) return Response(data) @@ -831,14 +837,16 @@ def post(self, request): if len(missing_metrics) > 0: if len(missing_metrics) == 1: - warn_msg = \ - f"{warn_msg}Metric {list(missing_metrics)[0]} " \ + warn_msg = ( + f"{warn_msg}Metric {list(missing_metrics)[0]} " f"does not exist." + ) else: - warn_msg = "{}Metrics {} do not exist.".format( - warn_msg, - ", ".join(sorted(list(missing_metrics))) + warn_msg = ( + f"{warn_msg}Metrics " + f"{', '.join(sorted(list(missing_metrics)))} " + f"do not exist." ) if warn_msg: diff --git a/poem/Poem/api/tests/test_metrics.py b/poem/Poem/api/tests/test_metrics.py index 9fef91a86..bd9843534 100644 --- a/poem/Poem/api/tests/test_metrics.py +++ b/poem/Poem/api/tests/test_metrics.py @@ -313,6 +313,11 @@ def mock_db(): content_type=ct ) +profiles4metrics = { + "argo.AMS-Check": ["ARGO_MON", "ARGO_MON_CRITICAL"], + "argo.AMSPublisher-Check": ["ARGO_MON_INTERNAL"] +} + class ListAllMetricsAPIViewTests(TenantTestCase): @factory.django.mute_signals(pre_save) @@ -424,8 +429,11 @@ def setUp(self): name="org.apel.APEL-Pub" ) - def test_get_metric_list(self): + @patch("Poem.api.internal_views.metrics.get_metrics_in_profiles") + def test_get_metric_list(self, mock_profiles4metrics): + mock_profiles4metrics.return_value = profiles4metrics request = self.factory.get(self.url) + request.tenant = self.tenant force_authenticate(request, user=self.user) response = self.view(request) self.assertEqual( @@ -436,6 +444,7 @@ def test_get_metric_list(self): 'name': 'argo.AMS-Check', 'mtype': 'Active', 'tags': ['test_tag1', 'test_tag2'], + "profiles": ["ARGO_MON", "ARGO_MON_CRITICAL"], 'probeversion': 'ams-probe (0.1.7)', 'group': 'EGI', 'description': 'Description of argo.AMS-Check', @@ -490,6 +499,7 @@ def test_get_metric_list(self): 'name': 'argo.AMSPublisher-Check', 'mtype': 'Active', 'tags': ['test_tag1'], + "profiles": ["ARGO_MON_INTERNAL"], 'probeversion': 'ams-publisher-probe (0.1.7)', 'group': 'EUDAT', 'description': '', @@ -538,6 +548,7 @@ def test_get_metric_list(self): 'name': 'org.apel.APEL-Pub', 'mtype': 'Passive', 'tags': [], + "profiles": [], 'probeversion': '', 'group': 'EGI', 'description': '', @@ -563,8 +574,11 @@ def test_get_metric_list(self): ] ) - def test_get_metric_by_name(self): + @patch("Poem.api.internal_views.metrics.get_metrics_in_profiles") + def test_get_metric_by_name(self, mock_profiles4metrics): + mock_profiles4metrics.return_value = profiles4metrics request = self.factory.get(self.url + 'argo.AMS-Check') + request.tenant = self.tenant force_authenticate(request, user=self.user) response = self.view(request, 'argo.AMS-Check') self.assertEqual( @@ -574,6 +588,7 @@ def test_get_metric_by_name(self): 'name': 'argo.AMS-Check', 'mtype': 'Active', 'tags': ['test_tag1', 'test_tag2'], + "profiles": ["ARGO_MON", "ARGO_MON_CRITICAL"], 'probeversion': 'ams-probe (0.1.7)', 'group': 'EGI', 'description': 'Description of argo.AMS-Check', diff --git a/poem/Poem/api/tests/test_metrictemplates.py b/poem/Poem/api/tests/test_metrictemplates.py index d6a046773..74ae8e4d4 100644 --- a/poem/Poem/api/tests/test_metrictemplates.py +++ b/poem/Poem/api/tests/test_metrictemplates.py @@ -10022,17 +10022,25 @@ def test_get_metric_tags_admin_superuser(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [{ + "name": "argo.AMS-Check" + }] }, { "id": self.tag3.id, "name": "test_tag1", - "metrics": ["argo.AMS-Check", "argo.EGI-Connectors-Check"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "argo.EGI-Connectors-Check"} + ] }, { "id": self.tag4.id, "name": "test_tag2", - "metrics": ["argo.AMS-Check", "org.apel.APEL-Pub"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "org.apel.APEL-Pub"} + ] } ] ) @@ -10052,17 +10060,25 @@ def test_get_metric_tags_admin_regular_user(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [ + {"name": "argo.AMS-Check"} + ] }, { "id": self.tag3.id, "name": "test_tag1", - "metrics": ["argo.AMS-Check", "argo.EGI-Connectors-Check"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "argo.EGI-Connectors-Check"} + ] }, { "id": self.tag4.id, "name": "test_tag2", - "metrics": ["argo.AMS-Check", "org.apel.APEL-Pub"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "org.apel.APEL-Pub"} + ] } ] ) @@ -10082,17 +10098,25 @@ def test_get_metric_tags_tenant_superuser(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [ + {"name": "argo.AMS-Check"} + ] }, { "id": self.tag3.id, "name": "test_tag1", - "metrics": ["argo.AMS-Check", "argo.EGI-Connectors-Check"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "argo.EGI-Connectors-Check"} + ] }, { "id": self.tag4.id, "name": "test_tag2", - "metrics": ["argo.AMS-Check", "org.apel.APEL-Pub"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "org.apel.APEL-Pub"} + ] } ] ) @@ -10112,17 +10136,25 @@ def test_get_metric_tags_tenant_regular_user(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [ + {"name": "argo.AMS-Check"} + ] }, { "id": self.tag3.id, "name": "test_tag1", - "metrics": ["argo.AMS-Check", "argo.EGI-Connectors-Check"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "argo.EGI-Connectors-Check"} + ] }, { "id": self.tag4.id, "name": "test_tag2", - "metrics": ["argo.AMS-Check", "org.apel.APEL-Pub"] + "metrics": [ + {"name": "argo.AMS-Check"}, + {"name": "org.apel.APEL-Pub"} + ] } ] ) @@ -10141,7 +10173,9 @@ def test_get_metric_tag_by_name_admin_superuser(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [ + {"name": "argo.AMS-Check"} + ] } ) @@ -10154,7 +10188,9 @@ def test_get_metric_tag_by_name_admin_regular_user(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [ + {"name": "argo.AMS-Check"} + ] } ) @@ -10167,7 +10203,9 @@ def test_get_metric_tag_by_name_tenant_superuser(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [ + {"name": "argo.AMS-Check"} + ] } ) @@ -10180,7 +10218,9 @@ def test_get_metric_tag_by_name_tenant_regular_user(self): { "id": self.tag1.id, "name": "internal", - "metrics": ["argo.AMS-Check"] + "metrics": [ + {"name": "argo.AMS-Check"} + ] } ) diff --git a/poem/Poem/frontend/react/MetricTags.js b/poem/Poem/frontend/react/MetricTags.js index ad586fd93..5f85a7ad0 100644 --- a/poem/Poem/frontend/react/MetricTags.js +++ b/poem/Poem/frontend/react/MetricTags.js @@ -1,4 +1,4 @@ -import React, { useState } from "react" +import React, { useContext, useEffect, useState } from "react" import { useMutation, useQuery, useQueryClient } from "react-query" import { Link, useLocation, useParams, useNavigate } from "react-router-dom" import { fetchMetricTags, fetchMetricTemplates, fetchUserDetails } from "./QueryFunctions" @@ -31,7 +31,7 @@ import { } from "reactstrap" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faSearch,faPlus, faTimes } from '@fortawesome/free-solid-svg-icons'; -import { Controller, useForm, useWatch } from "react-hook-form" +import { Controller, FormProvider, useFieldArray, useForm, useFormContext, useWatch } from "react-hook-form" import { ErrorMessage } from '@hookform/error-message' import { yupResolver } from '@hookform/resolvers/yup' import * as Yup from "yup" @@ -46,6 +46,9 @@ const validationSchema = Yup.object().shape({ }) +const MetricTagsContext = React.createContext() + + export const MetricTagsList = (props) => { const location = useLocation(); const publicView = props.publicView @@ -80,7 +83,7 @@ export const MetricTagsList = (props) => { : row.value.map((metric, i) => - { metric } + { metric.name } ) } @@ -120,6 +123,134 @@ export const MetricTagsList = (props) => { } +const MetricsList = () => { + const context = useContext(MetricTagsContext) + + const { control, getValues, setValue, resetField } = useFormContext() + + const { fields, insert, remove } = useFieldArray({ control, name: "view_metrics4tag" }) + + const onRemove = (index) => { + let tmp_metrics4tag = [ ...context.metrics4tag ] + let origIndex = tmp_metrics4tag.findIndex(e => e.name == getValues(`view_metrics4tag.${index}.name`)) + tmp_metrics4tag.splice(origIndex, 1) + resetField("metrics4tag") + setValue("metrics4tag", tmp_metrics4tag) + remove(index) + } + + const onInsert = (index) => { + let tmp_metrics4tag = [ ...context.metrics4tag ] + let origIndex = tmp_metrics4tag.findIndex(e => e.name == getValues(`view_metrics4tag.${index}.name`)) + let new_element = { name: "" } + tmp_metrics4tag.splice(origIndex + 1, 0, new_element) + resetField("metrics4tag") + setValue("metrics4tag", tmp_metrics4tag) + insert(index + 1, new_element) + } + + return ( + + + + + + { + !context.publicView && + } + + + + + + + + { + fields.map((item, index) => + + + + + { + !context.publicView && + + } + + + ) + } + +
#Metric templateActions
+ + + + + } + /> +
+ { index + 1 } + + { + context.publicView ? + item.name + : + + { + let origIndex = getValues("metrics4tag").findIndex(met => met.name == getValues(`view_metrics4tag.${index}.name`) ) + setValue(`metrics4tag.${origIndex}.name`, e.value) + setValue(`view_metrics4tag.${index}.name`, e.value) + } } + options={ + context.allMetrics.map( + met => met.name + ).filter( + met => !context.metrics4tag.map(met => met.name).includes(met) + ).map( + option => new Object({ label: option, value: option }) + )} + value={ { label: field.value, value: field.value } } + /> + } + /> + } + + + +
+ ) +} + + const MetricTagsForm = ({ name=undefined, tag=undefined, @@ -142,19 +273,41 @@ const MetricTagsForm = ({ const addMutation = useMutation(async (values) => await backend.addObject('/api/v2/internal/metrictags/', values)); const deleteMutation = useMutation(async () => await backend.deleteObject(`/api/v2/internal/metrictags/${name}`)) - const { control, getValues, setValue, handleSubmit, formState: { errors } } = useForm({ + const default_metrics4tag = tag?.metrics.length > 0 ? tag.metrics : [{ name: "" }] + + const methods = useForm({ defaultValues: { id: `${tag ? tag.id : ""}`, name: `${tag ? tag.name : ""}`, - metrics4tag: tag?.metrics.length > 0 ? tag.metrics : [""], + metrics4tag: default_metrics4tag, + view_metrics4tag: default_metrics4tag, searchItem: "" }, mode: "all", resolver: yupResolver(validationSchema) }) + const { control } = methods + const searchItem = useWatch({ control, name: "searchItem" }) const metrics4tag = useWatch({ control, name: "metrics4tag" }) + const view_metrics4tag = useWatch({ control, name: "view_metrics4tag" }) + + useEffect(() => { + if (view_metrics4tag.length === 0) { + methods.setValue("view_metrics4tag", [{ name: "" }]) + } + }, [view_metrics4tag]) + + useEffect(() => { + if (metrics4tag.length === 0) { + methods.setValue("metrics4tag", [{ name: "" }]) + } + }, [metrics4tag]) + + useEffect(() => { + methods.setValue("view_metrics4tag", metrics4tag.filter(e => e.name.toLowerCase().includes(searchItem.toLowerCase()))) + }, [searchItem]) const toggleAreYouSure = () => { setAreYouSureModal(!areYouSureModal) @@ -171,11 +324,11 @@ const MetricTagsForm = ({ } const doChange = () => { - let formValues = getValues() + let formValues = methods.getValues() const sendValues = new Object({ name: formValues.name, - metrics: formValues.metrics4tag.filter(met => met !== "") + metrics: formValues.metrics4tag.map(met => met.name).filter(met => met !== "") }) if (addview) @@ -279,178 +432,79 @@ const MetricTagsForm = ({ }} toggle={toggleAreYouSure} > -
- - - - - Name - - - } - /> - - - { message } - - } - /> - - - - - - - - - - - - { - !publicView && - } - - - - - - + + Name - } /> - - - { - metrics4tag.filter( - filteredRow => filteredRow.toLowerCase().includes(searchItem.toLowerCase()) - ).map((item, index) => - - - - - { - !publicView && - - } - - - ) - } - -
#Metric templateActions
- - + + + + +
- { index + 1 } - - { - publicView ? - item - : - - { - let tmpMetrics = getValues("metrics4tag") - tmpMetrics[index] = e.value - setValue("metrics4tag", tmpMetrics) - } } - options={ - allMetrics.map( - met => met.name - ).filter( - met => !metrics4tag.includes(met) - ).map( - option => new Object({ label: option, value: option }) - )} - value={ { label: item, value: item } } - /> - } - /> - } - - - -
-
- { - !publicView && -
- { - !addview ? - - : -
- } - -
- } -
+ + + { message } + + } + /> + + + + + + + + + + + { + !publicView && +
+ { + !addview ? + + : +
+ } + +
+ } + + ) } diff --git a/poem/Poem/frontend/react/Metrics.js b/poem/Poem/frontend/react/Metrics.js index 6ace548c4..7be3234f1 100644 --- a/poem/Poem/frontend/react/Metrics.js +++ b/poem/Poem/frontend/react/Metrics.js @@ -860,6 +860,7 @@ export const MetricForm = defaultValues: { id: initValues.id ? initValues.id : "", name: initValues.name, + profiles: initValues.profiles, probeversion: initValues.probeversion, type: initValues.type, group: initValues.group ? initValues.group: "", @@ -968,6 +969,25 @@ export const MetricForm = toggleAreYouSure() } + function onDeleteHandle() { + let profiles = getValues("profiles") + let name = getValues("name") + let msg = "" + + if (resourcename === "metric" && !isHistory && profiles.length > 0) { + msg =
+

Metric { name } is part of profile(s): { profiles.join(", ") }

+

ARE YOU SURE you want to delete it?

+
+ } else + msg = `Are you sure you want to delete ${resourcename_beautify}?` + + setModalMsg(msg) + setModalTitle(`Delete ${resourcename_beautify}`) + setModalFlag('delete') + toggleAreYouSure() + } + return ( { - setModalMsg(`Are you sure you want to delete ${resourcename_beautify}?`) - setModalTitle(`Delete ${resourcename_beautify}`) - setModalFlag('delete') - toggleAreYouSure() - }} + onClick={() => onDeleteHandle()} > Delete @@ -1707,7 +1722,8 @@ export const MetricChange = (props) => { file_attributes: metric.files, file_parameters: metric.fileparameter, probe: probe, - tags: metric.tags + tags: metric.tags, + profiles: metric.profiles }} isTenantSchema={ true } groups={ groups } diff --git a/poem/Poem/frontend/react/__tests__/MetricTags.test.js b/poem/Poem/frontend/react/__tests__/MetricTags.test.js index 10951d4cd..74d99af23 100644 --- a/poem/Poem/frontend/react/__tests__/MetricTags.test.js +++ b/poem/Poem/frontend/react/__tests__/MetricTags.test.js @@ -45,22 +45,27 @@ const mockListTags = [ { id: "3", name: "internal", - metrics: ["argo.AMSPublisher-Check"] + metrics: [ + { "name": "argo.AMSPublisher-Check" } + ] }, { id: "4", name: "harmonized", metrics: [ - "generic.certificate.validity", - "generic.http.connect", - "generic.tcp.connect", + { "name": "generic.certificate.validity" }, + { "name": "generic.http.connect" }, + { "name": "generic.tcp.connect" } ] }, { id: "2", name: "messaging", - metrics: ["argo.AMS-Check", "argo.AMSPublisher-Check"] - }, + metrics: [ + { "name": "argo.AMS-Check" }, + { "name": "argo.AMSPublisher-Check" } + ] + } ] const mockActiveSession = { @@ -561,6 +566,49 @@ describe("Test metric tags changeview", () => { ) }) + test("Test change metric tags name in filtered view", async () => { + mockChangeObject.mockReturnValueOnce( + Promise.resolve({ ok: true, status: 201, statusText: "CREATED" }) + ) + + renderChangeView() + + await waitFor(() => { + expect(screen.getByRole("button", { name: /save/i })).toBeInTheDocument() + }) + + fireEvent.change(screen.getByPlaceholderText(/search/i), { target: { value: "connect" } }) + + fireEvent.change(screen.getByTestId("name"), { target: { value: "test_tag" } }) + + await waitFor(() => { + expect(screen.getByTestId("form")).toHaveFormValues({name: "test_tag"}) + }) + + fireEvent.click(screen.getByRole('button', { name: /save/i })); + await waitFor(() => { + expect(screen.getByRole('dialog', { title: /change/i })).toBeInTheDocument(); + }) + fireEvent.click(screen.getByRole('button', { name: /yes/i })); + + await waitFor(() => { + expect(mockChangeObject).toHaveBeenCalledWith( + "/api/v2/internal/metrictags/", + { id: "4", name: "test_tag", metrics: ["generic.certificate.validity", "generic.http.connect", "generic.tcp.connect"] } + ) + }) + + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictemplate") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictemplate") + expect(NotificationManager.success).toHaveBeenCalledWith( + "Metric tag successfully changed", "Changed", 2000 + ) + }) + test("Test error changing metric tag with error message", async () => { mockChangeObject.mockImplementationOnce(() => { throw Error("400 BAD REQUEST: Metric tag with this name already exists.") @@ -654,10 +702,160 @@ describe("Test metric tags changeview", () => { expect(screen.getByRole("button", { name: /save/i })).toBeInTheDocument() }) - await selectEvent.select(screen.getByText("generic.certificate.validity"), "argo.AMS-Check") + await waitFor(() => { + selectEvent.select(screen.getByText("generic.certificate.validity"), "argo.AMS-Check") + }) + + fireEvent.click(screen.getByRole('button', { name: /save/i })); + await waitFor(() => { + expect(screen.getByRole('dialog', { title: /change/i })).toBeInTheDocument(); + }) + fireEvent.click(screen.getByRole('button', { name: /yes/i })); + + await waitFor(() => { + expect(mockChangeObject).toHaveBeenCalledWith( + "/api/v2/internal/metrictags/", + { id: "4", name: "harmonized", metrics: ["argo.AMS-Check", "generic.http.connect", "generic.tcp.connect"] } + ) + }) + + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictemplate") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictemplate") + expect(NotificationManager.success).toHaveBeenCalledWith( + "Metric tag successfully changed", "Changed", 2000 + ) + }) + + test("Test change metrics for metric tag in filtered view", async () => { + mockChangeObject.mockReturnValueOnce( + Promise.resolve({ ok: true, status: 201, statusText: "CREATED" }) + ) + + renderChangeView() + + await waitFor(() => { + expect(screen.getByRole("button", { name: /save/i })).toBeInTheDocument() + }) + + fireEvent.change(screen.getByPlaceholderText(/search/i), { target: { value: "connect" } }) + + await selectEvent.select(screen.getByText("generic.http.connect"), "argo.AMS-Check") + + fireEvent.click(screen.getByRole('button', { name: /save/i })); + await waitFor(() => { + expect(screen.getByRole('dialog', { title: /change/i })).toBeInTheDocument(); + }) + fireEvent.click(screen.getByRole('button', { name: /yes/i })); + + await waitFor(() => { + expect(mockChangeObject).toHaveBeenCalledWith( + "/api/v2/internal/metrictags/", + { id: "4", name: "harmonized", metrics: ["generic.certificate.validity", "argo.AMS-Check", "generic.tcp.connect"] } + ) + }) + + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictemplate") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictemplate") + expect(NotificationManager.success).toHaveBeenCalledWith( + "Metric tag successfully changed", "Changed", 2000 + ) + }) + + test("Test delete metrics from metric tag", async () => { + mockChangeObject.mockReturnValueOnce( + Promise.resolve({ ok: true, status: 201, statusText: "CREATED" }) + ) + + renderChangeView() + + await waitFor(() => { + expect(screen.getByRole("button", { name: /save/i })).toBeInTheDocument() + }) fireEvent.click(screen.getByTestId("remove-1")) + fireEvent.click(screen.getByRole('button', { name: /save/i })); + await waitFor(() => { + expect(screen.getByRole('dialog', { title: /change/i })).toBeInTheDocument(); + }) + fireEvent.click(screen.getByRole('button', { name: /yes/i })); + + await waitFor(() => { + expect(mockChangeObject).toHaveBeenCalledWith( + "/api/v2/internal/metrictags/", + { id: "4", name: "harmonized", metrics: ["generic.certificate.validity", "generic.tcp.connect"] } + ) + }) + + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictemplate") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictemplate") + expect(NotificationManager.success).toHaveBeenCalledWith( + "Metric tag successfully changed", "Changed", 2000 + ) + }) + + test("Test delete metrics from metric tag if filtered view", async () => { + mockChangeObject.mockReturnValueOnce( + Promise.resolve({ ok: true, status: 201, statusText: "CREATED" }) + ) + + renderChangeView() + + await waitFor(() => { + expect(screen.getByRole("button", { name: /save/i })).toBeInTheDocument() + }) + + fireEvent.change(screen.getByPlaceholderText(/search/i), { target: { value: "connect" } }) + + fireEvent.click(screen.getByTestId("remove-0")) + + fireEvent.click(screen.getByRole('button', { name: /save/i })); + await waitFor(() => { + expect(screen.getByRole('dialog', { title: /change/i })).toBeInTheDocument(); + }) + fireEvent.click(screen.getByRole('button', { name: /yes/i })); + + await waitFor(() => { + expect(mockChangeObject).toHaveBeenCalledWith( + "/api/v2/internal/metrictags/", + { id: "4", name: "harmonized", metrics: ["generic.certificate.validity", "generic.tcp.connect"] } + ) + }) + + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictemplate") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictemplate") + expect(NotificationManager.success).toHaveBeenCalledWith( + "Metric tag successfully changed", "Changed", 2000 + ) + }) + + test("Test insert new metrics for metric tag", async () => { + mockChangeObject.mockReturnValueOnce( + Promise.resolve({ ok: true, status: 201, statusText: "CREATED" }) + ) + + renderChangeView() + + await waitFor(() => { + expect(screen.getByRole("button", { name: /save/i })).toBeInTheDocument() + }) + fireEvent.click(screen.getByTestId("insert-0")) const table = within(screen.getByRole("table")) @@ -675,7 +873,54 @@ describe("Test metric tags changeview", () => { await waitFor(() => { expect(mockChangeObject).toHaveBeenCalledWith( "/api/v2/internal/metrictags/", - { id: "4", name: "harmonized", metrics: ["argo.AMS-Check", "argo.AMSPublisher-Check", "generic.tcp.connect"] } + { id: "4", name: "harmonized", metrics: ["generic.certificate.validity", "argo.AMSPublisher-Check", "generic.http.connect", "generic.tcp.connect"] } + ) + }) + + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("metrictemplate") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictags") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metric") + expect(queryClient.invalidateQueries).toHaveBeenCalledWith("public_metrictemplate") + expect(NotificationManager.success).toHaveBeenCalledWith( + "Metric tag successfully changed", "Changed", 2000 + ) + }) + + test("Test insert new metrics for metric tag in filtered view", async () => { + mockChangeObject.mockReturnValueOnce( + Promise.resolve({ ok: true, status: 201, statusText: "CREATED" }) + ) + + renderChangeView() + + await waitFor(() => { + expect(screen.getByRole("button", { name: /save/i })).toBeInTheDocument() + }) + + fireEvent.change(screen.getByPlaceholderText(/search/i), { target: { value: "connect" } }) + + fireEvent.click(screen.getByTestId("insert-0")) + + const table = within(screen.getByRole("table")) + + const row2 = table.getAllByRole("row")[3] + + await waitFor(() => { + selectEvent.select(within(row2).getByRole("combobox"), "argo.AMSPublisher-Check") + }) + + fireEvent.click(screen.getByRole('button', { name: /save/i })); + await waitFor(() => { + expect(screen.getByRole('dialog', { title: /change/i })).toBeInTheDocument(); + }) + fireEvent.click(screen.getByRole('button', { name: /yes/i })); + + await waitFor(() => { + expect(mockChangeObject).toHaveBeenCalledWith( + "/api/v2/internal/metrictags/", + { id: "4", name: "harmonized", metrics: ["generic.certificate.validity", "generic.http.connect", "argo.AMSPublisher-Check", "generic.tcp.connect"] } ) }) @@ -716,7 +961,9 @@ describe("Test metric tags changeview", () => { const row2 = table.getAllByRole("row")[3] - await selectEvent.select(within(row2).getByRole("combobox"), "argo.AMSPublisher-Check") + await waitFor(() => { + selectEvent.select(within(row2).getByRole("combobox"), "argo.AMSPublisher-Check") + }) fireEvent.click(screen.getByRole('button', { name: /save/i })); await waitFor(() => { @@ -777,7 +1024,9 @@ describe("Test metric tags changeview", () => { const row2 = table.getAllByRole("row")[3] - await selectEvent.select(within(row2).getByRole("combobox"), "argo.AMSPublisher-Check") + await waitFor(() => { + selectEvent.select(within(row2).getByRole("combobox"), "argo.AMSPublisher-Check") + }) fireEvent.click(screen.getByRole('button', { name: /save/i })); await waitFor(() => { @@ -1018,6 +1267,11 @@ describe("Test metric tags addview", () => { expect(table.queryByText(/generic/i)).not.toBeInTheDocument() expect(table.queryByText(/argo/i)).not.toBeInTheDocument() + expect(table.queryByText("generic.certificate.validity")).not.toBeInTheDocument() + expect(table.queryByText("generic.http.connect")).not.toBeInTheDocument() + expect(table.queryByText("generic.tcp.connect")).not.toBeInTheDocument() + expect(table.queryByText("argo.AMS-Check")).not.toBeInTheDocument() + expect(table.queryByText("argo.AMSPublisher-Check")).not.toBeInTheDocument() selectEvent.openMenu(input) expect(table.getByText("generic.certificate.validity")).toBeInTheDocument() expect(table.getByText("generic.http.connect")).toBeInTheDocument() @@ -1094,24 +1348,46 @@ describe("Test metric tags addview", () => { const row1 = table.getAllByRole("row")[2] const input1 = within(row1).getByRole("combobox") - await selectEvent.select(input1, "generic.certificate.validity") + await waitFor(() => { + selectEvent.select(input1, "generic.certificate.validity") + }) + + await waitFor(() => { + expect(table.queryByText("generic.http.connect")).not.toBeInTheDocument() + }) fireEvent.click(table.getByTestId("insert-0")) const row2 = table.getAllByRole("row")[3] const input2 = within(row2).getByRole("combobox") - await selectEvent.select(input2, "generic.http.connect") + await waitFor(() => { + selectEvent.select(input2, "generic.http.connect") + }) + + await waitFor(() => { + expect(table.queryByText("generic.tcp.connect")).not.toBeInTheDocument() + }) fireEvent.click(table.getByTestId("insert-1")) const row3 = table.getAllByRole("row")[4] const input3 = within(row3).getByRole("combobox") - await selectEvent.select(input3, "generic.tcp.connect") + await waitFor(() => { + selectEvent.select(input3, "generic.tcp.connect") + }) + + await waitFor(() => { + expect(table.getByText("generic.tcp.connect")).toBeInTheDocument() + }) fireEvent.click(table.getByTestId("remove-1")) + await waitFor(() => { + expect(table.queryByText("generic.http.connect")).not.toBeInTheDocument() + }) + await selectEvent.select(table.getByText("generic.tcp.connect"), "argo.AMS-Check") fireEvent.click(screen.getByRole('button', { name: /save/i })); @@ -1161,13 +1437,25 @@ describe("Test metric tags addview", () => { const row1 = table.getAllByRole("row")[2] const input1 = within(row1).getByRole("combobox") - await selectEvent.select(input1, "generic.tcp.connect") + await waitFor(() => { + selectEvent.select(input1, "generic.tcp.connect") + }) + + await waitFor(() => { + expect(table.getByText("generic.tcp.connect")).toBeInTheDocument() + }) fireEvent.click(table.getByTestId("insert-0")) const row2 = table.getAllByRole("row")[3] - await selectEvent.select(within(row2).getByRole("combobox"), "generic.http.connect") + await waitFor(() => { + selectEvent.select(within(row2).getByRole("combobox"), "generic.http.connect") + }) + + await waitFor(() => { + expect(table.getByText("generic.http.connect")).toBeInTheDocument() + }) fireEvent.click(screen.getByRole('button', { name: /save/i })); await waitFor(() => { @@ -1225,13 +1513,25 @@ describe("Test metric tags addview", () => { const row1 = table.getAllByRole("row")[2] const input1 = within(row1).getByRole("combobox") - await selectEvent.select(input1, "generic.tcp.connect") + await waitFor(() => { + selectEvent.select(input1, "generic.tcp.connect") + }) + + await waitFor(() => { + expect(table.getByText("generic.tcp.connect")).toBeInTheDocument() + }) fireEvent.click(table.getByTestId("insert-0")) const row2 = table.getAllByRole("row")[3] - await selectEvent.select(within(row2).getByRole("combobox"), "generic.http.connect") + await waitFor(() => { + selectEvent.select(within(row2).getByRole("combobox"), "generic.http.connect") + }) + + await waitFor(() => { + expect(table.getByText("generic.http.connect")).toBeInTheDocument() + }) fireEvent.click(screen.getByRole('button', { name: /save/i })); await waitFor(() => { diff --git a/poem/Poem/frontend/react/__tests__/Metrics.test.js b/poem/Poem/frontend/react/__tests__/Metrics.test.js index 65f91871c..08768e7f1 100644 --- a/poem/Poem/frontend/react/__tests__/Metrics.test.js +++ b/poem/Poem/frontend/react/__tests__/Metrics.test.js @@ -15,6 +15,7 @@ const mockListOfMetrics = [ name: 'argo.AMS-Check', mtype: 'Active', tags: ['test_tag1', 'test_tag2'], + profiles: ["ARGO_MON", "TEST_PROFILE"], probeversion: 'ams-probe (0.1.12)', group: 'EGI', description: 'Description of argo.AMS-Check metric', @@ -44,6 +45,7 @@ const mockListOfMetrics = [ name: 'argo.AMS-Publisher', mtype: 'Active', tags: ['internal'], + profiles: ["ARGO_MON_INTERNAL"], probeversion: 'ams-publisher-probe (0.1.12)', group: 'EGI', description: '', @@ -74,6 +76,7 @@ const mockListOfMetrics = [ name: 'org.apel.APEL-Pub', mtype: 'Passive', tags: [], + profiles: [], probeversion: '', group: 'ARGOTEST', description: '', @@ -97,6 +100,7 @@ const mockMetric = { name: 'argo.AMS-Check', mtype: 'Active', tags: ['test_tag1', 'test_tag2'], + profiles: ["ARGO_MON", "TEST_PROFILE"], probeversion: 'ams-probe (0.1.12)', group: 'EGI', description: 'Description of argo.AMS-Check metric', @@ -127,6 +131,7 @@ const mockPassiveMetric = { name: 'org.apel.APEL-Pub', mtype: 'Passive', tags: [], + profiles: [], probeversion: '', group: 'ARGOTEST', description: '',