// Copyright 2020 Kentaro Hibino. All rights reserved. // Use of this source code is governed by a MIT license // that can be found in the LICENSE file. package asynq import ( "context" "testing" "github.com/google/go-cmp/cmp" ) var called string // identity of the handler that was called. var invoked []string // list of middlewares in the order they were invoked. // makeFakeHandler returns a handler that updates the global called variable // to the given identity. func makeFakeHandler(identity string) Handler { return HandlerFunc(func(ctx context.Context, t *Task) error { called = identity return nil }) } // makeFakeMiddleware returns a middleware function that appends the given identity //to the global invoked slice. func makeFakeMiddleware(identity string) MiddlewareFunc { return func(next Handler) Handler { return HandlerFunc(func(ctx context.Context, t *Task) error { invoked = append(invoked, identity) return next.ProcessTask(ctx, t) }) } } // A list of pattern, handler pair that is registered with mux. var serveMuxRegister = []struct { pattern string h Handler }{ {"email:", makeFakeHandler("default email handler")}, {"email:signup", makeFakeHandler("signup email handler")}, {"csv:export", makeFakeHandler("csv export handler")}, } var serveMuxTests = []struct { typename string // task's type name want string // identifier of the handler that should be called }{ {"email:signup", "signup email handler"}, {"csv:export", "csv export handler"}, {"email:daily", "default email handler"}, } func TestServeMux(t *testing.T) { mux := NewServeMux() for _, e := range serveMuxRegister { mux.Handle(e.pattern, e.h) } for _, tc := range serveMuxTests { called = "" // reset to zero value task := NewTask(tc.typename, nil) if err := mux.ProcessTask(context.Background(), task); err != nil { t.Fatal(err) } if called != tc.want { t.Errorf("%q handler was called for task %q, want %q to be called", called, task.Type(), tc.want) } } } func TestServeMuxRegisterNilHandler(t *testing.T) { defer func() { if err := recover(); err == nil { t.Error("expected call to mux.HandleFunc to panic") } }() mux := NewServeMux() mux.HandleFunc("email:signup", nil) } func TestServeMuxRegisterEmptyPattern(t *testing.T) { defer func() { if err := recover(); err == nil { t.Error("expected call to mux.HandleFunc to panic") } }() mux := NewServeMux() mux.Handle("", makeFakeHandler("email")) } func TestServeMuxRegisterDuplicatePattern(t *testing.T) { defer func() { if err := recover(); err == nil { t.Error("expected call to mux.HandleFunc to panic") } }() mux := NewServeMux() mux.Handle("email", makeFakeHandler("email")) mux.Handle("email", makeFakeHandler("email:default")) } var notFoundTests = []struct { typename string // task's type name }{ {"image:minimize"}, {"csv:"}, // registered patterns match the task's type prefix, not the other way around. } func TestServeMuxNotFound(t *testing.T) { mux := NewServeMux() for _, e := range serveMuxRegister { mux.Handle(e.pattern, e.h) } for _, tc := range notFoundTests { task := NewTask(tc.typename, nil) err := mux.ProcessTask(context.Background(), task) if err == nil { t.Errorf("ProcessTask did not return error for task %q, should return 'not found' error", task.Type()) } } } var middlewareTests = []struct { typename string // task's type name middlewares []string // middlewares to use. They should be called in this order. want string // identifier of the handler that should be called }{ {"email:signup", []string{"logging", "expiration"}, "signup email handler"}, {"csv:export", []string{}, "csv export handler"}, {"email:daily", []string{"expiration", "logging"}, "default email handler"}, } func TestServeMuxMiddlewares(t *testing.T) { for _, tc := range middlewareTests { mux := NewServeMux() for _, e := range serveMuxRegister { mux.Handle(e.pattern, e.h) } var mws []MiddlewareFunc for _, s := range tc.middlewares { mws = append(mws, makeFakeMiddleware(s)) } mux.Use(mws...) invoked = []string{} // reset to empty slice called = "" // reset to zero value task := NewTask(tc.typename, nil) if err := mux.ProcessTask(context.Background(), task); err != nil { t.Fatal(err) } if diff := cmp.Diff(invoked, tc.middlewares); diff != "" { t.Errorf("invoked middlewares were %v, want %v", invoked, tc.middlewares) } if called != tc.want { t.Errorf("%q handler was called for task %q, want %q to be called", called, task.Type(), tc.want) } } }