Skip to content

Commit

Permalink
WIP: EnvVars e2e test modification
Browse files Browse the repository at this point in the history
  • Loading branch information
dushyanthsc committed Dec 3, 2018
1 parent 09aa4b8 commit 19640f8
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 24 deletions.
74 changes: 68 additions & 6 deletions test/e2e/envvars_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ limitations under the License.
package e2e

import (
"fmt"
"encoding/json"
"net/http"
"testing"

pkgTest "github.com/knative/pkg/test"
"github.com/knative/pkg/test/logging"
"github.com/knative/pkg/test/spoof"
"github.com/knative/serving/pkg/apis/serving/v1alpha1"
serviceresourcenames "github.com/knative/serving/pkg/reconciler/v1alpha1/service/resources/names"
"github.com/knative/serving/test"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -81,18 +83,78 @@ func TestEnvVars(t *testing.T) {
if err != nil {
t.Fatalf("Error fetching Route %s: %v", names.Route, err)
}
domain := route.Status.Domain

envVarsExpectedOutput := fmt.Sprintf("Here are our env vars service:%s - configuration:%s - revision:%s", names.Service, names.Config, names.Revision)
domain := route.Status.Domain + "/envvars/should"

_, err = pkgTest.WaitForEndpointState(
resp, err := pkgTest.WaitForEndpointState(
clients.KubeClient,
logger,
domain,
pkgTest.Retrying(pkgTest.MatchesBody(envVarsExpectedOutput), http.StatusNotFound),
pkgTest.Retrying(verifyUpStatus, http.StatusNotFound),
"EnvVarsServesText",
test.ServingFlags.ResolvableDomain)
if err != nil {
t.Fatalf("The endpoint for Route %s at domain %s didn't serve the expected text \"%s\": %v", names.Route, domain, envVarsExpectedOutput, err)
t.Fatalf("Failed before reaching desired state : %v", err)
}

expectedOutputs := map[string]string{
"K_SERVICE" : names.Service,
"K_CONFIGURATION" : names.Config,
"K_REVISION" : names.Revision,
}
// We are failing even for "SHOULD".
if err = verifyResponse(resp, "SHOULD", expectedOutputs); err != nil {
t.Error(err)
}

domain = route.Status.Domain + "/envvars/must"

resp, err = pkgTest.WaitForEndpointState(
clients.KubeClient,
logger,
domain,
pkgTest.Retrying(verifyUpStatus, http.StatusNotFound),
"EnvVarsServesText",
test.ServingFlags.ResolvableDomain)
if err != nil {
t.Fatalf("Failed before reaching desired state : %v", err)
}

expectedOutputs = map[string]string{
"PORT" : "8080",
}
if err = verifyResponse(resp, "MUST", expectedOutputs); err != nil {
t.Error(err)
}
}

func verifyUpStatus(resp *spoof.Response) (done bool, err error) {
if resp.StatusCode == http.StatusOK {
return true, nil
}

return true, errors.New(string(resp.Body))
}

func verifyResponse(resp *spoof.Response, constraint string, expectedOutputs map[string]string) error {
var respMap map[string]string
if jsonErr := json.Unmarshal(resp.Body, &respMap); jsonErr != nil {
return errors.Errorf("Json Un-marshalling error : %v", jsonErr)
}

if len(expectedOutputs) != len(respMap) {
return errors.Errorf("Expected number of %s environment variables don't match. Expected : %d, Got : %d", constraint, len(expectedOutputs), len(respMap))
}

for key, value := range expectedOutputs {
if v, ok := respMap[key]; ok {
if value != v {
return errors.Errorf("%s environment variable : %s didn't match. Expected : %s Got : %s", constraint, key, value, v)
}
} else {
return errors.Errorf("%s environment variable : %s not found", constraint, key)
}
}

return nil
}
8 changes: 5 additions & 3 deletions test/test_images/envvars/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# Helloworld test image
# Envvars test image

This directory contains the test image used in the envvars e2e test.

The image contains a simple Go webserver, `envvars.go`, that will, by default, listen on port `8080` and expose a service at `/`.
The image contains a simple Go webserver, `envvars.go`, that will, by default, listen on port `8080` and expose call to paths /envvars/must and /envvars/should `.

When called, the server emits a message containing the values of the environment variables for knative service, configuraiton and revision.
'must' and 'should' refer to the keywords "MUST" and "SHOULD" used in the Knative [run-time contract](/docs/runtime-contract.md) and provides environment variables that "MUST" and "SHOULD" be set by a Knative implementations

When called, the server emits JSON response containing the values of the environment variables for the corresponding path

## Building

Expand Down
43 changes: 35 additions & 8 deletions test/test_images/envvars/envvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package main

import (
"encoding/json"
"flag"
"fmt"
"log"
Expand All @@ -26,17 +27,43 @@ import (
"github.com/knative/serving/test"
)

func handler(w http.ResponseWriter, r *http.Request) {
log.Print("Env vars test app received a request.")
svc := os.Getenv("K_SERVICE")
cfg := os.Getenv("K_CONFIGURATION")
rev := os.Getenv("K_REVISION")
fmt.Fprintf(w, "Here are our env vars service:%s - configuration:%s - revision:%s", svc, cfg, rev)
//Environment variables that "SHOULD" be set by knative implementation
var shouldSet = []string{ "K_SERVICE", "K_CONFIGURATION", "K_REVISION"}

//Enviroment variables that "MUST" be set by knative implementation
var mustSet = []string{"PORT"}

func fetchEnvVariables(envVars []string) map[string]string {
m := make(map[string]string)
for _, envVar := range envVars {
m[envVar] = os.Getenv(envVar)
}

return m
}

func handlRequest(w http.ResponseWriter, envVarsSet []string) {
envVars := fetchEnvVariables(envVarsSet)
resp, err := json.Marshal(envVars)
if err != nil {
fmt.Fprintf(w, fmt.Sprintf("error building response : %v", err))
}
fmt.Fprintf(w, string(resp))
}

func shouldSetHandler(w http.ResponseWriter, r *http.Request) {
handlRequest(w, shouldSet)
}

func mustSetHandler(w http.ResponseWriter, r *http.Request) {
handlRequest(w, mustSet)
}

func main() {
flag.Parse()
log.Print("Env vars test app started.")

test.ListenAndServeGracefully(":8080", handler)
test.ListenAndServeGracefullyWithPattern(":8080", map[string]func(w http.ResponseWriter, r *http.Request){
"/envvars/should": shouldSetHandler,
"/envvars/must": mustSetHandler,
})
}
26 changes: 19 additions & 7 deletions test/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ 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.
*/
// util.go provides shared utilities methods across knative serving test

package test

import (
Expand All @@ -25,6 +25,8 @@ import (
"github.com/knative/pkg/test/logging"
)

// util.go provides shared utilities methods across knative serving test

// LogResourceObject logs the resource object with the resource name and value
func LogResourceObject(logger *logging.BaseLogger, value ResourceObjects) {
// Log the route object
Expand All @@ -40,18 +42,28 @@ func ImagePath(name string) string {
return fmt.Sprintf("%s/%s:%s", ServingFlags.DockerRepo, name, ServingFlags.Tag)
}

// ListenAndServeGracefully creates an HTTP server, listens on the defined address
// and handles incoming requests to "/" with the given function.
// It blocks until SIGTERM is received and the underlying server has shutdown gracefully.
// ListenAndServeGracefully calls into ListenAndServeGracefullyWithPattern
// by passing handler to handle requests for "/"
func ListenAndServeGracefully(addr string, handler func(w http.ResponseWriter, r *http.Request)) {
ListenAndServeGracefullyWithPattern(addr, map[string]func(w http.ResponseWriter, r *http.Request){
"/" : handler,
})
}

// ListenAndServeGracefullyWithPattern creates an HTTP server, listens on the defined address
// and handles incoming requests specified on pattern(path) with the given handlers.
// It blocks until SIGTERM is received and the underlying server has shutdown gracefully.
func ListenAndServeGracefullyWithPattern(addr string, handlers map[string]func(w http.ResponseWriter, r *http.Request)) {
m := http.NewServeMux()
m.HandleFunc("/", handler)
server := http.Server{Addr: addr, Handler: m}
for pattern, handler := range handlers {
m.HandleFunc(pattern, handler)
}

server := http.Server{Addr: addr, Handler: m}
go server.ListenAndServe()

sigTermChan := make(chan os.Signal)
signal.Notify(sigTermChan, syscall.SIGTERM)
<-sigTermChan
server.Shutdown(context.Background())
}
}

0 comments on commit 19640f8

Please sign in to comment.