diff --git a/src/envoy/mixer/integration_test/BUILD b/src/envoy/mixer/integration_test/BUILD index 57ef06b2ee6..35a649032b2 100644 --- a/src/envoy/mixer/integration_test/BUILD +++ b/src/envoy/mixer/integration_test/BUILD @@ -63,6 +63,9 @@ go_test_suite( "check_report_disable_test.go", "disable_check_cache_test.go", "failed_request_test.go", + "fault_inject_test.go", + "internal_fail_close_test.go", + "internal_fail_open_test.go", "quota_cache_test.go", "quota_test.go", "report_batch_test.go", diff --git a/src/envoy/mixer/integration_test/check_fail_close_test.go b/src/envoy/mixer/integration_test/check_fail_close_test.go index 7967ed314fb..24e11505b1f 100644 --- a/src/envoy/mixer/integration_test/check_fail_close_test.go +++ b/src/envoy/mixer/integration_test/check_fail_close_test.go @@ -21,9 +21,9 @@ import ( func TestFailClose(t *testing.T) { s := &TestSetup{ - t: t, - conf: basicConfig+","+networkFailClose, - no_mixer: true, + t: t, + conf: basicConfig + "," + networkFailClose, + noMixer: true, } if err := s.SetUp(); err != nil { t.Fatalf("Failed to setup test: %v", err) @@ -32,7 +32,7 @@ func TestFailClose(t *testing.T) { url := fmt.Sprintf("http://localhost:%d/echo", ClientProxyPort) - tag := "Fail-Open" + tag := "Fail-Close" // Use fail close policy. code, _, err := HTTPGet(url) if err != nil { diff --git a/src/envoy/mixer/integration_test/check_fail_open_test.go b/src/envoy/mixer/integration_test/check_fail_open_test.go index f1026e44544..71c79686dd4 100644 --- a/src/envoy/mixer/integration_test/check_fail_open_test.go +++ b/src/envoy/mixer/integration_test/check_fail_open_test.go @@ -21,9 +21,9 @@ import ( func TestFailOpen(t *testing.T) { s := &TestSetup{ - t: t, - conf: basicConfig, - no_mixer: true, + t: t, + conf: basicConfig, + noMixer: true, } if err := s.SetUp(); err != nil { t.Fatalf("Failed to setup test: %v", err) diff --git a/src/envoy/mixer/integration_test/check_report_disable_test.go b/src/envoy/mixer/integration_test/check_report_disable_test.go index c0e54f53a29..0f0fffb44dc 100644 --- a/src/envoy/mixer/integration_test/check_report_disable_test.go +++ b/src/envoy/mixer/integration_test/check_report_disable_test.go @@ -54,7 +54,7 @@ func TestCheckReportDisable(t *testing.T) { var err error // stop and start a new envoy config s.envoy.Stop() - s.envoy, err = NewEnvoy(s.conf, checkOnlyFlags, s.stress) + s.envoy, err = NewEnvoy(s.conf, checkOnlyFlags, s.stress, s.faultInject) if err != nil { t.Errorf("unable to re-create Envoy %v", err) } else { @@ -74,7 +74,7 @@ func TestCheckReportDisable(t *testing.T) { // stop and start a new envoy config s.envoy.Stop() - s.envoy, err = NewEnvoy(s.conf, reportOnlyFlags, s.stress) + s.envoy, err = NewEnvoy(s.conf, reportOnlyFlags, s.stress, s.faultInject) if err != nil { t.Errorf("unable to re-create Envoy %v", err) } else { diff --git a/src/envoy/mixer/integration_test/envoy.go b/src/envoy/mixer/integration_test/envoy.go index 6cfbb61ef01..c7c95e83039 100644 --- a/src/envoy/mixer/integration_test/envoy.go +++ b/src/envoy/mixer/integration_test/envoy.go @@ -58,13 +58,13 @@ func Run(name string, args ...string) (s string, err error) { return } -func NewEnvoy(conf, flags string, stress bool) (*Envoy, error) { +func NewEnvoy(conf, flags string, stress, faultInject bool) (*Envoy, error) { bin_path := getTestBinRootPath() + "/src/envoy/mixer/envoy" log.Printf("Envoy binary: %v\n", bin_path) conf_path := "/tmp/envoy.conf" log.Printf("Envoy config: in %v\n%v\n", conf_path, conf) - if err := CreateEnvoyConf(conf_path, conf, flags, stress); err != nil { + if err := CreateEnvoyConf(conf_path, conf, flags, stress, faultInject); err != nil { return nil, err } diff --git a/src/envoy/mixer/integration_test/envoy_conf.go b/src/envoy/mixer/integration_test/envoy_conf.go index 9fc2563b7f1..d02888ad166 100644 --- a/src/envoy/mixer/integration_test/envoy_conf.go +++ b/src/envoy/mixer/integration_test/envoy_conf.go @@ -43,6 +43,7 @@ type ConfParam struct { ServerConfig string AccessLog string MixerRouteFlags string + FaultFilter string } // A basic config @@ -103,6 +104,19 @@ const defaultMixerRouteFlags = ` "mixer_control": "on", ` +const allAbortFaultFilter = ` + { + "type": "decoder", + "name": "fault", + "config": { + "abort": { + "abort_percent": 100, + "http_status": 503 + } + } + }, +` + // The envoy config template const envoyConfTempl = ` { @@ -152,6 +166,7 @@ const envoyConfTempl = ` {{.ServerConfig}} } }, +{{.FaultFilter}} { "type": "decoder", "name": "router", @@ -320,7 +335,7 @@ func getConf() ConfParam { } } -func CreateEnvoyConf(path, conf, flags string, stress bool) error { +func CreateEnvoyConf(path, conf, flags string, stress, faultInject bool) error { c := getConf() c.ServerConfig = conf c.MixerRouteFlags = defaultMixerRouteFlags @@ -330,5 +345,8 @@ func CreateEnvoyConf(path, conf, flags string, stress bool) error { if stress { c.AccessLog = "/dev/null" } + if faultInject { + c.FaultFilter = allAbortFaultFilter + } return c.write(path) } diff --git a/src/envoy/mixer/integration_test/fault_inject_test.go b/src/envoy/mixer/integration_test/fault_inject_test.go new file mode 100644 index 00000000000..54aac3f83b2 --- /dev/null +++ b/src/envoy/mixer/integration_test/fault_inject_test.go @@ -0,0 +1,125 @@ +// Copyright 2017 Istio Authors. All Rights Reserved. +// +// 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 test + +import ( + "fmt" + "testing" +) + +// Check attributes from a fault injected GET request +const checkAttributes = ` +{ + "context.protocol": "http", + "mesh1.ip": "[1 1 1 1]", + "mesh2.ip": "[0 0 0 0 0 0 0 0 0 0 255 255 204 152 189 116]", + "mesh3.ip": "[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 8]", + "request.host": "localhost:27070", + "request.path": "/echo", + "request.time": "*", + "request.useragent": "Go-http-client/1.1", + "request.method": "GET", + "request.scheme": "http", + "source.uid": "POD11", + "source.namespace": "XYZ11", + "source.name": "source-name", + "source.user": "source-user", + "source.ip": "*", + "source.port": "*", + "target.name": "target-name", + "target.user": "target-user", + "target.uid": "POD222", + "target.namespace": "XYZ222", + "request.headers": { + ":method": "GET", + ":path": "/echo", + ":authority": "localhost:27070", + "x-forwarded-proto": "http", + "x-istio-attributes": "-", + "x-request-id": "*" + } +} +` + +// Report attributes from a fault inject GET request +const reportAttributes = ` +{ + "context.protocol": "http", + "mesh1.ip": "[1 1 1 1]", + "mesh2.ip": "[0 0 0 0 0 0 0 0 0 0 255 255 204 152 189 116]", + "mesh3.ip": "[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 8]", + "request.host": "localhost:27070", + "request.path": "/echo", + "request.time": "*", + "request.useragent": "Go-http-client/1.1", + "request.method": "GET", + "request.scheme": "http", + "source.uid": "POD11", + "source.namespace": "XYZ11", + "source.name": "source-name", + "source.user": "source-user", + "source.ip": "*", + "source.port": "*", + "target.name": "target-name", + "target.user": "target-user", + "target.uid": "POD222", + "target.namespace": "XYZ222", + "request.headers": { + ":method": "GET", + ":path": "/echo", + ":authority": "localhost:27070", + "x-forwarded-proto": "http", + "x-istio-attributes": "-", + "x-request-id": "*" + }, + "request.size": 0, + "response.time": "*", + "response.size": 18, + "response.duration": "*", + "response.code": 503, + "response.headers": { + "date": "*", + "content-type": "text/plain", + "content-length": "18", + ":status": "503", + "server": "envoy" + } +} +` + +func TestFaultInject(t *testing.T) { + s := &TestSetup{ + t: t, + conf: basicConfig, + faultInject: true, + } + if err := s.SetUp(); err != nil { + t.Fatalf("Failed to setup test: %v", err) + } + defer s.TearDown() + + url := fmt.Sprintf("http://localhost:%d/echo", ClientProxyPort) + + tag := "FaultInject" + code, _, err := HTTPGet(url) + if err != nil { + t.Errorf("Failed in request %s: %v", tag, err) + } + if code != 503 { + t.Errorf("Status code 503 is expected, got %d.", code) + } + s.VerifyCheck(tag, checkAttributes) + s.VerifyReport(tag, reportAttributes) +} diff --git a/src/envoy/mixer/integration_test/internal_fail_close_test.go b/src/envoy/mixer/integration_test/internal_fail_close_test.go new file mode 100644 index 00000000000..798070c5d0c --- /dev/null +++ b/src/envoy/mixer/integration_test/internal_fail_close_test.go @@ -0,0 +1,49 @@ +// Copyright 2017 Istio Authors. All Rights Reserved. +// +// 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 test + +import ( + "fmt" + "testing" + + rpc "github.com/googleapis/googleapis/google/rpc" +) + +func TestFailCloseForMixerInternal(t *testing.T) { + s := &TestSetup{ + t: t, + conf: basicConfig + "," + networkFailClose, + } + if err := s.SetUp(); err != nil { + t.Fatalf("Failed to setup test: %v", err) + } + defer s.TearDown() + + url := fmt.Sprintf("http://localhost:%d/echo", ClientProxyPort) + + tag := "Fail-Close" + // Mixer to return INTERNAL error. + s.mixer.check.r_status = rpc.Status{ + Code: int32(rpc.INTERNAL), + } + code, _, err := HTTPGet(url) + if err != nil { + t.Errorf("Failed in request %s: %v", tag, err) + } + // Since fail_close policy, expect 500. + if code != 500 { + t.Errorf("Status code 500 is expected, got %d.", code) + } +} diff --git a/src/envoy/mixer/integration_test/internal_fail_open_test.go b/src/envoy/mixer/integration_test/internal_fail_open_test.go new file mode 100644 index 00000000000..bd6facce3ce --- /dev/null +++ b/src/envoy/mixer/integration_test/internal_fail_open_test.go @@ -0,0 +1,49 @@ +// Copyright 2017 Istio Authors. All Rights Reserved. +// +// 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 test + +import ( + "fmt" + "testing" + + rpc "github.com/googleapis/googleapis/google/rpc" +) + +func TestFailOpenForMixerInternal(t *testing.T) { + s := &TestSetup{ + t: t, + conf: basicConfig, + } + if err := s.SetUp(); err != nil { + t.Fatalf("Failed to setup test: %v", err) + } + defer s.TearDown() + + url := fmt.Sprintf("http://localhost:%d/echo", ClientProxyPort) + + tag := "Fail-Open" + // Mixer to return INTERNAL error. + s.mixer.check.r_status = rpc.Status{ + Code: int32(rpc.INTERNAL), + } + code, _, err := HTTPGet(url) + if err != nil { + t.Errorf("Failed in request %s: %v", tag, err) + } + // Since fail_open policy by default, expect 200. + if code != 200 { + t.Errorf("Status code 200 is expected, got %d.", code) + } +} diff --git a/src/envoy/mixer/integration_test/setup.go b/src/envoy/mixer/integration_test/setup.go index 4cf1f54a06a..f98513be4b4 100644 --- a/src/envoy/mixer/integration_test/setup.go +++ b/src/envoy/mixer/integration_test/setup.go @@ -20,10 +20,11 @@ import ( ) type TestSetup struct { - t *testing.T - conf string - stress bool - no_mixer bool + t *testing.T + conf string + stress bool + faultInject bool + noMixer bool envoy *Envoy mixer *MixerServer @@ -32,14 +33,14 @@ type TestSetup struct { func (s *TestSetup) SetUp() error { var err error - s.envoy, err = NewEnvoy(s.conf, "", s.stress) + s.envoy, err = NewEnvoy(s.conf, "", s.stress, s.faultInject) if err != nil { log.Printf("unable to create Envoy %v", err) } else { s.envoy.Start() } - if !s.no_mixer { + if !s.noMixer { s.mixer, err = NewMixerServer(MixerPort, s.stress) if err != nil { log.Printf("unable to create mixer server %v", err)