From 125a7c54642d9456ecd4eb284de70ac85dafbfc7 Mon Sep 17 00:00:00 2001 From: Enrique Llorente Pastora Date: Wed, 10 Mar 2021 13:55:31 +0100 Subject: [PATCH] Test nns update timestamp currentState dependecy (#711) The network configuration at nodes is chaning sometimes without human intervention (at kubevirtci some ipv6 routes disappear sometimes or appear sometimes). This change do a best effort and checks nns update timestamp according to currentState changed or not. Signed-off-by: Quique Llorente --- test/e2e/handler/nns_update_timestamp_test.go | 56 ++++++++++++------- test/e2e/handler/nodes_test.go | 19 ++----- test/e2e/handler/utils.go | 48 +++++++++++++--- 3 files changed, 81 insertions(+), 42 deletions(-) diff --git a/test/e2e/handler/nns_update_timestamp_test.go b/test/e2e/handler/nns_update_timestamp_test.go index 3514782a0..6d3f2b2d6 100644 --- a/test/e2e/handler/nns_update_timestamp_test.go +++ b/test/e2e/handler/nns_update_timestamp_test.go @@ -6,13 +6,9 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - . "github.com/onsi/gomega/gstruct" - - "github.com/andreyvit/diff" "k8s.io/apimachinery/pkg/types" - "github.com/nmstate/kubernetes-nmstate/api/shared" nmstatev1beta1 "github.com/nmstate/kubernetes-nmstate/api/v1beta1" nmstatenode "github.com/nmstate/kubernetes-nmstate/pkg/node" ) @@ -28,24 +24,46 @@ var _ = Describe("[nns] NNS LastSuccessfulUpdateTime", func() { originalNNSs[node] = nodeNetworkState(key) } }) - Context("when network configuration hasn't change", func() { - It("should not be updated", func() { - for node, originalNNS := range originalNNSs { - // Give enough time for the NNS to be updated (3 interval times) - timeout := 3 * nmstatenode.NetworkStateRefresh - key := types.NamespacedName{Name: node} + Context("when network configuration is not changed by a NNCP", func() { + It("nns should not be updated after reconcile", func() { + // Give enough time for the NNS to be reconcile(2 interval times) + interval := 2 * nmstatenode.NetworkStateRefresh + timeout := 4 * interval + Eventually(func() error { + for node, originalNNS := range originalNNSs { + key := types.NamespacedName{Name: node} + currentStatus := nodeNetworkState(key).Status + originalStatus := originalNNS.Status + if currentStatus.CurrentState.String() == originalStatus.CurrentState.String() { + By(fmt.Sprintf("Check LastSuccessfulUpdateTime changed at %s", node)) + Expect(currentStatus.LastSuccessfulUpdateTime).To(Equal(originalStatus.LastSuccessfulUpdateTime)) + } else { + return fmt.Errorf("Network configuration changed, sending and error to retry") + } + } + return nil + }, timeout, interval).Should(Succeed()) + }) + }) + Context("when network configuration is changed externally", func() { + expectedDummyName := "dummy0" - Consistently(func() shared.NodeNetworkStateStatus { - return nodeNetworkState(key).Status - }, timeout, time.Second).Should(MatchAllFields(Fields{ - "CurrentState": WithTransform(shared.State.String, Equal(originalNNS.Status.CurrentState.String())), - "LastSuccessfulUpdateTime": Equal(originalNNS.Status.LastSuccessfulUpdateTime), - "Conditions": Equal(originalNNS.Status.Conditions), - }), func() string { - return fmt.Sprintf("currentState diff: \n%s", diff.LineDiff(originalNNS.Status.CurrentState.String(), nodeNetworkState(key).Status.CurrentState.String())) - }) + BeforeEach(func() { + createDummyConnectionAtAllNodes(expectedDummyName) + }) + AfterEach(func() { + deleteConnectionAndWait(allNodes, expectedDummyName) + }) + It("should update it with according to network state refresh duration", func() { + for node, originalNNS := range originalNNSs { + By(fmt.Sprintf("Checking timestamp against original one %s", originalNNS.Status.LastSuccessfulUpdateTime)) + Eventually(func() time.Time { + currentNNS := nodeNetworkState(types.NamespacedName{Name: node}) + return currentNNS.Status.LastSuccessfulUpdateTime.Time + }, 2*nmstatenode.NetworkStateRefresh, 10*time.Second).Should(BeTemporally(">", originalNNS.Status.LastSuccessfulUpdateTime.Time), "should update it at %s", node) } }) + }) Context("when network configuration is changed by a NNCP", func() { BeforeEach(func() { diff --git a/test/e2e/handler/nodes_test.go b/test/e2e/handler/nodes_test.go index 843904643..8e864bf42 100644 --- a/test/e2e/handler/nodes_test.go +++ b/test/e2e/handler/nodes_test.go @@ -27,28 +27,19 @@ var _ = Describe("[rfe_id:3503][crit:medium][vendor:cnv-qe@redhat.com][level:com }) }) Context("and new interface is configured", func() { - var ( - expectedDummyName = "dummy0" - ) + expectedDummyName := "dummy0" + BeforeEach(func() { - createDummyAtNodes(expectedDummyName) + createDummyConnectionAtNodes(expectedDummyName) }) AfterEach(func() { - deleteConnectionAtNodes(expectedDummyName) - By("Make sure the dummy interface gets deleted") - for _, node := range nodes { - for _, iface := range interfacesNameForNode(node) { - if iface == expectedDummyName { - deleteDeviceAtNode(node, expectedDummyName) - } - } - } + deleteConnectionAndWait(nodes, expectedDummyName) }) It("[test_id:3794]should update node network state with it", func() { for _, nodeName := range nodes { Eventually(func() []string { return interfacesNameForNode(nodeName) - }, node.NetworkStateRefresh, time.Second).Should(ContainElement(expectedDummyName)) + }, 2*node.NetworkStateRefresh, time.Second).Should(ContainElement(expectedDummyName)) } }) }) diff --git a/test/e2e/handler/utils.go b/test/e2e/handler/utils.go index 36f92cefc..fc9457217 100644 --- a/test/e2e/handler/utils.go +++ b/test/e2e/handler/utils.go @@ -21,6 +21,7 @@ import ( nmstate "github.com/nmstate/kubernetes-nmstate/api/shared" nmstatev1beta1 "github.com/nmstate/kubernetes-nmstate/api/v1beta1" + nmstatenode "github.com/nmstate/kubernetes-nmstate/pkg/node" "github.com/nmstate/kubernetes-nmstate/test/cmd" "github.com/nmstate/kubernetes-nmstate/test/e2e/handler/linuxbridge" testenv "github.com/nmstate/kubernetes-nmstate/test/env" @@ -221,24 +222,53 @@ func deleteBridgeAtNodes(bridgeName string, ports ...string) []error { return errs } -func createDummyAtNodes(dummyName string) []error { +func createDummyConnection(nodesToModify []string, dummyName string) []error { By(fmt.Sprintf("Creating dummy %s", dummyName)) - _, errs := runner.RunAtNodes(nodes, "sudo", "nmcli", "con", "add", "type", "dummy", "con-name", dummyName, "ifname", dummyName, "ip4", "192.169.1.50/24") - _, upErrs := runner.RunAtNodes(nodes, "sudo", "nmcli", "con", "up", dummyName) + _, errs := runner.RunAtNodes(nodesToModify, "sudo", "nmcli", "con", "add", "type", "dummy", "con-name", dummyName, "ifname", dummyName, "ip4", "192.169.1.50/24") + _, upErrs := runner.RunAtNodes(nodesToModify, "sudo", "nmcli", "con", "up", dummyName) errs = append(errs, upErrs...) return errs } -func deleteConnectionAtNodes(name string) []error { +func createDummyConnectionAtNodes(dummyName string) []error { + return createDummyConnection(nodes, dummyName) +} + +func createDummyConnectionAtAllNodes(dummyName string) []error { + return createDummyConnection(allNodes, dummyName) +} + +func deleteConnection(nodesToModify []string, name string) []error { By(fmt.Sprintf("Delete connection %s", name)) - _, errs := runner.RunAtNodes(nodes, "sudo", "nmcli", "con", "delete", name) + _, errs := runner.RunAtNodes(nodesToModify, "sudo", "nmcli", "con", "delete", name) return errs } -func deleteDeviceAtNode(node string, name string) error { - By(fmt.Sprintf("Delete device %s at node %s", name, node)) - _, err := runner.RunAtNode(node, "sudo", "nmcli", "device", "delete", name) - return err +func deleteConnectionAtNodes(name string) []error { + return deleteConnection(nodes, name) +} +func deleteConnectionAtAllNodes(name string) []error { + return deleteConnection(allNodes, name) +} + +func deleteDevice(nodesToModify []string, name string) []error { + By(fmt.Sprintf("Delete device %s at nodes %v", name, nodesToModify)) + _, errs := runner.RunAtNodes(nodesToModify, "sudo", "nmcli", "device", "delete", name) + return errs +} + +func waitForInterfaceDeletion(nodesToCheck []string, interfaceName string) { + for _, nodeName := range nodesToCheck { + Eventually(func() []string { + return interfacesNameForNode(nodeName) + }, 2*nmstatenode.NetworkStateRefresh, time.Second).ShouldNot(ContainElement(interfaceName)) + } +} + +func deleteConnectionAndWait(nodesToModify []string, interfaceName string) { + deleteConnection(nodesToModify, interfaceName) + deleteDevice(nodesToModify, interfaceName) + waitForInterfaceDeletion(nodesToModify, interfaceName) } func interfaces(state nmstate.State) []interface{} {