diff --git a/README.md b/README.md index 6ac7bb187d..27042f0221 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,16 @@ Layotto is an application runtime developed using Golang, which provides various distributed capabilities for applications, such as state management, configuration management, and event pub/sub capabilities to simplify application development. -Layotto uses the open source [MOSN](https://github.com/mosn/mosn) as the base, in addition to providing distributed capabilities, it also provides Service Mesh's ability to control traffic. +Layotto is built on the open source data plane [MOSN](https://github.com/mosn/mosn) .In addition to providing distributed building blocks, Layotto can also serve as the data plane of Service Mesh and has the ability to control traffic. ## Motivation -Layotto aims to combine Runtime with Service Mesh into one sidecar. No matter which product you are using as the Service Mesh data plane (e.g. MOSN,Envoy or any other product), you can always attach Layotto to it and add Multi-Runtime capabilities without adding new sidecars. +Layotto aims to combine [Multi-Runtime](https://www.infoq.com/articles/multi-runtime-microservice-architecture/) with Service Mesh into one sidecar. No matter which product you are using as the Service Mesh data plane (e.g. MOSN,Envoy or any other product), you can always attach Layotto to it and add Multi-Runtime capabilities without adding new sidecars. For example, by adding Runtime capabilities to MOSN, a Layotto process can both [serve as the data plane of istio](https://mosn.io/layotto/#/en/start/istio/start.md) and provide various Runtime APIs (such as Configuration API, Pub/Sub API, etc.) +In addition, we were surprised to find that a sidecar can do much more than that. We are trying to make Layotto even the runtime container of FaaS (Function as a service) and [reloadable sdk](https://github.com/mosn/layotto/issues/166) with the magic power of [WebAssembly](https://en.wikipedia.org/wiki/WebAssembly) . + ## Features - Service Communication diff --git a/docs/en/README.md b/docs/en/README.md index f790f1adca..df23e969a8 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -7,14 +7,14 @@ Layotto is an application runtime developed using Golang, which provides various distributed capabilities for applications, such as state management, configuration management, and event pub/sub capabilities to simplify application development. -Layotto uses the open source [MOSN](https://github.com/mosn/mosn) as the base, in addition to providing distributed capabilities, it also provides Service Mesh's ability to control traffic. +Layotto is built on the open source data plane [MOSN](https://github.com/mosn/mosn) .In addition to providing distributed building blocks, Layotto can also serve as the data plane of Service Mesh and has the ability to control traffic. ## Motivation +Layotto aims to combine [Multi-Runtime](https://www.infoq.com/articles/multi-runtime-microservice-architecture/) with Service Mesh into one sidecar. No matter which product you are using as the Service Mesh data plane (e.g. MOSN,Envoy or any other product), you can always attach Layotto to it and add Multi-Runtime capabilities without adding new sidecars. -Layotto aims to combine Runtime with Service Mesh into one sidecar. No matter which product you are using as the Service Mesh data plane (e.g. Mosn,Envoy or any other -product), you can always attach Layotto to it and add Multi-Runtime capabilities without adding new sidecars. +For example, by adding Runtime capabilities to MOSN, a Layotto process can both [serve as the data plane of istio](https://mosn.io/layotto/#/en/start/istio/start.md) and provide various Runtime APIs (such as Configuration API, Pub/Sub API, etc.) -For example, by adding Runtime capabilities to MOSN, a Layotto process can both [serve as the data plane of istio](en/start/istio/start) and provide various Runtime APIs (such as Configuration API, Pub/Sub API, etc.) +In addition, we were surprised to find that a sidecar can do much more than that. We are trying to make Layotto even the runtime container of FaaS (Function as a service) and [reloadable sdk](https://github.com/mosn/layotto/issues/166) with the magic power of [WebAssembly](https://en.wikipedia.org/wiki/WebAssembly) . ## Features diff --git a/docs/zh/README.md b/docs/zh/README.md index dbf983bbfe..3b2331589f 100644 --- a/docs/zh/README.md +++ b/docs/zh/README.md @@ -11,11 +11,13 @@ Layotto 以开源的 [MOSN](https://github.com/mosn/mosn) 为底座,在提供 ## 诞生背景 -Layotto希望可以把Runtime跟Service Mesh两者的能力结合起来,无论你是使用MOSN还是Envoy或者其他产品作为Service Mesh的数据面,都可以在不增加新的sidecar的前提下,使用Layotto为这些数据面追加Runtime的能力。 +Layotto希望可以把 [Multi-Runtime](https://www.infoq.com/articles/multi-runtime-microservice-architecture/) 跟Service Mesh两者的能力结合起来,无论你是使用MOSN还是Envoy或者其他产品作为Service Mesh的数据面,都可以在不增加新的sidecar的前提下,使用Layotto为这些数据面追加Runtime的能力。 例如,通过为MOSN添加Runtime能力,一个Layotto进程可以[既作为istio的数据面](zh/start/istio/start.md) 又提供各种Runtime API(例如Configuration API,Pub/Sub API等) -如果您对诞生背景感兴趣,可以看下[这篇演讲](https://mosn.io/layotto/#/zh/blog/mosn-subproject-layotto-opening-a-new-chapter-in-service-grid-application-runtime/index) +此外,随着探索实践,我们发现sidecar能做的事情远不止于此。 通过引入[WebAssembly](https://en.wikipedia.org/wiki/WebAssembly) ,我们正在尝试将Layotto做成 FaaS (Function as a service) 和 [reloadable sdk](https://github.com/mosn/layotto/issues/166) 的运行时容器 。 + +如果您对诞生背景感兴趣,可以看下[这篇演讲](https://mosn.io/layotto/#/zh/blog/mosn-subproject-layotto-opening-a-new-chapter-in-service-grid-application-runtime/index) 。 ## 功能 diff --git a/go.mod b/go.mod index fdf26b8a10..8077a7e237 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.14 require ( github.com/dapr/components-contrib v1.2.0 github.com/dapr/kit v0.0.1 + github.com/fsnotify/fsnotify v1.4.9 github.com/gammazero/workerpool v1.1.2 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 @@ -16,6 +17,7 @@ require ( github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/urfave/cli v1.22.1 github.com/valyala/fasthttp v1.26.0 + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect google.golang.org/grpc v1.39.0 google.golang.org/grpc/examples v0.0.0-20210526223527-2de42fcbbce3 // indirect google.golang.org/protobuf v1.27.1 diff --git a/go.sum b/go.sum index ee2c52a88a..1a284a1f7f 100644 --- a/go.sum +++ b/go.sum @@ -475,7 +475,6 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= @@ -1456,8 +1455,9 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/grpc/api.go b/pkg/grpc/api.go index ee4d9f1cfb..37b51a72df 100644 --- a/pkg/grpc/api.go +++ b/pkg/grpc/api.go @@ -26,6 +26,7 @@ import ( "github.com/dapr/components-contrib/state" "github.com/gammazero/workerpool" "github.com/golang/protobuf/ptypes/empty" + "mosn.io/layotto/pkg/converter" runtime_lock "mosn.io/layotto/pkg/runtime/lock" runtime_sequencer "mosn.io/layotto/pkg/runtime/sequencer" @@ -41,6 +42,7 @@ import ( "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/protobuf/types/known/emptypb" + "mosn.io/layotto/components/configstores" "mosn.io/layotto/components/hello" "mosn.io/layotto/components/lock" @@ -764,7 +766,7 @@ func (a *api) Unlock(ctx context.Context, req *runtimev1pb.UnlockRequest) (*runt return newInternalErrorUnlockResponse(), err } if req.LockOwner == "" { - err := status.Errorf(codes.InvalidArgument, messages.ErrResourceIdEmpty, req.StoreName) + err := status.Errorf(codes.InvalidArgument, messages.ErrLockOwnerEmpty, req.StoreName) return newInternalErrorUnlockResponse(), err } // 2. find store component diff --git a/pkg/grpc/api_test.go b/pkg/grpc/api_test.go index 8aa30ea25a..6ed968c44e 100644 --- a/pkg/grpc/api_test.go +++ b/pkg/grpc/api_test.go @@ -20,16 +20,31 @@ import ( "context" "errors" "fmt" + "net" + "testing" + "time" + + "github.com/dapr/components-contrib/pubsub" + "github.com/dapr/components-contrib/state" "github.com/golang/mock/gomock" + "github.com/golang/protobuf/ptypes/any" "github.com/stretchr/testify/assert" + tmock "github.com/stretchr/testify/mock" "google.golang.org/grpc" + "mosn.io/layotto/components/configstores" "mosn.io/layotto/components/hello" + "mosn.io/layotto/components/lock" + "mosn.io/layotto/components/rpc" + mosninvoker "mosn.io/layotto/components/rpc/invoker/mosn" + "mosn.io/layotto/components/sequencer" "mosn.io/layotto/pkg/mock" + mock_invoker "mosn.io/layotto/pkg/mock/components/invoker" + mock_lock "mosn.io/layotto/pkg/mock/components/lock" + mock_pubsub "mosn.io/layotto/pkg/mock/components/pubsub" + mock_sequencer "mosn.io/layotto/pkg/mock/components/sequencer" + "mosn.io/layotto/pkg/mock/components/state" runtimev1pb "mosn.io/layotto/spec/proto/runtime/v1" - "net" - "testing" - "time" ) const ( @@ -133,7 +148,7 @@ func TestGetConfiguration(t *testing.T) { mockConfigStore := mock.NewMockStore(ctrl) api := NewAPI("", nil, map[string]configstores.Store{"mock": mockConfigStore}, nil, nil, nil, nil, nil) mockConfigStore.EXPECT().Get(gomock.Any(), gomock.Any()).Return([]*configstores.ConfigurationItem{ - &configstores.ConfigurationItem{Key: "sofa", Content: "sofa1"}, + {Key: "sofa", Content: "sofa1"}, }, nil).Times(1) res, err := api.GetConfiguration(context.Background(), &runtimev1pb.GetConfigurationRequest{StoreName: "mock", AppId: "mosn", Keys: []string{"sofa"}}) assert.Nil(t, err) @@ -145,19 +160,74 @@ func TestGetConfiguration(t *testing.T) { } func TestSaveConfiguration(t *testing.T) { - ctrl := gomock.NewController(t) - mockConfigStore := mock.NewMockStore(ctrl) - api := NewAPI("", nil, map[string]configstores.Store{"mock": mockConfigStore}, nil, nil, nil, nil, nil) - _, err := api.SaveConfiguration(context.Background(), &runtimev1pb.SaveConfigurationRequest{StoreName: "etcd"}) - assert.Equal(t, err.Error(), "configure store [etcd] don't support now") + t.Run("normal", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockConfigStore := mock.NewMockStore(ctrl) + mockConfigStore.EXPECT().Set(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, req *configstores.SetRequest) error { + assert.Equal(t, "appid", req.AppId) + assert.Equal(t, "mock", req.StoreName) + assert.Equal(t, 1, len(req.Items)) + return nil + }) + req := &runtimev1pb.SaveConfigurationRequest{ + StoreName: "mock", + AppId: "appid", + Items: []*runtimev1pb.ConfigurationItem{ + { + Key: "key", + Content: "value", + Group: " ", + Label: " ", + Tags: nil, + Metadata: nil, + }, + }, + Metadata: nil, + } + api := NewAPI("", nil, map[string]configstores.Store{"mock": mockConfigStore}, nil, nil, nil, nil, nil) + _, err := api.SaveConfiguration(context.Background(), req) + assert.Nil(t, err) + }) + + t.Run("unsupport configstore", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockConfigStore := mock.NewMockStore(ctrl) + api := NewAPI("", nil, map[string]configstores.Store{"mock": mockConfigStore}, nil, nil, nil, nil, nil) + _, err := api.SaveConfiguration(context.Background(), &runtimev1pb.SaveConfigurationRequest{StoreName: "etcd"}) + assert.Equal(t, err.Error(), "configure store [etcd] don't support now") + }) + } func TestDeleteConfiguration(t *testing.T) { - ctrl := gomock.NewController(t) - mockConfigStore := mock.NewMockStore(ctrl) - api := NewAPI("", nil, map[string]configstores.Store{"mock": mockConfigStore}, nil, nil, nil, nil, nil) - _, err := api.DeleteConfiguration(context.Background(), &runtimev1pb.DeleteConfigurationRequest{StoreName: "etcd"}) - assert.Equal(t, err.Error(), "configure store [etcd] don't support now") + t.Run("normal", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockConfigStore := mock.NewMockStore(ctrl) + mockConfigStore.EXPECT().Delete(gomock.Any(), gomock.Any()).DoAndReturn(func(ctx context.Context, req *configstores.DeleteRequest) error { + assert.Equal(t, "appid", req.AppId) + assert.Equal(t, 1, len(req.Keys)) + assert.Equal(t, "key", req.Keys[0]) + return nil + }) + req := &runtimev1pb.DeleteConfigurationRequest{ + StoreName: "mock", + AppId: "appid", + Keys: []string{"key"}, + Metadata: nil, + } + api := NewAPI("", nil, map[string]configstores.Store{"mock": mockConfigStore}, nil, nil, nil, nil, nil) + _, err := api.DeleteConfiguration(context.Background(), req) + assert.Nil(t, err) + }) + + t.Run("unsupport configstore", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockConfigStore := mock.NewMockStore(ctrl) + api := NewAPI("", nil, map[string]configstores.Store{"mock": mockConfigStore}, nil, nil, nil, nil, nil) + _, err := api.DeleteConfiguration(context.Background(), &runtimev1pb.DeleteConfigurationRequest{StoreName: "etcd"}) + assert.Equal(t, err.Error(), "configure store [etcd] don't support now") + }) + } func TestSubscribeConfiguration(t *testing.T) { @@ -178,5 +248,726 @@ func TestSubscribeConfiguration(t *testing.T) { err = api.SubscribeConfiguration(grpcServer2) assert.NotNil(t, err) assert.Equal(t, err.Error(), "exit") +} + +type MockInvoker struct { + tmock.Mock +} + +func (m *MockInvoker) Init(config rpc.RpcConfig) error { + args := m.Called(config) + return args.Error(0) +} + +func (m *MockInvoker) Invoke(ctx context.Context, req *rpc.RPCRequest) (*rpc.RPCResponse, error) { + args := m.Called(ctx, req) + return args.Get(0).(*rpc.RPCResponse), args.Error(1) +} + +func TestInvokeService(t *testing.T) { + t.Run("normal", func(t *testing.T) { + resp := &rpc.RPCResponse{ + Header: rpc.RPCHeader{ + "header1": []string{"value1"}, + }, + ContentType: "application/json", + Data: []byte("resp data"), + } + + mockInvoker := mock_invoker.NewMockInvoker(gomock.NewController(t)) + mockInvoker.EXPECT().Invoke(gomock.Any(), gomock.Any()). + DoAndReturn(func(ctx context.Context, req *rpc.RPCRequest) (*rpc.RPCResponse, error) { + assert.Equal(t, "id1", req.Id) + assert.Equal(t, "POST", req.Method) + assert.Equal(t, "application/json", req.ContentType) + return resp, nil + }) + in := &runtimev1pb.InvokeServiceRequest{ + Id: "id1", + Message: &runtimev1pb.CommonInvokeRequest{ + Method: "POST", + Data: &any.Any{}, + ContentType: "application/json", + }, + } + + a := &api{ + rpcs: map[string]rpc.Invoker{ + mosninvoker.Name: mockInvoker, + }, + } + + _, err := a.InvokeService(context.Background(), in) + assert.Nil(t, err) + }) +} + +func TestPublishEvent(t *testing.T) { + t.Run("invalid pubsub name", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockPubSub := mock_pubsub.NewMockPubSub(ctrl) + api := NewAPI("", nil, nil, nil, map[string]pubsub.PubSub{"mock": mockPubSub}, nil, nil, nil) + _, err := api.PublishEvent(context.Background(), &runtimev1pb.PublishEventRequest{}) + assert.Equal(t, "rpc error: code = InvalidArgument desc = pubsub name is empty", err.Error()) + }) + + t.Run("invalid topic", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockPubSub := mock_pubsub.NewMockPubSub(ctrl) + api := NewAPI("", nil, nil, nil, map[string]pubsub.PubSub{"mock": mockPubSub}, nil, nil, nil) + req := &runtimev1pb.PublishEventRequest{ + PubsubName: "abc", + } + _, err := api.PublishEvent(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = topic is empty in pubsub abc", err.Error()) + }) + + t.Run("component not found", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockPubSub := mock_pubsub.NewMockPubSub(ctrl) + api := NewAPI("", nil, nil, nil, map[string]pubsub.PubSub{"mock": mockPubSub}, nil, nil, nil) + req := &runtimev1pb.PublishEventRequest{ + PubsubName: "abc", + Topic: "abc", + } + _, err := api.PublishEvent(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = pubsub abc not found", err.Error()) + }) + + t.Run("publish success", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockPubSub := mock_pubsub.NewMockPubSub(ctrl) + mockPubSub.EXPECT().Publish(gomock.Any()).Return(nil) + mockPubSub.EXPECT().Features().Return(nil) + api := NewAPI("", nil, nil, nil, map[string]pubsub.PubSub{"mock": mockPubSub}, nil, nil, nil) + req := &runtimev1pb.PublishEventRequest{ + PubsubName: "mock", + Topic: "abc", + } + _, err := api.PublishEvent(context.Background(), req) + assert.Nil(t, err) + }) + + t.Run("publish net error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockPubSub := mock_pubsub.NewMockPubSub(ctrl) + mockPubSub.EXPECT().Publish(gomock.Any()).Return(fmt.Errorf("net error")) + mockPubSub.EXPECT().Features().Return(nil) + api := NewAPI("", nil, nil, nil, map[string]pubsub.PubSub{"mock": mockPubSub}, nil, nil, nil) + req := &runtimev1pb.PublishEventRequest{ + PubsubName: "mock", + Topic: "abc", + } + _, err := api.PublishEvent(context.Background(), req) + assert.NotNil(t, err) + assert.Equal(t, "rpc error: code = Internal desc = error when publish to topic abc in pubsub mock: net error", err.Error()) + }) +} + +func TestGetBulkState(t *testing.T) { + t.Run("state store not found", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetBulkStateRequest{ + StoreName: "abc", + } + _, err := api.GetBulkState(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = state store abc is not found", err.Error()) + }) + + t.Run("get state error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().BulkGet(gomock.Any()).Return(false, nil, fmt.Errorf("net error")) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetBulkStateRequest{ + StoreName: "mock", + Keys: []string{"mykey"}, + } + _, err := api.GetBulkState(context.Background(), req) + assert.Equal(t, "net error", err.Error()) + }) + + t.Run("support bulk get", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + + compResp := []state.BulkGetResponse{ + { + Data: []byte("mock data"), + Metadata: nil, + }, + } + mockStore.EXPECT().BulkGet(gomock.Any()).Return(true, compResp, nil) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetBulkStateRequest{ + StoreName: "mock", + Keys: []string{"mykey"}, + } + rsp, err := api.GetBulkState(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, []byte("mock data"), rsp.GetItems()[0].GetData()) + }) + + t.Run("don't support bulk get", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + + resp1 := &state.GetResponse{ + Data: []byte("mock data"), + Metadata: nil, + } + + resp2 := &state.GetResponse{ + Data: []byte("mock data2"), + Metadata: nil, + } + mockStore.EXPECT().BulkGet(gomock.Any()).Return(false, nil, nil) + mockStore.EXPECT().Get(gomock.Any()).Return(resp1, nil) + mockStore.EXPECT().Get(gomock.Any()).Return(resp2, nil) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetBulkStateRequest{ + StoreName: "mock", + Keys: []string{"mykey", "mykey2"}, + } + rsp, err := api.GetBulkState(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, 2, len(rsp.GetItems())) + }) + +} + +func TestGetState(t *testing.T) { + t.Run("state store not found", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetStateRequest{ + StoreName: "abc", + } + _, err := api.GetState(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = state store abc is not found", err.Error()) + }) + + t.Run("state store not configured", func(t *testing.T) { + api := NewAPI("", nil, nil, nil, nil, nil, nil, nil) + req := &runtimev1pb.GetStateRequest{ + StoreName: "abc", + } + _, err := api.GetState(context.Background(), req) + assert.Equal(t, "rpc error: code = FailedPrecondition desc = state store is not configured", err.Error()) + }) + + t.Run("get modified state key error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetStateRequest{ + StoreName: "mock", + Key: "mykey||abc", + } + _, err := api.GetState(context.Background(), req) + assert.Equal(t, "input key/keyPrefix 'mykey||abc' can't contain '||'", err.Error()) + }) + + t.Run("get state error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().Get(gomock.Any()).Return(nil, fmt.Errorf("net error")) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetStateRequest{ + StoreName: "mock", + Key: "mykey", + } + _, err := api.GetState(context.Background(), req) + assert.Equal(t, "rpc error: code = Internal desc = fail to get mykey from state store mock: net error", err.Error()) + }) + + t.Run("normal", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + + compResp := &state.GetResponse{ + Data: []byte("mock data"), + Metadata: nil, + } + mockStore.EXPECT().Get(gomock.Any()).Return(compResp, nil) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.GetStateRequest{ + StoreName: "mock", + Key: "mykey", + } + rsp, err := api.GetState(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, []byte("mock data"), rsp.GetData()) + }) } + +func TestSaveState(t *testing.T) { + t.Run("normal", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().BulkSet(gomock.Any()).DoAndReturn(func(reqs []state.SetRequest) error { + assert.Equal(t, 1, len(reqs)) + assert.Equal(t, "abc", reqs[0].Key) + assert.Equal(t, []byte("mock data"), reqs[0].Value) + return nil + }) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.SaveStateRequest{ + StoreName: "mock", + States: []*runtimev1pb.StateItem{ + { + Key: "abc", + Value: []byte("mock data"), + }, + }, + } + _, err := api.SaveState(context.Background(), req) + assert.Nil(t, err) + }) + + t.Run("save error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().BulkSet(gomock.Any()).Return(fmt.Errorf("net error")) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.SaveStateRequest{ + StoreName: "mock", + States: []*runtimev1pb.StateItem{ + { + Key: "abc", + Value: []byte("mock data"), + }, + }, + } + _, err := api.SaveState(context.Background(), req) + assert.NotNil(t, err) + assert.Equal(t, "rpc error: code = Internal desc = failed saving state in state store mock: net error", err.Error()) + }) +} + +func TestDeleteState(t *testing.T) { + t.Run("normal", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().Delete(gomock.Any()).DoAndReturn(func(req *state.DeleteRequest) error { + assert.Equal(t, "abc", req.Key) + return nil + }) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.DeleteStateRequest{ + StoreName: "mock", + Key: "abc", + } + _, err := api.DeleteState(context.Background(), req) + assert.Nil(t, err) + }) + + t.Run("net error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().Delete(gomock.Any()).Return(fmt.Errorf("net error")) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.DeleteStateRequest{ + StoreName: "mock", + Key: "abc", + } + _, err := api.DeleteState(context.Background(), req) + assert.NotNil(t, err) + assert.Equal(t, "rpc error: code = Internal desc = failed deleting state with key abc: net error", err.Error()) + }) +} + +func TestDeleteBulkState(t *testing.T) { + t.Run("normal", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().BulkDelete(gomock.Any()).DoAndReturn(func(reqs []state.DeleteRequest) error { + assert.Equal(t, "abc", reqs[0].Key) + return nil + }) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.DeleteBulkStateRequest{ + StoreName: "mock", + States: []*runtimev1pb.StateItem{ + { + Key: "abc", + }, + }, + } + _, err := api.DeleteBulkState(context.Background(), req) + assert.Nil(t, err) + }) + + t.Run("net error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + mockStore.EXPECT().BulkDelete(gomock.Any()).Return(fmt.Errorf("net error")) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.DeleteBulkStateRequest{ + StoreName: "mock", + States: []*runtimev1pb.StateItem{ + { + Key: "abc", + }, + }, + } + _, err := api.DeleteBulkState(context.Background(), req) + assert.NotNil(t, err) + assert.Equal(t, "net error", err.Error()) + }) +} + +type MockTxStore struct { + state.Store + state.TransactionalStore +} + +func (m *MockTxStore) Init(metadata state.Metadata) error { + return m.Store.Init(metadata) +} + +func TestExecuteStateTransaction(t *testing.T) { + t.Run("state store not found", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return(nil) + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": mockStore}, nil, nil) + req := &runtimev1pb.ExecuteStateTransactionRequest{ + StoreName: "abc", + } + _, err := api.ExecuteStateTransaction(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = state store abc is not found", err.Error()) + }) + + t.Run("state store not configured", func(t *testing.T) { + api := NewAPI("", nil, nil, nil, nil, nil, nil, nil) + req := &runtimev1pb.ExecuteStateTransactionRequest{ + StoreName: "abc", + } + _, err := api.ExecuteStateTransaction(context.Background(), req) + assert.Equal(t, "rpc error: code = FailedPrecondition desc = state store is not configured", err.Error()) + }) + + t.Run("normal", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return([]state.Feature{state.FeatureTransactional}) + + mockTxStore := mock_state.NewMockTransactionalStore(gomock.NewController(t)) + mockTxStore.EXPECT().Multi(gomock.Any()).DoAndReturn(func(req *state.TransactionalStateRequest) error { + assert.Equal(t, 2, len(req.Operations)) + assert.Equal(t, "mosn", req.Metadata["runtime"]) + assert.Equal(t, state.Upsert, req.Operations[0].Operation) + assert.Equal(t, state.Delete, req.Operations[1].Operation) + return nil + }) + + store := &MockTxStore{ + mockStore, + mockTxStore, + } + + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": store}, nil, nil) + req := &runtimev1pb.ExecuteStateTransactionRequest{ + StoreName: "mock", + Operations: []*runtimev1pb.TransactionalStateOperation{ + { + OperationType: string(state.Upsert), + Request: &runtimev1pb.StateItem{ + Key: "upsert", + Value: []byte("mock data"), + }, + }, + { + OperationType: string(state.Delete), + Request: &runtimev1pb.StateItem{ + Key: "delete_abc", + }, + }, + { + OperationType: string(state.Delete), + }, + }, + Metadata: map[string]string{ + "runtime": "mosn", + }, + } + _, err := api.ExecuteStateTransaction(context.Background(), req) + assert.Nil(t, err) + }) + + t.Run("net error", func(t *testing.T) { + ctrl := gomock.NewController(t) + mockStore := mock_state.NewMockStore(ctrl) + mockStore.EXPECT().Features().Return([]state.Feature{state.FeatureTransactional}) + + mockTxStore := mock_state.NewMockTransactionalStore(gomock.NewController(t)) + mockTxStore.EXPECT().Multi(gomock.Any()).Return(fmt.Errorf("net error")) + + store := &MockTxStore{ + mockStore, + mockTxStore, + } + api := NewAPI("", nil, nil, nil, nil, map[string]state.Store{"mock": store}, nil, nil) + req := &runtimev1pb.ExecuteStateTransactionRequest{ + StoreName: "mock", + Operations: []*runtimev1pb.TransactionalStateOperation{ + { + OperationType: string(state.Upsert), + Request: &runtimev1pb.StateItem{ + Key: "upsert", + Value: []byte("mock data"), + }, + }, + { + OperationType: string(state.Delete), + Request: &runtimev1pb.StateItem{ + Key: "delete_abc", + }, + }, + { + OperationType: string(state.Delete), + }, + }, + Metadata: map[string]string{ + "runtime": "mosn", + }, + } + _, err := api.ExecuteStateTransaction(context.Background(), req) + assert.NotNil(t, err) + assert.Equal(t, "rpc error: code = Internal desc = error while executing state transaction: net error", err.Error()) + }) +} + +func TestTryLock(t *testing.T) { + t.Run("lock store not configured", func(t *testing.T) { + api := NewAPI("", nil, nil, nil, nil, nil, nil, nil) + req := &runtimev1pb.TryLockRequest{ + StoreName: "abc", + } + _, err := api.TryLock(context.Background(), req) + assert.Equal(t, "rpc error: code = FailedPrecondition desc = lock store is not configured", err.Error()) + }) + + t.Run("resourceid empty", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.TryLockRequest{ + StoreName: "abc", + } + _, err := api.TryLock(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = ResourceId is empty in lock store abc", err.Error()) + }) + + t.Run("lock owner empty", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.TryLockRequest{ + StoreName: "abc", + ResourceId: "resource", + } + _, err := api.TryLock(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = LockOwner is empty in lock store abc", err.Error()) + }) + + t.Run("lock expire is not positive", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.TryLockRequest{ + StoreName: "abc", + ResourceId: "resource", + LockOwner: "owner", + } + _, err := api.TryLock(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = Expire is not positive in lock store abc", err.Error()) + }) + + t.Run("lock store not found", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.TryLockRequest{ + StoreName: "abc", + ResourceId: "resource", + LockOwner: "owner", + Expire: 1, + } + _, err := api.TryLock(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = lock store abc not found", err.Error()) + }) + + t.Run("normal", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + mockLockStore.EXPECT().TryLock(gomock.Any()).DoAndReturn(func(req *lock.TryLockRequest) (*lock.TryLockResponse, error) { + assert.Equal(t, "lock|||resource", req.ResourceId) + assert.Equal(t, "owner", req.LockOwner) + assert.Equal(t, int32(1), req.Expire) + return &lock.TryLockResponse{ + Success: true, + }, nil + }) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.TryLockRequest{ + StoreName: "mock", + ResourceId: "resource", + LockOwner: "owner", + Expire: 1, + } + resp, err := api.TryLock(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, true, resp.Success) + }) + +} + +func TestUnlock(t *testing.T) { + t.Run("lock store not configured", func(t *testing.T) { + api := NewAPI("", nil, nil, nil, nil, nil, nil, nil) + req := &runtimev1pb.UnlockRequest{ + StoreName: "abc", + } + _, err := api.Unlock(context.Background(), req) + assert.Equal(t, "rpc error: code = FailedPrecondition desc = lock store is not configured", err.Error()) + }) + + t.Run("resourceid empty", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.UnlockRequest{ + StoreName: "abc", + } + _, err := api.Unlock(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = ResourceId is empty in lock store abc", err.Error()) + }) + + t.Run("lock owner empty", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.UnlockRequest{ + StoreName: "abc", + ResourceId: "resource", + } + _, err := api.Unlock(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = LockOwner is empty in lock store abc", err.Error()) + }) + + t.Run("lock store not found", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.UnlockRequest{ + StoreName: "abc", + ResourceId: "resource", + LockOwner: "owner", + } + _, err := api.Unlock(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = lock store abc not found", err.Error()) + }) + + t.Run("normal", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + mockLockStore.EXPECT().Unlock(gomock.Any()).DoAndReturn(func(req *lock.UnlockRequest) (*lock.UnlockResponse, error) { + assert.Equal(t, "lock|||resource", req.ResourceId) + assert.Equal(t, "owner", req.LockOwner) + return &lock.UnlockResponse{ + Status: lock.SUCCESS, + }, nil + }) + api := NewAPI("", nil, nil, nil, nil, nil, map[string]lock.LockStore{"mock": mockLockStore}, nil) + req := &runtimev1pb.UnlockRequest{ + StoreName: "mock", + ResourceId: "resource", + LockOwner: "owner", + } + resp, err := api.Unlock(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, runtimev1pb.UnlockResponse_SUCCESS, resp.Status) + }) +} + +func TestGetNextId(t *testing.T) { + t.Run("sequencers not configured", func(t *testing.T) { + api := NewAPI("", nil, nil, nil, nil, nil, nil, nil) + req := &runtimev1pb.GetNextIdRequest{ + StoreName: "abc", + } + _, err := api.GetNextId(context.Background(), req) + assert.Equal(t, "rpc error: code = FailedPrecondition desc = Sequencer store is not configured", err.Error()) + }) + + t.Run("seq key empty", func(t *testing.T) { + mockSequencerStore := mock_sequencer.NewMockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, nil, map[string]sequencer.Store{"mock": mockSequencerStore}) + req := &runtimev1pb.GetNextIdRequest{ + StoreName: "abc", + } + _, err := api.GetNextId(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = Key is empty in sequencer store abc", err.Error()) + }) + + t.Run("sequencer store not found", func(t *testing.T) { + mockSequencerStore := mock_sequencer.NewMockStore(gomock.NewController(t)) + api := NewAPI("", nil, nil, nil, nil, nil, nil, map[string]sequencer.Store{"mock": mockSequencerStore}) + req := &runtimev1pb.GetNextIdRequest{ + StoreName: "abc", + Key: "next key", + } + _, err := api.GetNextId(context.Background(), req) + assert.Equal(t, "rpc error: code = InvalidArgument desc = Sequencer store abc not found", err.Error()) + }) + + t.Run("auto increment is strong", func(t *testing.T) { + mockSequencerStore := mock_sequencer.NewMockStore(gomock.NewController(t)) + mockSequencerStore.EXPECT().GetNextId(gomock.Any()). + DoAndReturn(func(req *sequencer.GetNextIdRequest) (*sequencer.GetNextIdResponse, error) { + assert.Equal(t, "sequencer|||next key", req.Key) + assert.Equal(t, sequencer.STRONG, req.Options.AutoIncrement) + return &sequencer.GetNextIdResponse{ + NextId: 10, + }, nil + }) + api := NewAPI("", nil, nil, nil, nil, nil, nil, map[string]sequencer.Store{"mock": mockSequencerStore}) + req := &runtimev1pb.GetNextIdRequest{ + StoreName: "mock", + Key: "next key", + Options: &runtimev1pb.SequencerOptions{ + Increment: runtimev1pb.SequencerOptions_STRONG, + }, + } + rsp, err := api.GetNextId(context.Background(), req) + assert.Nil(t, err) + assert.Equal(t, int64(10), rsp.NextId) + }) + + t.Run("net error", func(t *testing.T) { + mockSequencerStore := mock_sequencer.NewMockStore(gomock.NewController(t)) + mockSequencerStore.EXPECT().GetNextId(gomock.Any()).Return(nil, fmt.Errorf("net error")) + api := NewAPI("", nil, nil, nil, nil, nil, nil, map[string]sequencer.Store{"mock": mockSequencerStore}) + req := &runtimev1pb.GetNextIdRequest{ + StoreName: "mock", + Key: "next key", + Options: &runtimev1pb.SequencerOptions{ + Increment: runtimev1pb.SequencerOptions_STRONG, + }, + } + _, err := api.GetNextId(context.Background(), req) + assert.NotNil(t, err) + assert.Equal(t, "net error", err.Error()) + }) +} diff --git a/pkg/mock/components/invoker/invoker.go b/pkg/mock/components/invoker/invoker.go new file mode 100644 index 0000000000..2f4f7492fc --- /dev/null +++ b/pkg/mock/components/invoker/invoker.go @@ -0,0 +1,180 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: components/rpc/types.go + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + rpc "mosn.io/layotto/components/rpc" +) + +// MockInvoker is a mock of Invoker interface. +type MockInvoker struct { + ctrl *gomock.Controller + recorder *MockInvokerMockRecorder +} + +// MockInvokerMockRecorder is the mock recorder for MockInvoker. +type MockInvokerMockRecorder struct { + mock *MockInvoker +} + +// NewMockInvoker creates a new mock instance. +func NewMockInvoker(ctrl *gomock.Controller) *MockInvoker { + mock := &MockInvoker{ctrl: ctrl} + mock.recorder = &MockInvokerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockInvoker) EXPECT() *MockInvokerMockRecorder { + return m.recorder +} + +// Init mocks base method. +func (m *MockInvoker) Init(config rpc.RpcConfig) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", config) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockInvokerMockRecorder) Init(config interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockInvoker)(nil).Init), config) +} + +// Invoke mocks base method. +func (m *MockInvoker) Invoke(ctx context.Context, req *rpc.RPCRequest) (*rpc.RPCResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Invoke", ctx, req) + ret0, _ := ret[0].(*rpc.RPCResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Invoke indicates an expected call of Invoke. +func (mr *MockInvokerMockRecorder) Invoke(ctx, req interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Invoke", reflect.TypeOf((*MockInvoker)(nil).Invoke), ctx, req) +} + +// MockCallback is a mock of Callback interface. +type MockCallback struct { + ctrl *gomock.Controller + recorder *MockCallbackMockRecorder +} + +// MockCallbackMockRecorder is the mock recorder for MockCallback. +type MockCallbackMockRecorder struct { + mock *MockCallback +} + +// NewMockCallback creates a new mock instance. +func NewMockCallback(ctrl *gomock.Controller) *MockCallback { + mock := &MockCallback{ctrl: ctrl} + mock.recorder = &MockCallbackMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCallback) EXPECT() *MockCallbackMockRecorder { + return m.recorder +} + +// AddAfterInvoke mocks base method. +func (m *MockCallback) AddAfterInvoke(arg0 rpc.CallbackFunc) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "AddAfterInvoke", arg0) +} + +// AddAfterInvoke indicates an expected call of AddAfterInvoke. +func (mr *MockCallbackMockRecorder) AddAfterInvoke(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddAfterInvoke", reflect.TypeOf((*MockCallback)(nil).AddAfterInvoke), arg0) +} + +// AddBeforeInvoke mocks base method. +func (m *MockCallback) AddBeforeInvoke(arg0 rpc.CallbackFunc) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "AddBeforeInvoke", arg0) +} + +// AddBeforeInvoke indicates an expected call of AddBeforeInvoke. +func (mr *MockCallbackMockRecorder) AddBeforeInvoke(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBeforeInvoke", reflect.TypeOf((*MockCallback)(nil).AddBeforeInvoke), arg0) +} + +// AfterInvoke mocks base method. +func (m *MockCallback) AfterInvoke(arg0 *rpc.RPCResponse) (*rpc.RPCResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AfterInvoke", arg0) + ret0, _ := ret[0].(*rpc.RPCResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AfterInvoke indicates an expected call of AfterInvoke. +func (mr *MockCallbackMockRecorder) AfterInvoke(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterInvoke", reflect.TypeOf((*MockCallback)(nil).AfterInvoke), arg0) +} + +// BeforeInvoke mocks base method. +func (m *MockCallback) BeforeInvoke(arg0 *rpc.RPCRequest) (*rpc.RPCRequest, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BeforeInvoke", arg0) + ret0, _ := ret[0].(*rpc.RPCRequest) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// BeforeInvoke indicates an expected call of BeforeInvoke. +func (mr *MockCallbackMockRecorder) BeforeInvoke(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BeforeInvoke", reflect.TypeOf((*MockCallback)(nil).BeforeInvoke), arg0) +} + +// MockChannel is a mock of Channel interface. +type MockChannel struct { + ctrl *gomock.Controller + recorder *MockChannelMockRecorder +} + +// MockChannelMockRecorder is the mock recorder for MockChannel. +type MockChannelMockRecorder struct { + mock *MockChannel +} + +// NewMockChannel creates a new mock instance. +func NewMockChannel(ctrl *gomock.Controller) *MockChannel { + mock := &MockChannel{ctrl: ctrl} + mock.recorder = &MockChannelMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockChannel) EXPECT() *MockChannelMockRecorder { + return m.recorder +} + +// Do mocks base method. +func (m *MockChannel) Do(arg0 *rpc.RPCRequest) (*rpc.RPCResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Do", arg0) + ret0, _ := ret[0].(*rpc.RPCResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Do indicates an expected call of Do. +func (mr *MockChannelMockRecorder) Do(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Do", reflect.TypeOf((*MockChannel)(nil).Do), arg0) +} diff --git a/pkg/mock/components/lock/lock.go b/pkg/mock/components/lock/lock.go new file mode 100644 index 0000000000..345bf3d076 --- /dev/null +++ b/pkg/mock/components/lock/lock.go @@ -0,0 +1,93 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: components/lock/lock_store.go + +// Package mock_lock is a generated GoMock package. +package mock_lock + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + lock "mosn.io/layotto/components/lock" +) + +// MockLockStore is a mock of LockStore interface. +type MockLockStore struct { + ctrl *gomock.Controller + recorder *MockLockStoreMockRecorder +} + +// MockLockStoreMockRecorder is the mock recorder for MockLockStore. +type MockLockStoreMockRecorder struct { + mock *MockLockStore +} + +// NewMockLockStore creates a new mock instance. +func NewMockLockStore(ctrl *gomock.Controller) *MockLockStore { + mock := &MockLockStore{ctrl: ctrl} + mock.recorder = &MockLockStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockLockStore) EXPECT() *MockLockStoreMockRecorder { + return m.recorder +} + +// Features mocks base method. +func (m *MockLockStore) Features() []lock.Feature { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Features") + ret0, _ := ret[0].([]lock.Feature) + return ret0 +} + +// Features indicates an expected call of Features. +func (mr *MockLockStoreMockRecorder) Features() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Features", reflect.TypeOf((*MockLockStore)(nil).Features)) +} + +// Init mocks base method. +func (m *MockLockStore) Init(metadata lock.Metadata) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", metadata) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockLockStoreMockRecorder) Init(metadata interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockLockStore)(nil).Init), metadata) +} + +// TryLock mocks base method. +func (m *MockLockStore) TryLock(req *lock.TryLockRequest) (*lock.TryLockResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TryLock", req) + ret0, _ := ret[0].(*lock.TryLockResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TryLock indicates an expected call of TryLock. +func (mr *MockLockStoreMockRecorder) TryLock(req interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TryLock", reflect.TypeOf((*MockLockStore)(nil).TryLock), req) +} + +// Unlock mocks base method. +func (m *MockLockStore) Unlock(req *lock.UnlockRequest) (*lock.UnlockResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Unlock", req) + ret0, _ := ret[0].(*lock.UnlockResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Unlock indicates an expected call of Unlock. +func (mr *MockLockStoreMockRecorder) Unlock(req interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Unlock", reflect.TypeOf((*MockLockStore)(nil).Unlock), req) +} diff --git a/pkg/mock/components/pubsub/pubsub.go b/pkg/mock/components/pubsub/pubsub.go new file mode 100644 index 0000000000..67c47d121a --- /dev/null +++ b/pkg/mock/components/pubsub/pubsub.go @@ -0,0 +1,105 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/dapr/components-contrib/pubsub (interfaces: PubSub) + +// Package mock is a generated GoMock package. +package mock + +import ( + reflect "reflect" + + pubsub "github.com/dapr/components-contrib/pubsub" + gomock "github.com/golang/mock/gomock" +) + +// MockPubSub is a mock of PubSub interface. +type MockPubSub struct { + ctrl *gomock.Controller + recorder *MockPubSubMockRecorder +} + +// MockPubSubMockRecorder is the mock recorder for MockPubSub. +type MockPubSubMockRecorder struct { + mock *MockPubSub +} + +// NewMockPubSub creates a new mock instance. +func NewMockPubSub(ctrl *gomock.Controller) *MockPubSub { + mock := &MockPubSub{ctrl: ctrl} + mock.recorder = &MockPubSubMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockPubSub) EXPECT() *MockPubSubMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockPubSub) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockPubSubMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPubSub)(nil).Close)) +} + +// Features mocks base method. +func (m *MockPubSub) Features() []pubsub.Feature { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Features") + ret0, _ := ret[0].([]pubsub.Feature) + return ret0 +} + +// Features indicates an expected call of Features. +func (mr *MockPubSubMockRecorder) Features() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Features", reflect.TypeOf((*MockPubSub)(nil).Features)) +} + +// Init mocks base method. +func (m *MockPubSub) Init(arg0 pubsub.Metadata) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockPubSubMockRecorder) Init(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockPubSub)(nil).Init), arg0) +} + +// Publish mocks base method. +func (m *MockPubSub) Publish(arg0 *pubsub.PublishRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Publish", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Publish indicates an expected call of Publish. +func (mr *MockPubSubMockRecorder) Publish(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Publish", reflect.TypeOf((*MockPubSub)(nil).Publish), arg0) +} + +// Subscribe mocks base method. +func (m *MockPubSub) Subscribe(arg0 pubsub.SubscribeRequest, arg1 pubsub.Handler) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Subscribe", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Subscribe indicates an expected call of Subscribe. +func (mr *MockPubSubMockRecorder) Subscribe(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockPubSub)(nil).Subscribe), arg0, arg1) +} diff --git a/pkg/mock/components/sequencer/sequencer.go b/pkg/mock/components/sequencer/sequencer.go new file mode 100644 index 0000000000..1eaf253849 --- /dev/null +++ b/pkg/mock/components/sequencer/sequencer.go @@ -0,0 +1,80 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: components/sequencer/store.go + +// Package mock_sequencer is a generated GoMock package. +package mock_sequencer + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + sequencer "mosn.io/layotto/components/sequencer" +) + +// MockStore is a mock of Store interface. +type MockStore struct { + ctrl *gomock.Controller + recorder *MockStoreMockRecorder +} + +// MockStoreMockRecorder is the mock recorder for MockStore. +type MockStoreMockRecorder struct { + mock *MockStore +} + +// NewMockStore creates a new mock instance. +func NewMockStore(ctrl *gomock.Controller) *MockStore { + mock := &MockStore{ctrl: ctrl} + mock.recorder = &MockStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStore) EXPECT() *MockStoreMockRecorder { + return m.recorder +} + +// GetNextId mocks base method. +func (m *MockStore) GetNextId(arg0 *sequencer.GetNextIdRequest) (*sequencer.GetNextIdResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNextId", arg0) + ret0, _ := ret[0].(*sequencer.GetNextIdResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetNextId indicates an expected call of GetNextId. +func (mr *MockStoreMockRecorder) GetNextId(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNextId", reflect.TypeOf((*MockStore)(nil).GetNextId), arg0) +} + +// GetSegment mocks base method. +func (m *MockStore) GetSegment(arg0 *sequencer.GetSegmentRequest) (bool, *sequencer.GetSegmentResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSegment", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(*sequencer.GetSegmentResponse) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// GetSegment indicates an expected call of GetSegment. +func (mr *MockStoreMockRecorder) GetSegment(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSegment", reflect.TypeOf((*MockStore)(nil).GetSegment), arg0) +} + +// Init mocks base method. +func (m *MockStore) Init(config sequencer.Configuration) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", config) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockStoreMockRecorder) Init(config interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockStore)(nil).Init), config) +} diff --git a/pkg/mock/components/state/state.go b/pkg/mock/components/state/state.go new file mode 100644 index 0000000000..6e1e8ace60 --- /dev/null +++ b/pkg/mock/components/state/state.go @@ -0,0 +1,201 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/dapr/components-contrib/state (interfaces: Store,TransactionalStore) + +// Package mock_state is a generated GoMock package. +package mock_state + +import ( + reflect "reflect" + + state "github.com/dapr/components-contrib/state" + gomock "github.com/golang/mock/gomock" +) + +// MockStore is a mock of Store interface. +type MockStore struct { + ctrl *gomock.Controller + recorder *MockStoreMockRecorder +} + +// MockStoreMockRecorder is the mock recorder for MockStore. +type MockStoreMockRecorder struct { + mock *MockStore +} + +// NewMockStore creates a new mock instance. +func NewMockStore(ctrl *gomock.Controller) *MockStore { + mock := &MockStore{ctrl: ctrl} + mock.recorder = &MockStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStore) EXPECT() *MockStoreMockRecorder { + return m.recorder +} + +// BulkDelete mocks base method. +func (m *MockStore) BulkDelete(arg0 []state.DeleteRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BulkDelete", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// BulkDelete indicates an expected call of BulkDelete. +func (mr *MockStoreMockRecorder) BulkDelete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkDelete", reflect.TypeOf((*MockStore)(nil).BulkDelete), arg0) +} + +// BulkGet mocks base method. +func (m *MockStore) BulkGet(arg0 []state.GetRequest) (bool, []state.BulkGetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BulkGet", arg0) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].([]state.BulkGetResponse) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// BulkGet indicates an expected call of BulkGet. +func (mr *MockStoreMockRecorder) BulkGet(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkGet", reflect.TypeOf((*MockStore)(nil).BulkGet), arg0) +} + +// BulkSet mocks base method. +func (m *MockStore) BulkSet(arg0 []state.SetRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BulkSet", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// BulkSet indicates an expected call of BulkSet. +func (mr *MockStoreMockRecorder) BulkSet(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkSet", reflect.TypeOf((*MockStore)(nil).BulkSet), arg0) +} + +// Delete mocks base method. +func (m *MockStore) Delete(arg0 *state.DeleteRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockStoreMockRecorder) Delete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockStore)(nil).Delete), arg0) +} + +// Features mocks base method. +func (m *MockStore) Features() []state.Feature { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Features") + ret0, _ := ret[0].([]state.Feature) + return ret0 +} + +// Features indicates an expected call of Features. +func (mr *MockStoreMockRecorder) Features() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Features", reflect.TypeOf((*MockStore)(nil).Features)) +} + +// Get mocks base method. +func (m *MockStore) Get(arg0 *state.GetRequest) (*state.GetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0) + ret0, _ := ret[0].(*state.GetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockStoreMockRecorder) Get(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockStore)(nil).Get), arg0) +} + +// Init mocks base method. +func (m *MockStore) Init(arg0 state.Metadata) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockStoreMockRecorder) Init(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockStore)(nil).Init), arg0) +} + +// Set mocks base method. +func (m *MockStore) Set(arg0 *state.SetRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Set", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Set indicates an expected call of Set. +func (mr *MockStoreMockRecorder) Set(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Set", reflect.TypeOf((*MockStore)(nil).Set), arg0) +} + +// MockTransactionalStore is a mock of TransactionalStore interface. +type MockTransactionalStore struct { + ctrl *gomock.Controller + recorder *MockTransactionalStoreMockRecorder +} + +// MockTransactionalStoreMockRecorder is the mock recorder for MockTransactionalStore. +type MockTransactionalStoreMockRecorder struct { + mock *MockTransactionalStore +} + +// NewMockTransactionalStore creates a new mock instance. +func NewMockTransactionalStore(ctrl *gomock.Controller) *MockTransactionalStore { + mock := &MockTransactionalStore{ctrl: ctrl} + mock.recorder = &MockTransactionalStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTransactionalStore) EXPECT() *MockTransactionalStoreMockRecorder { + return m.recorder +} + +// Init mocks base method. +func (m *MockTransactionalStore) Init(arg0 state.Metadata) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Init", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Init indicates an expected call of Init. +func (mr *MockTransactionalStoreMockRecorder) Init(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Init", reflect.TypeOf((*MockTransactionalStore)(nil).Init), arg0) +} + +// Multi mocks base method. +func (m *MockTransactionalStore) Multi(arg0 *state.TransactionalStateRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Multi", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Multi indicates an expected call of Multi. +func (mr *MockTransactionalStoreMockRecorder) Multi(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Multi", reflect.TypeOf((*MockTransactionalStore)(nil).Multi), arg0) +} diff --git a/pkg/mock/runtime/appcallback/appcallback.go b/pkg/mock/runtime/appcallback/appcallback.go new file mode 100644 index 0000000000..0db0c5874a --- /dev/null +++ b/pkg/mock/runtime/appcallback/appcallback.go @@ -0,0 +1,131 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: spec/proto/runtime/v1/appcallback.pb.go + +// Package mock_appcallback is a generated GoMock package. +package mock_appcallback + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + empty "github.com/golang/protobuf/ptypes/empty" + grpc "google.golang.org/grpc" + runtime "mosn.io/layotto/spec/proto/runtime/v1" +) + +// MockAppCallbackClient is a mock of AppCallbackClient interface. +type MockAppCallbackClient struct { + ctrl *gomock.Controller + recorder *MockAppCallbackClientMockRecorder +} + +// MockAppCallbackClientMockRecorder is the mock recorder for MockAppCallbackClient. +type MockAppCallbackClientMockRecorder struct { + mock *MockAppCallbackClient +} + +// NewMockAppCallbackClient creates a new mock instance. +func NewMockAppCallbackClient(ctrl *gomock.Controller) *MockAppCallbackClient { + mock := &MockAppCallbackClient{ctrl: ctrl} + mock.recorder = &MockAppCallbackClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAppCallbackClient) EXPECT() *MockAppCallbackClientMockRecorder { + return m.recorder +} + +// ListTopicSubscriptions mocks base method. +func (m *MockAppCallbackClient) ListTopicSubscriptions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*runtime.ListTopicSubscriptionsResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListTopicSubscriptions", varargs...) + ret0, _ := ret[0].(*runtime.ListTopicSubscriptionsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListTopicSubscriptions indicates an expected call of ListTopicSubscriptions. +func (mr *MockAppCallbackClientMockRecorder) ListTopicSubscriptions(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTopicSubscriptions", reflect.TypeOf((*MockAppCallbackClient)(nil).ListTopicSubscriptions), varargs...) +} + +// OnTopicEvent mocks base method. +func (m *MockAppCallbackClient) OnTopicEvent(ctx context.Context, in *runtime.TopicEventRequest, opts ...grpc.CallOption) (*runtime.TopicEventResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{ctx, in} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "OnTopicEvent", varargs...) + ret0, _ := ret[0].(*runtime.TopicEventResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OnTopicEvent indicates an expected call of OnTopicEvent. +func (mr *MockAppCallbackClientMockRecorder) OnTopicEvent(ctx, in interface{}, opts ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx, in}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnTopicEvent", reflect.TypeOf((*MockAppCallbackClient)(nil).OnTopicEvent), varargs...) +} + +// MockAppCallbackServer is a mock of AppCallbackServer interface. +type MockAppCallbackServer struct { + ctrl *gomock.Controller + recorder *MockAppCallbackServerMockRecorder +} + +// MockAppCallbackServerMockRecorder is the mock recorder for MockAppCallbackServer. +type MockAppCallbackServerMockRecorder struct { + mock *MockAppCallbackServer +} + +// NewMockAppCallbackServer creates a new mock instance. +func NewMockAppCallbackServer(ctrl *gomock.Controller) *MockAppCallbackServer { + mock := &MockAppCallbackServer{ctrl: ctrl} + mock.recorder = &MockAppCallbackServerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAppCallbackServer) EXPECT() *MockAppCallbackServerMockRecorder { + return m.recorder +} + +// ListTopicSubscriptions mocks base method. +func (m *MockAppCallbackServer) ListTopicSubscriptions(arg0 context.Context, arg1 *empty.Empty) (*runtime.ListTopicSubscriptionsResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListTopicSubscriptions", arg0, arg1) + ret0, _ := ret[0].(*runtime.ListTopicSubscriptionsResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListTopicSubscriptions indicates an expected call of ListTopicSubscriptions. +func (mr *MockAppCallbackServerMockRecorder) ListTopicSubscriptions(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTopicSubscriptions", reflect.TypeOf((*MockAppCallbackServer)(nil).ListTopicSubscriptions), arg0, arg1) +} + +// OnTopicEvent mocks base method. +func (m *MockAppCallbackServer) OnTopicEvent(arg0 context.Context, arg1 *runtime.TopicEventRequest) (*runtime.TopicEventResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OnTopicEvent", arg0, arg1) + ret0, _ := ret[0].(*runtime.TopicEventResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// OnTopicEvent indicates an expected call of OnTopicEvent. +func (mr *MockAppCallbackServerMockRecorder) OnTopicEvent(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnTopicEvent", reflect.TypeOf((*MockAppCallbackServer)(nil).OnTopicEvent), arg0, arg1) +} diff --git a/pkg/runtime/runtime_test.go b/pkg/runtime/runtime_test.go new file mode 100644 index 0000000000..fdc279da00 --- /dev/null +++ b/pkg/runtime/runtime_test.go @@ -0,0 +1,364 @@ +/* + * Copyright 2021 Layotto Authors + * + * 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 runtime + +import ( + "context" + "encoding/json" + "fmt" + "net" + "testing" + + "github.com/dapr/components-contrib/pubsub" + "github.com/dapr/components-contrib/state" + "github.com/golang/mock/gomock" + jsoniter "github.com/json-iterator/go" + "github.com/stretchr/testify/assert" + rawGRPC "google.golang.org/grpc" + "google.golang.org/grpc/test/bufconn" + + "mosn.io/pkg/log" + + "mosn.io/layotto/components/configstores" + "mosn.io/layotto/components/hello" + "mosn.io/layotto/components/lock" + "mosn.io/layotto/components/rpc" + "mosn.io/layotto/components/sequencer" + "mosn.io/layotto/pkg/mock" + mock_invoker "mosn.io/layotto/pkg/mock/components/invoker" + mock_lock "mosn.io/layotto/pkg/mock/components/lock" + mock_pubsub "mosn.io/layotto/pkg/mock/components/pubsub" + mock_sequencer "mosn.io/layotto/pkg/mock/components/sequencer" + mock_state "mosn.io/layotto/pkg/mock/components/state" + mock_appcallback "mosn.io/layotto/pkg/mock/runtime/appcallback" + mlock "mosn.io/layotto/pkg/runtime/lock" + mpubsub "mosn.io/layotto/pkg/runtime/pubsub" + msequencer "mosn.io/layotto/pkg/runtime/sequencer" + mstate "mosn.io/layotto/pkg/runtime/state" + runtimev1pb "mosn.io/layotto/spec/proto/runtime/v1" +) + +func TestNewMosnRuntime(t *testing.T) { + runtimeConfig := &MosnRuntimeConfig{} + rt := NewMosnRuntime(runtimeConfig) + assert.NotNil(t, rt) +} + +func TestMosnRuntime_GetInfo(t *testing.T) { + runtimeConfig := &MosnRuntimeConfig{} + rt := NewMosnRuntime(runtimeConfig) + runtimeInfo := rt.GetInfo() + assert.NotNil(t, runtimeInfo) +} + +func TestMosnRuntime_Run(t *testing.T) { + t.Run("run succ", func(t *testing.T) { + runtimeConfig := &MosnRuntimeConfig{} + rt := NewMosnRuntime(runtimeConfig) + server, err := rt.Run() + assert.Nil(t, err) + assert.NotNil(t, server) + }) + + t.Run("no runtime config", func(t *testing.T) { + rt := NewMosnRuntime(nil) + _, err := rt.Run() + assert.NotNil(t, err) + assert.Equal(t, "[runtime] init error:no runtimeConfig", err.Error()) + }) +} + +func TestMosnRuntime_initAppCallbackConnection(t *testing.T) { + t.Run("init success", func(t *testing.T) { + // prepare app callback grpc server + port := 8888 + listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%v", port)) + assert.Nil(t, err) + defer listener.Close() + svr := rawGRPC.NewServer() + go func() { + svr.Serve(listener) + }() + cfg := &MosnRuntimeConfig{ + AppManagement: AppConfig{ + AppId: "", + GrpcCallbackPort: port, + }, + } + // construct MosnRuntime + m := NewMosnRuntime(cfg) + // test initAppCallbackConnection + err = m.initAppCallbackConnection() + // assert + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_initPubSubs(t *testing.T) { + t.Run("normal", func(t *testing.T) { + // mock callback response + subResp := &runtimev1pb.ListTopicSubscriptionsResponse{ + Subscriptions: []*runtimev1pb.TopicSubscription{ + { + PubsubName: "mock", + Topic: "layotto", + Metadata: nil, + }, + }, + } + // init grpc server + mockAppCallbackServer := mock_appcallback.NewMockAppCallbackServer(gomock.NewController(t)) + mockAppCallbackServer.EXPECT().ListTopicSubscriptions(gomock.Any(), gomock.Any()).Return(subResp, nil) + + lis := bufconn.Listen(1024 * 1024) + s := rawGRPC.NewServer() + runtimev1pb.RegisterAppCallbackServer(s, mockAppCallbackServer) + go func() { + s.Serve(lis) + }() + + // init callback client + callbackClient, err := rawGRPC.DialContext(context.Background(), "bufnet", rawGRPC.WithInsecure(), rawGRPC.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) { + return lis.Dial() + })) + assert.Nil(t, err) + + // mock pubsub component + mockPubSub := mock_pubsub.NewMockPubSub(gomock.NewController(t)) + mockPubSub.EXPECT().Init(gomock.Any()).Return(nil) + mockPubSub.EXPECT().Subscribe(gomock.Any(), gomock.Any()).Return(nil) + f := func() pubsub.PubSub { + return mockPubSub + } + + cfg := &MosnRuntimeConfig{ + PubSubManagement: map[string]mpubsub.Config{ + "mock": { + Metadata: map[string]string{ + "target": "layotto", + }, + }, + }, + } + // construct MosnRuntime + m := NewMosnRuntime(cfg) + m.AppCallbackConn = callbackClient + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + // test initPubSubs + err = m.initPubSubs(mpubsub.NewFactory("mock", f)) + // assert result + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_initStates(t *testing.T) { + t.Run("init success", func(t *testing.T) { + // prepare mock + mockStateStore := mock_state.NewMockStore(gomock.NewController(t)) + mockStateStore.EXPECT().Init(gomock.Any()).Return(nil) + f := func() state.Store { + return mockStateStore + } + + cfg := &MosnRuntimeConfig{ + StateManagement: map[string]mstate.Config{ + "mock": { + Metadata: map[string]string{ + "target": "layotto", + }, + }, + }, + } + // construct MosnRuntime + m := NewMosnRuntime(cfg) + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + // test initStates + err := m.initStates(mstate.NewFactory("mock", f)) + // assert result + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_initRpc(t *testing.T) { + t.Run("init success", func(t *testing.T) { + // prepare mock + mockInvoker := mock_invoker.NewMockInvoker(gomock.NewController(t)) + mockInvoker.EXPECT().Init(gomock.Any()).Return(nil) + f := func() rpc.Invoker { + return mockInvoker + } + + cfg := &MosnRuntimeConfig{ + RpcManagement: map[string]rpc.RpcConfig{ + "mock": {}, + }, + } + // construct MosnRuntime + m := NewMosnRuntime(cfg) + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + // test initRpcs method + err := m.initRpcs(rpc.NewRpcFactory("mock", f)) + // assert + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_initConfigStores(t *testing.T) { + t.Run("init success", func(t *testing.T) { + mockStore := mock.NewMockStore(gomock.NewController(t)) + mockStore.EXPECT().Init(gomock.Any()).Return(nil) + f := func() configstores.Store { + return mockStore + } + + cfg := &MosnRuntimeConfig{ + ConfigStoreManagement: map[string]configstores.StoreConfig{ + "mock": {}, + }, + } + m := NewMosnRuntime(cfg) + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + err := m.initConfigStores(configstores.NewStoreFactory("mock", f)) + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_initHellos(t *testing.T) { + t.Run("init success", func(t *testing.T) { + mockHello := mock.NewMockHelloService(gomock.NewController(t)) + mockHello.EXPECT().Init(gomock.Any()).Return(nil) + f := func() hello.HelloService { + return mockHello + } + + cfg := &MosnRuntimeConfig{ + HelloServiceManagement: map[string]hello.HelloConfig{ + "mock": {}, + }, + } + m := NewMosnRuntime(cfg) + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + err := m.initHellos(hello.NewHelloFactory("mock", f)) + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_initSequencers(t *testing.T) { + t.Run("init success", func(t *testing.T) { + mockStore := mock_sequencer.NewMockStore(gomock.NewController(t)) + mockStore.EXPECT().Init(gomock.Any()).Return(nil) + f := func() sequencer.Store { + return mockStore + } + + cfg := &MosnRuntimeConfig{ + SequencerManagement: map[string]sequencer.Config{ + "mock": {}, + }, + } + m := NewMosnRuntime(cfg) + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + err := m.initSequencers(msequencer.NewFactory("mock", f)) + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_initLocks(t *testing.T) { + t.Run("init success", func(t *testing.T) { + mockLockStore := mock_lock.NewMockLockStore(gomock.NewController(t)) + mockLockStore.EXPECT().Init(gomock.Any()).Return(nil) + f := func() lock.LockStore { + return mockLockStore + } + + cfg := &MosnRuntimeConfig{ + LockManagement: map[string]lock.Config{ + "mock": {}, + }, + } + m := NewMosnRuntime(cfg) + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + err := m.initLocks(mlock.NewFactory("mock", f)) + assert.Nil(t, err) + }) +} + +func TestMosnRuntime_publishMessageGRPC(t *testing.T) { + t.Run("publish success", func(t *testing.T) { + subResp := &runtimev1pb.TopicEventResponse{ + Status: runtimev1pb.TopicEventResponse_SUCCESS, + } + // init grpc server + mockAppCallbackServer := mock_appcallback.NewMockAppCallbackServer(gomock.NewController(t)) + mockAppCallbackServer.EXPECT().OnTopicEvent(gomock.Any(), gomock.Any()).Return(subResp, nil) + + lis := bufconn.Listen(1024 * 1024) + s := rawGRPC.NewServer() + runtimev1pb.RegisterAppCallbackServer(s, mockAppCallbackServer) + go func() { + s.Serve(lis) + }() + + // init callback client + callbackClient, err := rawGRPC.DialContext(context.Background(), "bufnet", rawGRPC.WithInsecure(), rawGRPC.WithContextDialer(func(ctx context.Context, s string) (net.Conn, error) { + return lis.Dial() + })) + assert.Nil(t, err) + + cloudEvent := map[string]interface{}{ + pubsub.IDField: "id", + pubsub.SourceField: "source", + pubsub.DataContentTypeField: "content-type", + pubsub.TypeField: "type", + pubsub.SpecVersionField: "v1.0.0", + pubsub.DataBase64Field: "bGF5b3R0bw==", + } + + data, err := json.Marshal(cloudEvent) + assert.Nil(t, err) + + msg := &pubsub.NewMessage{ + Data: data, + Topic: "layotto", + Metadata: make(map[string]string), + } + + cfg := &MosnRuntimeConfig{} + m := NewMosnRuntime(cfg) + m.errInt = func(err error, format string, args ...interface{}) { + log.DefaultLogger.Errorf("[runtime] occurs an error: "+err.Error()+", "+format, args...) + } + m.AppCallbackConn = callbackClient + m.json = jsoniter.ConfigFastest + err = m.publishMessageGRPC(context.Background(), msg) + assert.Nil(t, err) + }) +} diff --git a/pkg/wasm/factory.go b/pkg/wasm/factory.go index 927cd796f6..2d14653e4c 100644 --- a/pkg/wasm/factory.go +++ b/pkg/wasm/factory.go @@ -74,6 +74,7 @@ func createProxyWasmFilterFactory(conf map[string]interface{}) (api.StreamFilter log.DefaultLogger.Errorf("[proxywasm][factory] createProxyWasmFilterFactory fail to add plugin, err: %v", err) return nil, err } + addWatchFile(config, pluginName) } else { pluginName = config.FromWasmPlugin } diff --git a/pkg/wasm/watcher.go b/pkg/wasm/watcher.go new file mode 100644 index 0000000000..a476150bf9 --- /dev/null +++ b/pkg/wasm/watcher.go @@ -0,0 +1,147 @@ +package wasm + +import ( + "os" + "path/filepath" + "strings" + + v2 "mosn.io/mosn/pkg/config/v2" + "mosn.io/mosn/pkg/log" + "mosn.io/mosn/pkg/wasm" + + "github.com/fsnotify/fsnotify" +) + +var ( + watcher *fsnotify.Watcher + configs = make(map[string]*filterConfig) + pluginNames = make(map[string]string) +) + +func init() { + var err error + watcher, err = fsnotify.NewWatcher() + if err != nil { + log.DefaultLogger.Errorf("[proxywasm] [watcher] init fail to create watcher: %v", err) + return + } + go runWatcher() +} + +func runWatcher() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + log.DefaultLogger.Errorf("[proxywasm] [watcher] runWatcher exit") + return + } + log.DefaultLogger.Debugf("[proxywasm] [watcher] runWatcher got event, %s", event) + + if pathIsWasmFile(event.Name) { + if event.Op&fsnotify.Chmod == fsnotify.Chmod || + event.Op&fsnotify.Rename == fsnotify.Rename { + continue + } else if event.Op&fsnotify.Remove == fsnotify.Remove { + // rewatch the file if it exists + // remove this file then nename other file to this name will cause this case + if fileExist(event.Name) { + _ = watcher.Add(event.Name) + } + continue + } else if event.Op&fsnotify.Create == fsnotify.Create { + if fileExist(event.Name) { + _ = watcher.Add(event.Name) + } + } + reloadWasm(event.Name) + } + case err, ok := <-watcher.Errors: + if !ok { + log.DefaultLogger.Errorf("[proxywasm] [watcher] runWatcher exit") + return + } + log.DefaultLogger.Errorf("[proxywasm] [watcher] runWatcher got errors, err: %v", err) + } + } +} + +func addWatchFile(cfg *filterConfig, pluginName string) { + path := cfg.VmConfig.Path + if err := watcher.Add(path); err != nil { + log.DefaultLogger.Errorf("[proxywasm] [watcher] addWatchFile fail to watch wasm file, err: %v", err) + return + } + + dir := filepath.Dir(path) + if err := watcher.Add(dir); err != nil { + log.DefaultLogger.Errorf("[proxywasm] [watcher] addWatchFile fail to watch wasm dir, err: %v", err) + return + } + + configs[path] = cfg + pluginNames[path] = pluginName + log.DefaultLogger.Infof("[proxywasm] [watcher] addWatchFile start to watch wasm file and its dir: %s", path) +} + +func reloadWasm(fullPath string) { + found := false + + for path, config := range configs { + if strings.HasSuffix(fullPath, path) { + found = true + pluginName := pluginNames[path] + + err := wasm.GetWasmManager().UninstallWasmPluginByName(pluginName) + if err != nil { + log.DefaultLogger.Errorf("[proxywasm] [watcher] reloadWasm fail to uninstall plugin, err: %v", err) + } + + v2Config := v2.WasmPluginConfig{ + PluginName: pluginName, + VmConfig: config.VmConfig, + InstanceNum: config.InstanceNum, + } + err = wasm.GetWasmManager().AddOrUpdateWasm(v2Config) + if err != nil { + log.DefaultLogger.Errorf("[proxywasm] [watcher] reloadWasm fail to add plugin, err: %v", err) + return + } + + pw := wasm.GetWasmManager().GetWasmPluginWrapperByName(pluginName) + if pw == nil { + log.DefaultLogger.Errorf("[proxywasm] [watcher] reloadWasm plugin not found") + return + } + + factory := &FilterConfigFactory{ + pluginName: pluginName, + config: config, + } + pw.RegisterPluginHandler(factory) + + log.DefaultLogger.Infof("[proxywasm] [watcher] reloadWasm reload wasm success: %s", path) + } + } + + if !found { + log.DefaultLogger.Errorf("[proxywasm] [watcher] reloadWasm WasmPluginConfig not found: %s", fullPath) + } +} + +func fileExist(file string) bool { + _, err := os.Stat(file) + if err != nil && !os.IsExist(err) { + return false + } + return true +} + +func pathIsWasmFile(fullPath string) bool { + for path, _ := range configs { + if strings.HasSuffix(fullPath, path) { + return true + } + } + return false +}