1

I have a middleware handler function and I would like to be able to write unit tests for this function. How might I go about doing this in GoLang? I would like to be able to verify when I call to add this middleware that the context will have the user id if successfully verifying jwt token or API key. And also confirm if the right error message gets sent if I have the wrong key for some reason.

Here is the function.

// Middleware wraps the request with auth middleware
func Middleware(path string, cfg *cfg.Server, orm *orm.ORM) gin.HandlerFunc {
    logger.Info("[Auth.Middleware] Applied to path: %s", path)
    return gin.HandlerFunc(func(c *gin.Context) {
        // Check and authenticate with api key
        if a, err := parseAPIKey(c, cfg); err == nil {
            user, err := findUserByAPIKey(a, orm)
            if err != nil {
                authError(c, ErrForbidden)
            }
            if user != nil {
                c.Request = addToContext(c, consts.ProjectContextKeys.UserCtxKey, user)
                c.Request = addUserIdToContext(c, user.ID)
                logger.Debug("User authenticated via api: %s", user.ID)
            }
            c.Next()
        } else {
            if err != ErrEmptyAPIKeyHeader {
                authError(c, err)
            } else {
                // Authenticate via JWT Token
                t, err := parseToken(c, cfg)
                if err != nil {
                    authError(c, err)
                } else {
                    if claims, ok := t.Claims.(jwt.MapClaims); ok {
                        if claims["exp"] != nil {
                            issuer := claims["iss"].(string)
                            userid := claims["jti"].(string)
                            email := claims["sub"].(string)
                            if claims["aud"] != nil {
                                audiences := claims["aud"]
                                logger.Warn("\n\naudiences: %s\n\n", audiences)
                            }
                            if claims["alg"] != nil {
                                algo := claims["alg"].(string)
                                logger.Warn("\n\nalgo: %s\n\n", algo)
                            }
                            if user, err := findUserByJWT(email, issuer, userid, orm); err != nil {
                                authError(c, ErrForbidden)
                            } else {
                                if user != nil {
                                    c.Request = addToContext(c, consts.ProjectContextKeys.UserCtxKey, user)
                                    c.Request = addUserIdToContext(c, user.ID)
                                    logger.Debug("User: %s", user.ID)
                                }
                                c.Next()
                            }
                        } else {
                            authError(c, ErrMissingExpField)
                        }
                    } else {
                        authError(c, err)
                    }
                }
            }
        }
    })
}

and here is me trying to figure out how to get started with the tests

func TestMiddleware(t *testing.T) {
    // TODO Need to update test
    t.Run("middleware api key from header", func(t *testing.T) {
        findUserByAPIKey = func(apiKey string, o *orm.ORM) (*models.User, error) {
            return &models.User{}, nil
        }
        parseAPIKey = func(c *gin.Context, sc *cfg.Server) (apiKey string, err error) {
            return "api_key", nil
        }
        svc := &cfg.Server{}
        Middleware("/test", svc, &orm.ORM{})
    })
    // TODO Need to update test
    t.Run("middleware jwt key from header", func(t *testing.T) {
        findUserByJWT = func(email, provider, userID string, o *orm.ORM) (*models.User, error) {
            return &models.User{}, nil
        }

        parseToken = func(c *gin.Context, sc *cfg.Server) (t *jwt.Token, err error) {
            return &jwt.Token{}, nil
        }
        svc := &cfg.Server{}
        Middleware("/test", svc, &orm.ORM{})
    })
}
rak1n
  • 671
  • 1
  • 8
  • 17
  • 1
    1. where exactly are you having difficulties? 2. I suggest refactoring your code to avoid too many nested `if-else`, it makes the code very hard to follow. 3. I suggest avoiding using global function variables to make your code testable – blackgreen Nov 09 '21 at 08:53
  • I was reading this https://www.myhatchpad.com/insight/mocking-techniques-for-go/ and that's one of the way it recommended mocking/faking it. But ya if you have a suggestion on how I can possible mock the functions that would be great. And I am considering breaking it off as you said it too much testing and making it hard to test also. I wanted to test if err returns the error response etc. or calls c.Next() if all is well. – rak1n Nov 09 '21 at 14:52
  • [here](https://stackoverflow.com/questions/66952761/how-to-unit-test-a-go-gin-handler-function) you can find some general info about how to test a gin handler. maybe you can have a look at that first, and then edit your question if you get stuck – blackgreen Nov 09 '21 at 14:56

0 Answers0