From c42ea8b8d8a4c4b25aa15a034688b6913b1dadfb Mon Sep 17 00:00:00 2001 From: mathetake Date: Thu, 10 Sep 2020 14:28:43 +0900 Subject: [PATCH] add e2e tests on examples --- Makefile | 4 +- e2e/e2e_test.go | 246 ++++++++++++++++++++++++++++++++- examples/helloworld/envoy.yaml | 8 +- examples/shared_queue/main.go | 2 +- 4 files changed, 252 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 39b04d9c..f416fe01 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .DEFAULT_GOAL := build.examples -.PHONY: help build.examples lint test test.sdk test.e2e +.PHONY: help build.example build.examples lint test test.sdk test.e2e help: grep -E '^[a-z0-9A-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @@ -20,7 +20,7 @@ test.sdk: go test -tags=proxytest -race -v ./proxywasm/... test.e2e: - go test -tags=proxytest -race -v ./e2e + go test -tags=proxytest -v ./e2e run: getenvoy run wasm:1.15 -- -c ./examples/${name}/envoy.yaml diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index 09ebf438..69a1d6ef 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -1,7 +1,251 @@ +// Copyright 2020 Tetrate +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package e2e import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "strings" "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMain(m *testing.M) { + if err := os.Chdir(".."); err != nil { + log.Fatal(err) + } + os.Exit(m.Run()) +} + +const ( + envoyVersion = "wasm:1.15" + envoyEndpoint = "http://localhost:18000" + envoyAdminEndpoint = "http://localhost:8001" ) -func Test_examples(t *testing.T) {} +func startExample(t *testing.T, name string) (*exec.Cmd, *bytes.Buffer) { + cmd := exec.Command("getenvoy", + "run", + envoyVersion, + "--", + "--concurrency", "1", + "-c", fmt.Sprintf("./examples/%s/envoy.yaml", name)) + + buf := new(bytes.Buffer) + cmd.Stderr = buf + require.NoError(t, cmd.Start()) + + time.Sleep(time.Second * 5) // TODO: use admin endpoint to check health + return cmd, buf +} + +func TestE2E_helloworld(t *testing.T) { + cmd, stdErr := startExample(t, "helloworld") + defer func() { + require.NoError(t, cmd.Process.Kill()) + }() + + out := stdErr.String() + fmt.Println(out) + + var onVMLog, onTickOK bool + for _, line := range strings.Split(out, "\n") { + if strings.Contains(line, "wasm log helloworld: proxy_on_vm_start from Go!") { + fmt.Println(line) + onVMLog = true + } + + if strings.Contains(line, "wasm log helloworld: OnTick on ") { + fmt.Println(line) + onTickOK = true + } + } + + assert.True(t, onVMLog) + assert.True(t, onTickOK) +} + +func TestE2E_http_auth_random(t *testing.T) { + cmd, stdErr := startExample(t, "http_auth_random") + defer func() { + require.NoError(t, cmd.Process.Kill()) + }() + + req, err := http.NewRequest("GET", envoyEndpoint+"/uuid", nil) + require.NoError(t, err) + + key := "this-is-key" + value := "this-is-value" + req.Header.Add(key, value) + + for i := 0; i < 25; i++ { // TODO: maybe flaky + r, err := http.DefaultClient.Do(req) + require.NoError(t, err) + r.Body.Close() + } + + out := stdErr.String() + fmt.Println(out) + var accessForbidden bool + var accessGranted bool + for _, line := range strings.Split(out, "\n") { + if strings.Contains(line, "access forbidden") { + accessForbidden = true + } + + if strings.Contains(line, "access granted") { + accessGranted = true + } + } + + assert.True(t, accessForbidden) + assert.True(t, accessGranted) +} + +func TestE2E_http_headers(t *testing.T) { + cmd, stdErr := startExample(t, "http_headers") + defer func() { + require.NoError(t, cmd.Process.Kill()) + }() + + req, err := http.NewRequest("GET", envoyEndpoint, nil) + require.NoError(t, err) + + key := "this-is-key" + value := "this-is-value" + req.Header.Add(key, value) + + r, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer r.Body.Close() + + out := stdErr.String() + fmt.Println(out) + + var keyLogged, valueLogged, responseHeaderLogged bool + for _, line := range strings.Split(out, "\n") { + if strings.Contains(line, key) { + keyLogged = true + } + + if strings.Contains(line, value) { + valueLogged = true + } + + if strings.Contains(line, "server: envoy") { + responseHeaderLogged = true + } + } + + assert.True(t, keyLogged) + assert.True(t, valueLogged) + assert.True(t, responseHeaderLogged) +} + +func TestE2E_metrics(t *testing.T) { + cmd, stdErr := startExample(t, "metrics") + defer func() { + require.NoError(t, cmd.Process.Kill()) + }() + + req, err := http.NewRequest("GET", envoyEndpoint, nil) + require.NoError(t, err) + + count := 10 + for i := 0; i < count; i++ { + r, err := http.DefaultClient.Do(req) + require.NoError(t, err) + r.Body.Close() + } + + fmt.Println(stdErr.String()) + + req, err = http.NewRequest("GET", envoyAdminEndpoint+"/stats", nil) + require.NoError(t, err) + + r, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer r.Body.Close() + + b, err := ioutil.ReadAll(r.Body) + require.NoError(t, err) + assert.True(t, strings.Contains(string(b), fmt.Sprintf("proxy_wasm_go.request_counter: %d", count))) +} + +func TestE2E_shared_data(t *testing.T) { + cmd, stdErr := startExample(t, "shared_data") + defer func() { + require.NoError(t, cmd.Process.Kill()) + }() + + req, err := http.NewRequest("GET", envoyEndpoint, nil) + require.NoError(t, err) + + count := 10 + for i := 0; i < count; i++ { + r, err := http.DefaultClient.Do(req) + require.NoError(t, err) + r.Body.Close() + } + + out := stdErr.String() + fmt.Println(out) + assert.True(t, strings.Contains(out, fmt.Sprintf("shared value: %d", count))) +} + +func TestE2E_shared_queue(t *testing.T) { + cmd, stdErr := startExample(t, "shared_queue") + defer func() { + require.NoError(t, cmd.Process.Kill()) + }() + + req, err := http.NewRequest("GET", envoyEndpoint, nil) + require.NoError(t, err) + + count := 10 + for i := 0; i < count; i++ { + r, err := http.DefaultClient.Do(req) + require.NoError(t, err) + r.Body.Close() + } + + time.Sleep(time.Second * 2) + + out := stdErr.String() + fmt.Println(out) + assert.True(t, strings.Contains(out, "dequed data: hello")) + assert.True(t, strings.Contains(out, "dequed data: world")) + assert.True(t, strings.Contains(out, "dequed data: proxy-wasm")) +} + +func TestE2E_vm_plugin_configuration(t *testing.T) { + cmd, stdErr := startExample(t, "vm_plugin_configuration") + defer func() { + require.NoError(t, cmd.Process.Kill()) + }() + + out := stdErr.String() + fmt.Println(out) + assert.True(t, strings.Contains(out, "name\": \"vm configuration")) + assert.True(t, strings.Contains(out, "name\": \"plugin configuration")) +} diff --git a/examples/helloworld/envoy.yaml b/examples/helloworld/envoy.yaml index 28b1aa6f..40121f92 100644 --- a/examples/helloworld/envoy.yaml +++ b/examples/helloworld/envoy.yaml @@ -4,7 +4,7 @@ static_resources: address: socket_address: address: 127.0.0.1 - port_value: 1234 + port_value: 18000 filter_chains: - filters: - name: envoy.http_connection_manager @@ -26,10 +26,10 @@ static_resources: - name: envoy.filters.http.wasm config: config: - name: "my_plugin" - root_id: "my_root_id" + name: "helloworld" + root_id: "helloworld" vm_config: - vm_id: "my_vm_id" + vm_id: "helloworld" runtime: "envoy.wasm.runtime.v8" code: local: diff --git a/examples/shared_queue/main.go b/examples/shared_queue/main.go index 0ecc7750..351d5ff9 100644 --- a/examples/shared_queue/main.go +++ b/examples/shared_queue/main.go @@ -30,7 +30,7 @@ type queue struct{ proxywasm.DefaultContext } const ( queueName = "proxy_wasm_go.queue" - tickMilliseconds = 1000 + tickMilliseconds = 100 ) var queueID uint32