Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSSM-3343 Create test case for IOR #375

Merged
merged 30 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3006760
Set proxy variables from oc get proxy to avoid issue on IPv6 cluster
fjglira Feb 16, 2023
9809714
ext-auth test case
Feb 20, 2023
033de5c
Merge pull request #372 from pbajjuri20/ext-auth
pbajjuri20 Feb 20, 2023
086870f
Adding ior initial main test case
fjglira Feb 21, 2023
4f5726f
Adding changes to finish the test cases
fjglira Feb 21, 2023
977474c
Deleting non necessary time sleep
fjglira Feb 21, 2023
27e1ef4
adding delete configmap on unistall sleep app
fjglira Feb 22, 2023
2b9e3c0
Merge pull request #371 from fjglira/fixes-ipv6
fjglira Feb 22, 2023
d1520e9
Merge branch 'maistra:maistra-2.3' into ior-testcase
fjglira Feb 27, 2023
2655a87
Adding changes to delete istio pod iteration on T38 test case
fjglira Feb 27, 2023
2df8029
Finishing ior test cases
fjglira Mar 2, 2023
4f78378
fix oc patch to enable ior in 2.4
fjglira Mar 27, 2023
b411236
Deleting non used files
fjglira Mar 27, 2023
b6c08a9
Merge remote-tracking branch 'fjglira/ior-testcase' into maistra-2.4
yannuil Apr 18, 2023
fa0a9d4
Rename
yannuil Apr 21, 2023
0eeb7e8
Refactor IOR test to v2.4
yannuil Apr 21, 2023
43fc05e
Merge remote-tracking branch 'origin/maistra-2.4'
yannuil Apr 21, 2023
41d180e
Update
yannuil Apr 21, 2023
d5275b8
Remove unused file
yannuil Apr 21, 2023
d99a128
Apply changes requested
yannuil May 6, 2023
7829315
fix func restartPod delete unused param
fjglira May 9, 2023
f936fdd
make test more readable
fjglira May 9, 2023
fd23d8f
skip some sub test case in 2.3
fjglira May 9, 2023
f0f2872
Update pkg/tests/ossm/ior_test.go
fjglira May 29, 2023
2e61180
Merge remote-tracking branch 'origin/main' OSSM-3343
yannuil Jun 14, 2023
a40a6fc
Refactor tests
yannuil Jun 14, 2023
65d5bb1
Map routes to multi line string for comparison
yannuil Jun 14, 2023
d3b7d98
Compare route yaml except `resourceVersion`
yannuil Jun 14, 2023
8ca5a31
Improve detection on route changes
yannuil Jun 15, 2023
5c7af5f
Lint
yannuil Jun 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
363 changes: 363 additions & 0 deletions pkg/tests/ossm/ior_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,363 @@
package ossm

import (
"encoding/json"
"fmt"
"sort"
"strings"
"testing"

"gopkg.in/yaml.v2"

"github.com/maistra/maistra-test-tool/pkg/util"
"github.com/maistra/maistra-test-tool/pkg/util/env"
"github.com/maistra/maistra-test-tool/pkg/util/oc"
"github.com/maistra/maistra-test-tool/pkg/util/pod"
"github.com/maistra/maistra-test-tool/pkg/util/retry"
"github.com/maistra/maistra-test-tool/pkg/util/shell"
"github.com/maistra/maistra-test-tool/pkg/util/test"
"github.com/maistra/maistra-test-tool/pkg/util/version"
)

type RouteMetadata struct {
Uid string `json:"uid"`
Name string `json:"name"`
ResourceVersion string `json:"resourceVersion"`
Labels map[string]string `json:"labels"`
Annotations map[string]string `json:"annotations"`
}

type Route struct {
Metadata RouteMetadata `json:"metadata"`
}

const (
originalHostAnnotation = "maistra.io/original-host"
)

// TestIOR tests IOR error regarding routes recreated: https://issues.redhat.com/browse/OSSM-1974. IOR will be deprecated on 2.4 and willl be removed on 3.0
fjglira marked this conversation as resolved.
Show resolved Hide resolved
func TestIOR(t *testing.T) {
test.NewTest(t).Groups(test.Full).Run(func(t test.TestHelper) {
t.Log("This test verifies the behavior of IOR.")

meshNamespace := env.GetDefaultMeshNamespace()
meshName := env.GetDefaultSMCPName()

t.Cleanup(func() {
oc.RecreateNamespace(t, meshNamespace)
})

host := "www.test.ocp"

createSimpleGateway := func(t test.TestHelper) {
t.Logf("Creating Gateway for %s host", host)
oc.ApplyString(t, "", generateGateway("gw", meshNamespace, host))
}

checkSimpleGateway := func(t test.TestHelper) {
t.Logf("Checking whether a Route is generated for %s", host)
retry.UntilSuccess(t, func(t test.TestHelper) {
routes := getRoutes(t, meshNamespace)
if len(routes) != 1 {
t.Fatalf("Expect a single route set for %s host, but got %s instead", host, len(routes))
}
found := routes[0].Metadata.Annotations[originalHostAnnotation]
if found != host {
t.Fatalf("Expect a route set for %s host, but got %s instead", host, found)
} else {
t.LogSuccessf("Got an expected Route for %s", host)
}
})
}

DeployControlPlane(t)

t.NewSubTest("check IOR off by default v2.5").Run(func(t test.TestHelper) {
if env.GetSMCPVersion().LessThan(version.SMCP_2_5) {
t.Skip("Skipping until 2.5")
}
t.LogStep("Check whether the IOR has the correct default setting")
if env.GetSMCPVersion().GreaterThanOrEqual(version.SMCP_2_5) {
if getIORSetting(t, meshNamespace, meshName) != "false" {
yannuil marked this conversation as resolved.
Show resolved Hide resolved
t.Fatal("Expect to find IOR disabled by default in v2.4+, but it is currently enabled")
} else {
t.LogSuccess("Got the expected false for IOR setting")
}
} else {
t.Skip("IOR is not set by default versions less than v2.3")
}
luksa marked this conversation as resolved.
Show resolved Hide resolved
})

t.NewSubTest("check IOR basic functionalities").Run(func(t test.TestHelper) {
t.Cleanup(func() {
if env.GetSMCPVersion().GreaterThanOrEqual(version.SMCP_2_5) {
removeIORCustomSetting(t, meshNamespace, meshName)
}
})

t.LogStep("Ensure the IOR enabled")
if env.GetSMCPVersion().GreaterThanOrEqual(version.SMCP_2_5) {
enableIOR(t, meshNamespace, meshName)
}

t.LogStep("Check whether the IOR creates Routes for hosts specified in the Gateway")
createSimpleGateway(t)
checkSimpleGateway(t)
})

t.NewSubTest("check routes aren't deleted during v2.3 to v2.4 upgrade").Run(func(t test.TestHelper) {
if env.GetSMCPVersion().LessThan(version.SMCP_2_4) {
t.Skip("This test only applies for v2.3 to v2.4 upgrade")
}

t.Cleanup(func() {
oc.RecreateNamespace(t, meshNamespace)
setupDefaultSMCP(t, meshNamespace)
})

t.LogStepf("Delete and recreate namespace %s", meshNamespace)
oc.RecreateNamespace(t, meshNamespace)

t.LogStep("Deploy SMCP v2.3")
setupV23SMCP(t, meshNamespace, meshName)

t.LogStep("Check whether IOR creates Routes for hosts specified in the Gateway")
createSimpleGateway(t)
checkSimpleGateway(t)

t.LogStepf("Record the Route before the upgrade")
before := getRoutes(t, meshNamespace)

t.LogStep("Upgrade SMCP to v2.4")
updateToV24SMCP(t, meshNamespace, meshName)

t.LogStep("Check the Routes existed afther the upgrade")
checkSimpleGateway(t)
after := getRoutes(t, meshNamespace)

t.LogStep("Check the Routes unchanged afther the upgrade")
if before[0].Metadata.ResourceVersion != after[0].Metadata.ResourceVersion {
t.Fatal("Expect the route to be unchanged, but it is changed after the upgrade")
} else {
t.LogSuccess("Got the same resourceVersion before and after the upgrade")
}
})

t.NewSubTest("check IOR does not delete routes after deleting Istio pod").Run(func(t test.TestHelper) {
total := 3
nsNames := []string{}
gateways := []string{}

t.Cleanup(func() {
if env.GetSMCPVersion().GreaterThanOrEqual(version.SMCP_2_4) {
removeIORCustomSetting(t, meshNamespace, meshName)
}

oc.DeleteNamespace(t, nsNames...)
oc.ApplyString(t, meshNamespace, GetSMMRTemplate())
oc.WaitSMMRReady(t, meshNamespace)
})

t.LogStep("Ensure the IOR enabled")
if env.GetSMCPVersion().GreaterThanOrEqual(version.SMCP_2_4) {
enableIOR(t, meshNamespace, meshName)
}

t.LogStepf("Create %d Gateways and they are in their own Namespace", total)
gatewayMap := make(map[string]string)
for i := 0; i < total; i++ {
ns := fmt.Sprintf("ns-%d", i)
nsNames = append(nsNames, ns)
gatewayName := fmt.Sprintf("gw-%d", i)
gatewayHost := fmt.Sprintf("www-%d.test.ocp", i)
gateways = append(gateways, generateGateway(gatewayName, ns, gatewayHost))
gatewayMap[gatewayName] = gatewayHost
}
oc.CreateNamespace(t, nsNames...)
oc.ApplyString(t, "", gateways...)

t.LogStepf("Update SMMR to include %d Namespaces", total)
oc.ApplyString(t, meshNamespace, AppendDefaultSMMR(nsNames...))
oc.WaitSMMRReady(t, meshNamespace)

retry.UntilSuccess(t, func(t test.TestHelper) {
routes := getRoutes(t, meshNamespace)
if len(routes) != total {
t.Fatalf("Expect to find %d Routes but found %d instead", total, len(routes))
}

newGatewayMap := make(map[string]string)
for _, r := range routes {
newGatewayMap[r.Metadata.Labels["maistra.io/gateway-name"]] = r.Metadata.Annotations[originalHostAnnotation]
}

var (
err error
beforeYaml []byte
afterYaml []byte
)
if beforeYaml, err = yaml.Marshal(gatewayMap); err != nil {
t.Fatalf("Failed to marshal %s", gatewayMap)
}
if afterYaml, err = yaml.Marshal(gatewayMap); err != nil {
t.Fatalf("Failed to marshal %s", newGatewayMap)
}
if err := util.Compare(beforeYaml, afterYaml); err != nil {
t.Fatalf("Expected %d Routes created for each Gateway but got %s.", total, err)
}

t.LogSuccessf("Found all %d Routes", total)
})

before := buildManagedRouteYamlDocument(t, meshNamespace)
detectRouteChanges := func(t test.TestHelper) {
after := buildManagedRouteYamlDocument(t, meshNamespace)
if err := util.Compare(
[]byte(before),
[]byte(after)); err != nil {
t.Fatalf("Expect %d Routes remain unchanged, but they changed\n%s", total, err)
}

t.LogSuccessf("Got %d Routes unchanged", total)
}

t.LogStepf("Check whether the Routes changes when the istio pod restarts multiple times")
t.Log("Restart pod 10 times to make sure the Routes are not changed")
count := 10
for i := 0; i < count; i++ {
istiodPod := pod.MatchingSelector("app=istiod", meshNamespace)
oc.DeletePod(t, istiodPod)
oc.WaitPodReady(t, istiodPod)
}
oc.WaitSMCPReady(t, meshNamespace, smcpName)
detectRouteChanges(t)

t.LogStepf("Check weather the Routes changes when adding new IngressGateway")
addAdditionalIngressGateway(t, meshName, meshNamespace, "additional-test-ior-ingress-gateway")
detectRouteChanges(t)
})
})
}

func addAdditionalIngressGateway(t test.TestHelper, meshName, meshNamespace, gatewayName string) {
oc.Patch(t, meshNamespace,
"smcp", meshName,
"merge", fmt.Sprintf(`
{
"spec": {
"gateways": {
"additionalIngress": {
"%s": {}
}
}
}
}
`, gatewayName))
oc.WaitSMCPReady(t, meshNamespace, meshName)
}

func getRoutes(t test.TestHelper, ns string) []Route {
res := shell.Executef(t, "oc -n %s get --selector 'maistra.io/generated-by=ior' --output 'jsonpath={.items}' route", ns)
var routes []Route
err := json.Unmarshal([]byte(res), &routes)
if err != nil {
t.Fatalf("Error parsing data %s: %v", res, err)
}

return routes
}

func getRouteNames(t test.TestHelper, ns string) []string {
return strings.Split(
shell.Executef(t,
"oc -n %s get --selector 'maistra.io/generated-by=ior' --output 'jsonpath={.items[*].metadata.name}' route",
ns),
" ")
}

func buildManagedRouteYamlDocument(t test.TestHelper, ns string) string {
names := getRouteNames(t, ns)
sort.Strings(names)

doc := ""
for _, name := range names {
route := oc.GetYaml(t, ns, "route", name)

lines := strings.Split(route, "\n")
count := len(lines)
found := false

for i := 0; found == false && i < count; i++ {
if strings.HasPrefix(strings.TrimSpace(lines[i]), "resourceVersion") {
found = true
lines[i] = ""
}
}

doc += fmt.Sprintf("%s\n---\n", strings.Join(lines, "\n"))
}

return doc
}

func setupDefaultSMCP(t test.TestHelper, ns string) {
InstallSMCP(t, ns)
oc.WaitSMCPReady(t, ns, env.GetDefaultSMCPName())
}

func setupV23SMCP(t test.TestHelper, ns, name string) {
InstallSMCPVersion(t, ns, version.SMCP_2_3)
oc.WaitSMCPReady(t, ns, name)

oc.ApplyString(t, ns, GetSMMRTemplate())
oc.WaitSMMRReady(t, ns)
}

func updateToV24SMCP(t test.TestHelper, ns, name string) {
oc.Patch(t, ns,
"smcp", name,
"json", `[{"op": "add", "path": "/spec/version", "value": "v2.4"}]`)
oc.WaitSMCPReady(t, ns, name)
}

func getIORSetting(t test.TestHelper, ns, name string) string {
return shell.Executef(t,
`oc -n %s get smcp/%s -o jsonpath='{.status.appliedValues.istio.gateways.istio-ingressgateway.ior_enabled}'`,
ns, name)
}

func enableIOR(t test.TestHelper, ns, name string) {
oc.Patch(t,
ns, "smcp", name, "json",
`[{"op": "add", "path": "/spec/gateways", "value": {"openshiftRoute": {"enabled": true}}}]`,
)
}

func removeIORCustomSetting(t test.TestHelper, ns, name string) {
oc.Patch(t,
ns, "smcp", name, "json",
`[{"op": "remove", "path": "/spec/gateways"}]`,
)
}

func generateGateway(name, ns, host string) string {
return fmt.Sprintf(`
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: "%s"
namespace: "%s"
spec:
selector:
istio: "ingressgateway"
servers:
- hosts:
- "%s"
port:
name: "http"
number: 80
protocol: "HTTP"
---`,
name, ns, host,
)
}
9 changes: 9 additions & 0 deletions pkg/tests/ossm/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package ossm

import (
_ "embed"
"fmt"
"strings"

"github.com/maistra/maistra-test-tool/pkg/util/env"
"github.com/maistra/maistra-test-tool/pkg/util/ns"
Expand Down Expand Up @@ -128,6 +130,13 @@ func GetSMMRTemplate() string {
return smmr
}

func AppendDefaultSMMR(namespaces ...string) string {
return fmt.Sprintf(`
%s
- %s
`, smmr, strings.Join(namespaces, "\n - "))
}

func GetProfileFile() string {
return profileFile
}