Service profiles integration tests#2638
Conversation
|
Integration test results for c4b4f3b: fail 😕 |
alpeb
left a comment
There was a problem hiding this comment.
Looking good 👍
I added a few comments below.
Also I didn't see the new files emojivoto-injected.yml and Voting.proto being used, mabye they were added by mistake?
| func TestServiceProfilesFromTap(t *testing.T) { | ||
| testCases := []testCase{ | ||
| { | ||
| namespace: "emojivoto", |
There was a problem hiding this comment.
Would you mind leveraging TestHelper.GetTestNamespace to generate these namespaces with a prefix? It's not uncommon to have emojivoto/booksapp lying around and this would conflict.
This would imply removing the namespace workload in emojivoto.yml and booksapp.yml, and all the namespace fields in emojivoto.yml.
Also by using a prefix you could leave those namespaces around like the other tests do, for bin/clean-up to take care of, without having to rely on tearDown().
|
|
||
| for _, tc := range testCases { | ||
| t.Run(fmt.Sprintf("service profiles from tap:%s", tc.namespace), func(t *testing.T) { | ||
| cmd := []string{"inject", fmt.Sprintf("testdata/%s", tc.injectYAML)} |
There was a problem hiding this comment.
Since #2595 got merged, install_test.go is leaving the control plane with auto-injection enabled, so you don't need to explicitly inject things. Although this doesn't create a problem per se, as the auto-injector will just ignore payloads that are already injected...
There was a problem hiding this comment.
Confirming that this assumes that the namespaces for these apps have linkerd.io/inject: enabled? I could see value in testing both ways, though either approach would be fine for these tests.
| return true | ||
| } | ||
|
|
||
| func getRoutes(deployName, namespace string, helper *testutil.TestHelper) ([]string, error) { |
There was a problem hiding this comment.
The TestHelper is already global, so you don't need to pass it here.
| t.Fatalf("routes command failed: %s\n", err) | ||
| } | ||
|
|
||
| if len(routes) <= 1 { |
There was a problem hiding this comment.
I guess you could use here assertExpectedRoutes as you do below.
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/cloudflare/cfssl/log" |
siggy
left a comment
There was a problem hiding this comment.
looking good, awesome to include tests for swagger, proto, and tap.
these tests are adding nearly 5 minutes on my laptop. i suspect a lot of that is taken up by tearDown(), which will go away per @alpeb's comment.
i think a lot of the rest of the time is spent on deployment, particularly booksapp. consider deploying something smaller with less startup time, or just re-use/modify smoke-test.yaml, which should already be deployed and injected by the time your tests run. also have a look at tap_application.yaml.
$ go test -v ./test/serviceprofiles -integration-tests -linkerd `pwd`/bin/linkerd
=== RUN TestServiceProfilesFromTap
=== RUN TestServiceProfilesFromTap/service_profiles_from_tap:emojivoto
=== RUN TestServiceProfilesFromTap/service_profiles_from_tap:booksapp
--- PASS: TestServiceProfilesFromTap (166.14s)
--- PASS: TestServiceProfilesFromTap/service_profiles_from_tap:emojivoto (39.31s)
--- PASS: TestServiceProfilesFromTap/service_profiles_from_tap:booksapp (126.83s)
=== RUN TestServiceProfilesFromSwagger
--- PASS: TestServiceProfilesFromSwagger (1.00s)
=== RUN TestServiceProfilesFromProto
--- PASS: TestServiceProfilesFromProto (2.12s)
PASS
ok github.com/linkerd/linkerd2/test/serviceprofiles 289.940s| cmd := []string{"routes", "--namespace", namespace, deployName} | ||
| out, stderr, err := helper.LinkerdRun(cmd...) | ||
| if err != nil { | ||
| log.Infof("error getting routes: %s\n", stderr) |
There was a problem hiding this comment.
we typically don't log in these tests, better to just return the error, or call t.Errorf or t.Fatalf.
|
|
||
| for _, tc := range testCases { | ||
| t.Run(fmt.Sprintf("service profiles from tap:%s", tc.namespace), func(t *testing.T) { | ||
| cmd := []string{"inject", fmt.Sprintf("testdata/%s", tc.injectYAML)} |
There was a problem hiding this comment.
Confirming that this assumes that the namespaces for these apps have linkerd.io/inject: enabled? I could see value in testing both ways, though either approach would be fine for these tests.
| t.Fatalf("routes command failed: %s\n", err.Error()) | ||
| } | ||
| for _, route := range routes { | ||
| if len(route) <= 1 { |
There was a problem hiding this comment.
i think len(route) is testing the length of each route name? should this instead be...
if len(routes) <= 1 {
t.Fatalf("Expected routes for service to be greater than or equal to 1 but got %d\n", len(routes))
}There was a problem hiding this comment.
How do we feel about testing routes the way routes_test.go is doing it (i.e. comparing CLI output with golden files)? Not sure which one is better, but at least with routes_test.go, I can open up the golden file to see what the expected output is.
ihcsim
left a comment
There was a problem hiding this comment.
Thanks for tests!
I think TestServiceProfilesFromTap(), TestServiceProfilesFromSwagger() and TestServiceProfilesFromProto() are essentially very similar, except for the flags passed to the profile command.
TIOLI: Group them as data sources under one TestServiceProfiles() function. I think something like this might work:
diff --git a/test/serviceprofiles/serviceprofiles_test.go b/test/serviceprofiles/serviceprofiles_test.go
index 2b7707fd..314672cd 100644
--- a/test/serviceprofiles/serviceprofiles_test.go
+++ b/test/serviceprofiles/serviceprofiles_test.go
@@ -75,6 +74,65 @@ func TestServiceProfilesFromTap(t *testing.T) {
t.Fatalf("Expected route details for service to be at most 1 but got %d\n", len(routes))
}
+ dataSources := []struct {
+ name string
+ args []string
+ }{
+ {
+ name: "tap",
+ args: []string{
+ tc.deployName,
+ "--tap-route-limit",
+ "5",
+ "--tap-duration",
+ "10s",
+ },
+ },
+ {
+ name: "open-api",
+ args: []string{"testdata/authors.swagger"},
+ },
+ {
+ name: "proto",
+ args: []string{"testdata/Emoji.proto"},
+ },
+ }
+
+ for _, dataSource := range dataSources {
+ routes, err := getRoutes(tc.deployName, tc.namespace, TestHelper)
+ if err != nil {
+ t.Fatalf("routes command failed: %s\n", err)
+ }
+
+ if len(routes) > 1 {
+ t.Fatalf("Expected route details for service to be at-most 1 but got %d\n", len(routes))
+ }
+
+ sourceFlag := fmt.Sprintf("--%s", dataSource.name)
+ cmd := []string{"profile", "--namespace", tc.namespace, tc.spName, sourceFlag}
+ cmd = append(cmd, dataSource.args...)
+ out, _, err := TestHelper.LinkerdRun(cmd...)
+ if err != nil {
+ t.Fatalf("profile command failed: %s\n", err.Error())
+ }
+
+ out, err = TestHelper.KubectlApply(out, tc.namespace)
+ if err != nil {
+ t.Fatalf("kubectl apply command failed:\n%s", err)
+ }
+
+ // check that authors now has more than one route
+ routes, err = getRoutes(tc.deployName, tc.namespace, TestHelper)
+ if err != nil {
+ t.Fatalf("routes command failed: %s\n", err)
+ }
+
+ if len(routes) <= 1 {
+ t.Fatalf("Expected route details for service to be greater than 1 but got %d\n", len(routes))
+ }
+ }| t.Fatalf("routes command failed: %s\n", err.Error()) | ||
| } | ||
| for _, route := range routes { | ||
| if len(route) <= 1 { |
There was a problem hiding this comment.
How do we feel about testing routes the way routes_test.go is doing it (i.e. comparing CLI output with golden files)? Not sure which one is better, but at least with routes_test.go, I can open up the golden file to see what the expected output is.
Signed-off-by: Dennis Adjei-Baah <[email protected]>
Signed-off-by: Dennis Adjei-Baah <[email protected]>
Signed-off-by: Dennis Adjei-Baah <[email protected]>
Signed-off-by: Dennis Adjei-Baah <[email protected]>
Signed-off-by: Dennis Adjei-Baah <[email protected]>
Signed-off-by: Dennis Adjei-Baah <[email protected]>
c4b4f3b to
ccbe530
Compare
|
Integration test results for ccbe530: success 🎉 |
Signed-off-by: Dennis Adjei-Baah <[email protected]>
|
Integration test results for ff99ca3: success 🎉 |
Signed-off-by: Dennis Adjei-Baah <[email protected]>
|
Integration test results for ee5188a: success 🎉 |
ihcsim
left a comment
There was a problem hiding this comment.
Thanks for the changes. Some comments below.
| } | ||
|
|
||
| if !assertExpectedRoutes(tc.expectedRoutes, routes) { | ||
| t.Fatalf("Expected routes to have prefixes:\n%s\nbut got:\n%s", |
There was a problem hiding this comment.
We should make this t.Errorf(), so that even if one test case fails, the loop can continue with subsequent test cases.
Signed-off-by: Dennis Adjei-Baah <[email protected]>
| } | ||
|
|
||
| for _, tc := range testCases { | ||
| t.Run(tc.sourceName, func(t *testing.T) { |
| @@ -0,0 +1,197 @@ | |||
| # slow_cooker --http-> gateway --grpc-> t1 | |||
There was a problem hiding this comment.
what about reusing test/tap/testdata/tap_application.yaml?
There was a problem hiding this comment.
I was thinking about that too, but then I thought it would be better to have a tap_application.yaml specifically for serviceprofiles. If we want to modify t* services for specific test scenarios. e.g modifying t3 to fail 50% of the time to test out and validate retries.
There was a problem hiding this comment.
Makes sense, and I see you just added --percent-failure... mind bumping the bb images to v0.0.5 to match the original version?
| cmd = append(cmd, tc.args...) | ||
| out, _, err := TestHelper.LinkerdRun(cmd...) | ||
| if err != nil { | ||
| t.Fatalf("profile command failed: %s\n", err.Error()) |
There was a problem hiding this comment.
i'm getting a failure on this test (i'll dig into what's happening):
--- FAIL: TestServiceProfiles (33.18s)
--- FAIL: TestServiceProfiles/tap (11.57s)
serviceprofiles_test.go:106: profile command failed: exit status 1
--- PASS: TestServiceProfiles/open-api (0.93s)...mind adding a bit more output to help troubleshoot?
if err != nil {
t.Fatalf("'linkerd %s' command failed with %s: %s\n", cmd, err.Error(), out)
}|
Integration test results for 29021e7: fail 😕 |
|
fwiw i'm getting the same failure locally: https://gist.github.com/l5d-bot/1e79ad2cdbd250b787962861273485c3 |
Signed-off-by: Dennis Adjei-Baah <[email protected]>
|
Integration test results for f965976: success 🎉 |
siggy
left a comment
There was a problem hiding this comment.
lgtm! one more fix but good to go after that 👍 🚢
| cmd = append(cmd, tc.args...) | ||
| out, stderr, err := TestHelper.LinkerdRun(cmd...) | ||
| if err != nil { | ||
| t.Fatalf("'linkerd %s' command failed with %s: %s\n", cmd, err.Error(), stderr) |
There was a problem hiding this comment.
this failed on my local system with:
$ go test -v ./test/serviceprofiles -integration-tests -linkerd `pwd`/bin/linkerd
=== RUN TestServiceProfiles
=== RUN TestServiceProfiles/tap
=== RUN TestServiceProfiles/open-api
--- FAIL: TestServiceProfiles (35.05s)
--- FAIL: TestServiceProfiles/tap (10.43s)
serviceprofiles_test.go:102: 'linkerd [profile --namespace l5d-integration-serviceprofile-test t1-svc --tap deploy/t1 --tap-route-limit 5 --tap-duration 10s]' command failed with exit status 1: Error: Tap duration exceeded, try increasing --tap-duration
Usage:i'm guessing it's a timing issue between slow-cooker's sleep 15 at startup, and the profile --tap --tap-duration 10s not seeing any requests.
i think you can mitigate this by increasing --tap-duration to 25s, but also decrease --tap-route-limit to 1, so the command should complete as soon as it sees the first request.
diff --git a/test/serviceprofiles/serviceprofiles_test.go b/test/serviceprofiles/serviceprofiles_test.go
index 34803828..c3fadc26 100644
--- a/test/serviceprofiles/serviceprofiles_test.go
+++ b/test/serviceprofiles/serviceprofiles_test.go
@@ -84,9 +84,9 @@ func TestServiceProfiles(t *testing.T) {
tc.args = []string{
tc.deployName,
"--tap-route-limit",
- "5",
+ "1",
"--tap-duration",
- "10s",
+ "25s",
}
}| } | ||
|
|
||
| func getRoutes(deployName, namespace string) ([]string, error) { | ||
| cmd := []string{"routes", "--namespace", namespace, deployName} |
There was a problem hiding this comment.
not necessarily for this PR, but it may make parsing easier if you add --output json
ihcsim
left a comment
There was a problem hiding this comment.
👍
Running test [serviceprofiles_test.go]
=== RUN TestServiceProfiles
=== RUN TestServiceProfiles/tap
=== RUN TestServiceProfiles/open-api
--- PASS: TestServiceProfiles (26.97s)
--- PASS: TestServiceProfiles/tap (10.40s)
--- PASS: TestServiceProfiles/open-api (0.38s)
PASS
ok command-line-arguments 27.098s
Signed-off-by: Dennis Adjei-Baah <[email protected]>
|
Integration test results for d1316ef: success 🎉 |
This PR adds integration tests for service profiles that test profile generation through the tap and Open API flags. This work serves as a baseline for additional work to come listed in issue #2518 .
Related to #2518