You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2021/10/27 02:27:35 UTC

[apisix] branch master updated: test(wasm): add fault-injection example (#5337)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 9df6e88  test(wasm): add fault-injection example (#5337)
9df6e88 is described below

commit 9df6e887349e31e9159f99dc7a874dba3798a299
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Wed Oct 27 10:27:27 2021 +0800

    test(wasm): add fault-injection example (#5337)
---
 t/wasm/fault-injection.t       | 186 +++++++++++++++++++++++++++++++++++++++++
 t/wasm/fault-injection/main.go | 108 ++++++++++++++++++++++++
 t/wasm/go.mod                  |   6 +-
 t/wasm/go.sum                  |   7 ++
 4 files changed, 306 insertions(+), 1 deletion(-)

diff --git a/t/wasm/fault-injection.t b/t/wasm/fault-injection.t
new file mode 100644
index 0000000..addeddd
--- /dev/null
+++ b/t/wasm/fault-injection.t
@@ -0,0 +1,186 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+use t::APISIX;
+
+my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
+my $version = eval { `$nginx_binary -V 2>&1` };
+
+if ($version !~ m/\/apisix-nginx-module/) {
+    plan(skip_all => "apisix-nginx-module not installed");
+} else {
+    plan('no_plan');
+}
+
+add_block_preprocessor(sub {
+    my ($block) = @_;
+
+    if ((!defined $block->error_log) && (!defined $block->no_error_log)) {
+        $block->set_value("no_error_log", "[error]");
+    }
+
+    if (!defined $block->request) {
+        $block->set_value("request", "GET /t");
+    }
+
+    my $extra_yaml_config = <<_EOC_;
+wasm:
+    plugins:
+        - name: wasm_fault_injection
+          priority: 7997
+          file: t/wasm/fault-injection/main.go.wasm
+_EOC_
+    $block->set_value("extra_yaml_config", $extra_yaml_config);
+});
+
+run_tests();
+
+__DATA__
+
+=== TEST 1: fault injection
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "uri": "/hello",
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        }
+                    },
+                    "plugins": {
+                        "wasm_fault_injection": {
+                            "conf": "{\"http_status\":401, \"body\":\"HIT\n\"}"
+                        }
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 2: hit
+--- request
+GET /hello
+--- error_code: 401
+--- response_body
+HIT
+
+
+
+=== TEST 3: fault injection, with 0 percentage
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "uri": "/hello",
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        }
+                    },
+                    "plugins": {
+                        "wasm_fault_injection": {
+                            "conf": "{\"http_status\":401, \"percentage\":0}"
+                        }
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 4: hit
+--- request
+GET /hello
+--- response_body
+hello world
+
+
+
+=== TEST 5: fault injection without body
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "uri": "/hello",
+                    "upstream": {
+                        "type": "roundrobin",
+                        "nodes": {
+                            "127.0.0.1:1980": 1
+                        }
+                    },
+                    "plugins": {
+                        "wasm_fault_injection": {
+                            "conf": "{\"http_status\":401}"
+                        }
+                    }
+                }]]
+            )
+
+            if code >= 300 then
+                ngx.status = code
+                ngx.say(body)
+                return
+            end
+
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 6: hit
+--- request
+GET /hello
+--- error_code: 401
+--- response_body_like eval
+qr/<title>401 Authorization Required<\/title>/
diff --git a/t/wasm/fault-injection/main.go b/t/wasm/fault-injection/main.go
new file mode 100644
index 0000000..698bb97
--- /dev/null
+++ b/t/wasm/fault-injection/main.go
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 main
+
+import (
+	"math/rand"
+
+	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm"
+	"github.com/tetratelabs/proxy-wasm-go-sdk/proxywasm/types"
+
+	// tinygo doesn't support encoding/json, see https://github.com/tinygo-org/tinygo/issues/447
+	"github.com/valyala/fastjson"
+)
+
+func main() {
+	proxywasm.SetVMContext(&vmContext{})
+}
+
+type vmContext struct {
+	types.DefaultVMContext
+}
+
+func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
+	return &pluginContext{}
+}
+
+type pluginContext struct {
+	types.DefaultPluginContext
+	Body       []byte
+	HttpStatus uint32
+	Percentage int
+}
+
+func (ctx *pluginContext) OnPluginStart(pluginConfigurationSize int) types.OnPluginStartStatus {
+	data, err := proxywasm.GetPluginConfiguration()
+	if err != nil {
+		proxywasm.LogErrorf("error reading plugin configuration: %v", err)
+		return types.OnPluginStartStatusFailed
+	}
+
+	var p fastjson.Parser
+	v, err := p.ParseBytes(data)
+	if err != nil {
+		proxywasm.LogErrorf("erorr decoding plugin configuration: %v", err)
+		return types.OnPluginStartStatusFailed
+	}
+	ctx.Body = v.GetStringBytes("body")
+	ctx.HttpStatus = uint32(v.GetUint("http_status"))
+	if v.Exists("percentage") {
+		ctx.Percentage = v.GetInt("percentage")
+	} else {
+		ctx.Percentage = 100
+	}
+
+	// schema check
+	if ctx.HttpStatus < 200 {
+		proxywasm.LogError("bad http_status")
+		return types.OnPluginStartStatusFailed
+	}
+	if ctx.Percentage < 0 || ctx.Percentage > 100 {
+		proxywasm.LogError("bad percentage")
+		return types.OnPluginStartStatusFailed
+	}
+
+	return types.OnPluginStartStatusOK
+}
+
+func (ctx *pluginContext) NewHttpContext(contextID uint32) types.HttpContext {
+	return &httpLifecycle{parent: ctx}
+}
+
+type httpLifecycle struct {
+	types.DefaultHttpContext
+	parent *pluginContext
+}
+
+func sampleHit(percentage int) bool {
+	return rand.Intn(100) < percentage
+}
+
+func (ctx *httpLifecycle) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
+	plugin := ctx.parent
+	if !sampleHit(plugin.Percentage) {
+		return types.ActionContinue
+	}
+
+	err := proxywasm.SendHttpResponse(plugin.HttpStatus, nil, plugin.Body, -1)
+	if err != nil {
+		proxywasm.LogErrorf("failed to send local response: %v", err)
+		return types.ActionContinue
+	}
+	return types.ActionPause
+}
diff --git a/t/wasm/go.mod b/t/wasm/go.mod
index 9a875c8..3f9de8a 100644
--- a/t/wasm/go.mod
+++ b/t/wasm/go.mod
@@ -2,5 +2,9 @@ module github.com/api7/wasm-nginx-module
 
 go 1.15
 
-require github.com/tetratelabs/proxy-wasm-go-sdk v0.14.1-0.20210819090022-1e4e69881a31
+require (
+	github.com/tetratelabs/proxy-wasm-go-sdk v0.14.1-0.20210819090022-1e4e69881a31
+	github.com/valyala/fastjson v1.6.3
+)
+
 //replace github.com/tetratelabs/proxy-wasm-go-sdk => ../proxy-wasm-go-sdk
diff --git a/t/wasm/go.sum b/t/wasm/go.sum
index 599f226..97ddff7 100644
--- a/t/wasm/go.sum
+++ b/t/wasm/go.sum
@@ -1,8 +1,15 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/tetratelabs/proxy-wasm-go-sdk v0.14.1-0.20210819090022-1e4e69881a31 h1:V3GXN5nayOdIU3NypbxVegGFCVGm78qOA8Q7wkeudy8=
 github.com/tetratelabs/proxy-wasm-go-sdk v0.14.1-0.20210819090022-1e4e69881a31/go.mod h1:qZ+4i6e2wHlhnhgpH0VG4QFzqd2BEvQbQFU0npt2e2k=
+github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc=
+github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=