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/06/22 07:38:06 UTC

[apisix-go-plugin-runner] branch master updated: feat: concurrent safe way to RegisterPlugin (#10)

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-go-plugin-runner.git


The following commit(s) were added to refs/heads/master by this push:
     new 6e33fa6  feat: concurrent safe way to RegisterPlugin (#10)
6e33fa6 is described below

commit 6e33fa657de759343f0a257c8de74fe635bd7da5
Author: tyltr <31...@users.noreply.github.com>
AuthorDate: Tue Jun 22 15:37:59 2021 +0800

    feat: concurrent safe way to RegisterPlugin (#10)
---
 internal/plugin/plugin.go      |  16 +++-
 internal/plugin/plugin_test.go | 192 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 197 insertions(+), 11 deletions(-)

diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go
index 7fa6136..a33c61a 100644
--- a/internal/plugin/plugin.go
+++ b/internal/plugin/plugin.go
@@ -18,6 +18,7 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
+	"sync"
 
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
 	flatbuffers "github.com/google/flatbuffers/go"
@@ -36,6 +37,11 @@ type pluginOpts struct {
 	Filter    FilterFunc
 }
 
+type pluginRegistries struct {
+	sync.Mutex
+	opts map[string]*pluginOpts
+}
+
 type ErrPluginRegistered struct {
 	name string
 }
@@ -45,7 +51,7 @@ func (err ErrPluginRegistered) Error() string {
 }
 
 var (
-	pluginRegistry = map[string]*pluginOpts{}
+	pluginRegistry = pluginRegistries{opts: map[string]*pluginOpts{}}
 
 	ErrMissingName            = errors.New("missing name")
 	ErrMissingParseConfMethod = errors.New("missing ParseConf method")
@@ -67,15 +73,17 @@ func RegisterPlugin(name string, pc ParseConfFunc, sv FilterFunc) error {
 		ParseConf: pc,
 		Filter:    sv,
 	}
-	if _, found := pluginRegistry[name]; found {
+	pluginRegistry.Lock()
+	defer pluginRegistry.Unlock()
+	if _, found := pluginRegistry.opts[name]; found {
 		return ErrPluginRegistered{name}
 	}
-	pluginRegistry[name] = opt
+	pluginRegistry.opts[name] = opt
 	return nil
 }
 
 func findPlugin(name string) *pluginOpts {
-	if opt, found := pluginRegistry[name]; found {
+	if opt, found := pluginRegistry.opts[name]; found {
 		return opt
 	}
 	return nil
diff --git a/internal/plugin/plugin_test.go b/internal/plugin/plugin_test.go
index 65c9f9c..ecaad30 100644
--- a/internal/plugin/plugin_test.go
+++ b/internal/plugin/plugin_test.go
@@ -20,12 +20,12 @@ import (
 	"testing"
 	"time"
 
+	inHTTP "github.com/apache/apisix-go-plugin-runner/internal/http"
+	pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
+
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
 	flatbuffers "github.com/google/flatbuffers/go"
 	"github.com/stretchr/testify/assert"
-
-	inHTTP "github.com/apache/apisix-go-plugin-runner/internal/http"
-	pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
 )
 
 var (
@@ -94,10 +94,188 @@ func TestHTTPReqCall_FailedToParseConf(t *testing.T) {
 }
 
 func TestRegisterPlugin(t *testing.T) {
-	assert.Equal(t, ErrMissingParseConfMethod,
-		RegisterPlugin("bad_conf", nil, emptyFilter))
-	assert.Equal(t, ErrMissingFilterMethod,
-		RegisterPlugin("bad_conf", emptyParseConf, nil))
+	type args struct {
+		name string
+		pc   ParseConfFunc
+		sv   FilterFunc
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr error
+	}{
+		{
+			name: "test_MissingParseConfMethod",
+			args: args{
+				name: "1",
+				pc:   nil,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrMissingParseConfMethod,
+		},
+		{
+			name: "test_MissingFilterMethod",
+			args: args{
+				name: "1",
+				pc:   emptyParseConf,
+				sv:   nil,
+			},
+			wantErr: ErrMissingFilterMethod,
+		},
+		{
+			name: "test_MissingParseConfMethod&FilterMethod",
+			args: args{
+				name: "1",
+				pc:   nil,
+				sv:   nil,
+			},
+			wantErr: ErrMissingParseConfMethod,
+		},
+		{
+			name: "test_MissingName&ParseConfMethod",
+			args: args{
+				name: "",
+				pc:   nil,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrMissingName,
+		},
+		{
+			name: "test_MissingName&FilterMethod",
+			args: args{
+				name: "",
+				pc:   emptyParseConf,
+				sv:   nil,
+			},
+			wantErr: ErrMissingName,
+		},
+		{
+			name: "test_MissingAll",
+			args: args{
+				name: "",
+				pc:   nil,
+				sv:   nil,
+			},
+			wantErr: ErrMissingName,
+		},
+		{
+			name: "test_plugin1",
+			args: args{
+				name: "plugin1",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: nil,
+		},
+		{
+			name: "test_plugin1_again",
+			args: args{
+				name: "plugin1",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrPluginRegistered{"plugin1"},
+		},
+		{
+			name: "test_plugin2",
+			args: args{
+				name: "plugin2111%#@#",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: nil,
+		},
+		{
+			name: "test_plugin3",
+			args: args{
+				name: "plugin311*%#@#",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: nil,
+		},
+		{
+			name: "test_plugin3_again",
+			args: args{
+				name: "plugin311*%#@#",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrPluginRegistered{"plugin311*%#@#"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := RegisterPlugin(tt.args.name, tt.args.pc, tt.args.sv); !assert.Equal(t, tt.wantErr, err) {
+				t.Errorf("RegisterPlugin() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
+func TestRegisterPluginConcurrent(t *testing.T) {
+	RegisterPlugin("test_concurrent-1", emptyParseConf, emptyFilter)
+	RegisterPlugin("test_concurrent-2", emptyParseConf, emptyFilter)
+	type args struct {
+		name string
+		pc   ParseConfFunc
+		sv   FilterFunc
+	}
+	type test struct {
+		name    string
+		args    args
+		wantErr error
+	}
+	tests := []test{
+		{
+			name: "test_concurrent-1",
+			args: args{
+				name: "test_concurrent-1",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrPluginRegistered{"test_concurrent-1"},
+		},
+		{
+			name: "test_concurrent-2#01",
+			args: args{
+				name: "test_concurrent-2",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrPluginRegistered{"test_concurrent-2"},
+		},
+		{
+			name: "test_concurrent-2#02",
+			args: args{
+				name: "test_concurrent-2",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrPluginRegistered{"test_concurrent-2"},
+		},
+		{
+			name: "test_concurrent-2#03",
+			args: args{
+				name: "test_concurrent-2",
+				pc:   emptyParseConf,
+				sv:   emptyFilter,
+			},
+			wantErr: ErrPluginRegistered{"test_concurrent-2"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			for i := 0; i < 3; i++ {
+				go func(tt test) {
+					if err := RegisterPlugin(tt.args.name, tt.args.pc, tt.args.sv); !assert.Equal(t, tt.wantErr, err) {
+						t.Errorf("RegisterPlugin() error = %v, wantErr %v", err, tt.wantErr)
+					}
+				}(tt)
+			}
+
+		})
+	}
 }
 
 func TestFilter(t *testing.T) {