package api import ( "fmt" "net/http" "net/http/httptest" "testing" "time" "github.com/FernandoJVideira/simple_bank/internal/auth" "github.com/FernandoJVideira/simple_bank/internal/domain/role" mocksvc "github.com/FernandoJVideira/simple_bank/internal/service/mock" "github.com/FernandoJVideira/simple_bank/pkg/testutil" "github.com/gin-gonic/gin" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) func addAuth(t *testing.T, request *http.Request, tokenMaker auth.Maker, authType string, username string, role string, duration time.Duration) { token, payload, err := tokenMaker.CreateToken(username, role, duration) require.NoError(t, err) require.NotEmpty(t, payload) authorizationHeader := fmt.Sprintf("%s %s", authType, token) request.Header.Set(authHeaderKey, authorizationHeader) } func TestAuthMiddleware(t *testing.T) { username := testutil.RandomOwner() testRole := role.MemberRole testCases := []struct { name string setupAuth func(t *testing.T, request *http.Request, tokenMaker auth.Maker) checkResponse func(t *testing.T, recorder *httptest.ResponseRecorder) }{ { name: "OK", setupAuth: func(t *testing.T, request *http.Request, tokenMaker auth.Maker) { addAuth(t, request, tokenMaker, authTypeBearer, username, testRole, time.Minute) }, checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { require.Equal(t, http.StatusOK, recorder.Code) }, }, { name: "NoAuthorization", setupAuth: func(t *testing.T, request *http.Request, tokenMaker auth.Maker) { // Do not add any authorization header }, checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { require.Equal(t, http.StatusUnauthorized, recorder.Code) }, }, { name: "UnsupportedAuthType", setupAuth: func(t *testing.T, request *http.Request, tokenMaker auth.Maker) { addAuth(t, request, tokenMaker, "UnsupportedAuthType", username, testRole, time.Minute) }, checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { require.Equal(t, http.StatusUnauthorized, recorder.Code) }, }, { name: "InvalidAuthFormat", setupAuth: func(t *testing.T, request *http.Request, tokenMaker auth.Maker) { addAuth(t, request, tokenMaker, "", username, testRole, time.Minute) }, checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { require.Equal(t, http.StatusUnauthorized, recorder.Code) }, }, { name: "ExpiredAtToken", setupAuth: func(t *testing.T, request *http.Request, tokenMaker auth.Maker) { addAuth(t, request, tokenMaker, authTypeBearer, username, testRole, -time.Minute) }, checkResponse: func(t *testing.T, recorder *httptest.ResponseRecorder) { require.Equal(t, http.StatusUnauthorized, recorder.Code) }, }, } for i := range testCases { tc := testCases[i] t.Run(tc.name, func(t *testing.T) { authCtrl := gomock.NewController(t) defer authCtrl.Finish() authService := mocksvc.NewMockAuthService(authCtrl) s := newTestServer(t, nil, nil, nil, authService) authPath := "/auth" s.router.GET( authPath, authMiddleware(s.tokenMaker, []string{role.AdminRole, role.MemberRole}), func(ctx *gin.Context) { ctx.JSON(200, gin.H{}) }, ) recorder := httptest.NewRecorder() request, err := http.NewRequest(http.MethodGet, authPath, nil) require.NoError(t, err) tc.setupAuth(t, request, s.tokenMaker) s.router.ServeHTTP(recorder, request) tc.checkResponse(t, recorder) }) } }