diff --git a/router/further_dealer_test.go b/router/further_dealer_test.go index fb4399e1..49634e94 100644 --- a/router/further_dealer_test.go +++ b/router/further_dealer_test.go @@ -5,8 +5,6 @@ package router_test import ( "context" "encoding/json" - _ "errors" - _ "fmt" "testing" "time" @@ -17,6 +15,8 @@ import ( "github.com/gammazero/nexus/wamp" ) +// unfortunately we have to redo code from dealer_test... + var ( debug bool logger stdlog.StdLog @@ -117,13 +117,116 @@ func TestPreProcessDecoratorErrorResult(t *testing.T) { // Trigger preprocess decorator rsp, err := caller.Call(ctx, "foo.test.bar.error", nil, nil, nil, "") + rspp, _ := json.MarshalIndent(rsp, "", " ") + t.Logf("rsp is: %s\n", rspp) if err == nil { - // FIXME: this should return an error message to the caller. Instead it returns an error message nested into a response message. - t.Errorf("Expected an ERROR, got %v\n", rsp) + t.Fatalf("Expected an ERROR, got %v\n", rsp) } t.Logf("Got error: %v\n", err) } +func TestPreProcessDecoratorOrder(t *testing.T) { + router, _ := newTestRouter() + callee, _ := newTestClient(router) + decoratee, _ := newTestClient(router) + caller, _ := newTestClient(router) + ctx := context.Background() + done := make(chan string, 3) + + // test pre-process decorators with order. + handlerFooBar := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + return &client.InvokeResult{} + } + + decoratorHandler := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + // handler should be called first, as associated decorator has the smaller order number. + t.Log("Called decorator handler, order: 0.") + done <- "one" + return &client.InvokeResult{} + } + decoratorHandler2 := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + // handler should be called second, as associated decorator has the larger order number. + t.Log("Called decorator handler, order: 1.") + done <- "two" + return &client.InvokeResult{} + } + decoratorHandler3 := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + // handler should be called third, as associated decorator has the larger order number. + t.Log("Called decorator handler, order: 2.") + done <- "three" + return &client.InvokeResult{} + } + + // Register target URI + if err := callee.Register("foo.test.bar.order", handlerFooBar, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Register handler URI3 + if err := decoratee.Register("decoratortest.handlerURI.three", decoratorHandler3, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + // Register handler URI1 + if err := decoratee.Register("decoratortest.handlerURI.one", decoratorHandler, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + // Register handler URI2 + if err := decoratee.Register("decoratortest.handlerURI.two", decoratorHandler2, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Add preprocess decorator2 + args := wamp.List{ + "preprocess", + "foo.test.bar.order", + "exact", + "decoratortest.handlerURI.two", + 1, + "sync"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + // Add preprocess decorator1 + args = wamp.List{ + "preprocess", + "foo.test.bar.order", + "exact", + "decoratortest.handlerURI.one", + 0, + "sync"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + // Add preprocess decorator3 + args = wamp.List{ + "preprocess", + "foo.test.bar.order", + "exact", + "decoratortest.handlerURI.three", + 2, + "sync"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + + // Trigger preprocess decorators + rsp, err := caller.Call(ctx, "foo.test.bar.order", nil, nil, nil, "") + rspp, _ := json.MarshalIndent(rsp, "", " ") + t.Logf("rsp is: %s\n", rspp) + if err != nil { + t.Fatalf("Error: %v\n", err) + } + if <-done != "one" { + t.Fatal("Error: wrong order") + } + if <-done != "two" { + t.Fatal("Error: wrong order") + } + if <-done != "three" { + t.Fatal("Error: wrong order") + } +} + func TestPreProcessDecoratorEmptyResult(t *testing.T) { router, _ := newTestRouter() callee, _ := newTestClient(router) @@ -142,7 +245,6 @@ func TestPreProcessDecoratorEmptyResult(t *testing.T) { t.Log("Running decoratorHandler") // returning nothing: the call should be processed as usual return &client.InvokeResult{} - // return nil } // Register old target URI @@ -179,7 +281,7 @@ func TestPreProcessDecoratorEmptyResult(t *testing.T) { done <- false }() if !<-done { - t.Error("Preprocess Decorator: HandlerFooBar not called after 5 seconds!") + t.Fatal("Preprocess Decorator: HandlerFooBar not called after 5 seconds!") } } @@ -256,8 +358,7 @@ func TestPreProcessDecoratorRedirectResult(t *testing.T) { done <- false }() if !<-done { - // FIXME: This should redirect the Call to the target URI "test.rewrite.URI". Instead it returns the new call to the caller, again as a nested call. - t.Error("Preprocess Decorator: Call not redirected after 5 seconds!") + t.Fatal("Preprocess Decorator: Call not redirected after 5 seconds!") } } @@ -316,6 +417,320 @@ func TestPreProcessDecoratorAsync(t *testing.T) { done <- false }() if !<-done { - t.Error("Preprocess Decorator: HandlerFooBar not called after 5 seconds!") + t.Fatal("Preprocess Decorator: HandlerFooBar not called after 5 seconds!") + } +} + +func TestPreProcessDecoratorWildcard(t *testing.T) { + router, _ := newTestRouter() + callee, _ := newTestClient(router) + decoratee, _ := newTestClient(router) + caller, _ := newTestClient(router) + ctx := context.Background() + done := make(chan bool, 1) + + handlerFooBar := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + return &client.InvokeResult{} + } + + decoratorHandler := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + t.Log("Running decoratorHandler") + done <- true + // returning nothing: the call should be processed as usual + return &client.InvokeResult{} + // return nil + } + + // Register target URI + if err := callee.Register("foo.test.bar.nothing", handlerFooBar, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Register handler URI + if err := decoratee.Register("decoratortest.handlerURI.nothing", decoratorHandler, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Add preprocess decorator + args := wamp.List{ + "preprocess", + "foo.test..nothing", + "wildcard", + "decoratortest.handlerURI.nothing", + 0, + "sync"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + + // Trigger preprocess decorator + rsp, err := caller.Call(ctx, "foo.test.bar.nothing", nil, nil, nil, "") + if err != nil { + t.Fatalf("Error calling preprocess decorator: %v\n", err) + } + rspp, _ := json.MarshalIndent(rsp, "", " ") + t.Logf("rsp is: %s\n", rspp) + go func() { + time.Sleep(5 * time.Second) + done <- false + }() + if !<-done { + t.Fatal("Preprocess Decorator: Decorator not called after 5 seconds!") + } +} + +func TestPreProcessDecoratorPrefix(t *testing.T) { + router, _ := newTestRouter() + callee, _ := newTestClient(router) + decoratee, _ := newTestClient(router) + caller, _ := newTestClient(router) + ctx := context.Background() + done := make(chan bool, 1) + + handlerFooBar := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + return &client.InvokeResult{} + } + + decoratorHandler := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + t.Log("Running decoratorHandler") + done <- true + // returning nothing: the call should be processed as usual + return &client.InvokeResult{} + // return nil + } + + // Register target URI + if err := callee.Register("foo.test.bar.nothing", handlerFooBar, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Register handler URI + if err := decoratee.Register("decoratortest.handlerURI.nothing", decoratorHandler, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Add preprocess decorator + args := wamp.List{ + "preprocess", + "foo.test", + "prefix", + "decoratortest.handlerURI.nothing", + 0, + "sync"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + + // Trigger preprocess decorator + rsp, err := caller.Call(ctx, "foo.test.bar.nothing", nil, nil, nil, "") + if err != nil { + t.Fatalf("Error calling preprocess decorator: %v\n", err) + } + rspp, _ := json.MarshalIndent(rsp, "", " ") + t.Logf("rsp is: %s\n", rspp) + go func() { + time.Sleep(5 * time.Second) + done <- false + }() + if !<-done { + t.Fatal("Preprocess Decorator: Decorator not called after 5 seconds!") + } +} + +func TestPreProcessDecoratorCall(t *testing.T) { + router, _ := newTestRouter() + callee, _ := newTestClient(router) + decoratee, _ := newTestClient(router) + caller, _ := newTestClient(router) + ctx := context.Background() + done := make(chan bool, 1) + + handlerFooBar := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + return &client.InvokeResult{ + Args: wamp.List{details}, + } + } + + decoratorHandler := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + t.Log("Running decoratorHandler") + returnInv := serialize.WampMessageToList(&wamp.Invocation{ + Request: args[0].(*wamp.Invocation).Request, + Registration: wamp.GlobalID(), + Details: wamp.Dict{"Test": true}, + Arguments: wamp.List{}, + ArgumentsKw: wamp.Dict{}, + }) + done <- true + return &client.InvokeResult{ + Args: wamp.List{returnInv}, + } + } + + // Register target URI + if err := callee.Register("foo.test.bar.nothing", handlerFooBar, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Register handler URI + if err := decoratee.Register("decoratortest.handlerURI.nothing", decoratorHandler, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Add precall decorator + args := wamp.List{ + "precall", + "foo.test.bar.nothing", + "exact", + "decoratortest.handlerURI.nothing", + 0, + "sync"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + + // Trigger precall decorator + rsp, err := caller.Call(ctx, "foo.test.bar.nothing", nil, nil, nil, "") + if err != nil { + t.Fatalf("Error calling preprocess decorator: %v\n", err) + } + dict, ok := wamp.AsDict(rsp.Arguments[0]) + if !ok || dict["Test"] != true { + t.Fatalf("Error changing Invocation Message!") + } + rspp, _ := json.MarshalIndent(rsp, "", " ") + t.Logf("rsp is: %s\n", rspp) + go func() { + time.Sleep(5 * time.Second) + done <- false + }() + if !<-done { + t.Fatal("Preprocess Decorator: Decorator not called after 5 seconds!") + } +} + +func TestPreProcessDecoratorCallMod(t *testing.T) { + router, _ := newTestRouter() + callee, _ := newTestClient(router) + decoratee, _ := newTestClient(router) + caller, _ := newTestClient(router) + ctx := context.Background() + done := make(chan bool, 1) + + handlerFooBar := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + return &client.InvokeResult{ + Args: wamp.List{details}, + } + } + + decoratorHandler := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + t.Log("Running decoratorHandler") + returnInv := serialize.WampMessageToList(&wamp.Invocation{ + Request: args[0].(*wamp.Invocation).Request, + Registration: wamp.GlobalID(), + Details: wamp.Dict{"Test": true}, + Arguments: wamp.List{}, + ArgumentsKw: wamp.Dict{}, + }) + done <- true + return &client.InvokeResult{ + Args: wamp.List{returnInv}, + } + } + + // Register target URI + if err := callee.Register("foo.test.bar.nothing", handlerFooBar, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Register handler URI + if err := decoratee.Register("decoratortest.handlerURI.nothing", decoratorHandler, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Add precall decorator + args := wamp.List{ + "precall", + "foo.test.bar.nothing", + "exact", + "decoratortest.handlerURI.nothing", + 0, + "sync"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + + // Trigger precall decorator + rsp, err := caller.Call(ctx, "foo.test.bar.nothing", nil, nil, nil, "") + if err != nil { + t.Fatalf("Error calling preprocess decorator: %v\n", err) + } + dict, ok := wamp.AsDict(rsp.Arguments[0]) + if !ok || dict["Test"] != true { + t.Fatalf("Error changing Invocation Message!") + } + rspp, _ := json.MarshalIndent(rsp, "", " ") + t.Logf("rsp is: %s\n", rspp) + go func() { + time.Sleep(5 * time.Second) + done <- false + }() + if !<-done { + t.Fatal("Preprocess Decorator: Decorator not called after 5 seconds!") + } +} + +func TestPreProcessDecoratorCallAsync(t *testing.T) { + router, _ := newTestRouter() + callee, _ := newTestClient(router) + decoratee, _ := newTestClient(router) + caller, _ := newTestClient(router) + ctx := context.Background() + done := make(chan bool, 1) + + handlerFooBar := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + return &client.InvokeResult{} + } + + decoratorHandler := func(ctx context.Context, args wamp.List, kwargs, details wamp.Dict) *client.InvokeResult { + t.Log("Running decoratorHandler") + done <- true + return &client.InvokeResult{} + } + + // Register target URI + if err := callee.Register("foo.test.bar.nothing", handlerFooBar, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Register handler URI + if err := decoratee.Register("decoratortest.handlerURI.nothing", decoratorHandler, nil); err != nil { + t.Fatalf("failed to register procedure: %v\n", err) + } + + // Add precall decorator + args := wamp.List{ + "precall", + "foo.test.bar.nothing", + "exact", + "decoratortest.handlerURI.nothing", + 0, + "async"} + if _, err := decoratee.Call(ctx, "wamp.decorator.add", nil, args, nil, ""); err != nil { + t.Fatalf("Error calling wamp.decorator.add: %v\n", err) + } + + // Trigger precall decorator + rsp, err := caller.Call(ctx, "foo.test.bar.nothing", nil, nil, nil, "") + if err != nil { + t.Fatalf("Error calling preprocess decorator: %v\n", err) + } + rspp, _ := json.MarshalIndent(rsp, "", " ") + t.Logf("rsp is: %s\n", rspp) + go func() { + time.Sleep(5 * time.Second) + done <- false + }() + if !<-done { + t.Fatal("Preprocess Decorator: Decorator not called after 5 seconds!") } }