diff --git a/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/action.golden b/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/action.golden new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/action.golden @@ -0,0 +1 @@ +{} diff --git a/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/introspect.golden b/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/introspect.golden new file mode 100755 index 0000000..f7765d2 --- /dev/null +++ b/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/introspect.golden @@ -0,0 +1 @@ +{"me":"https://user.example.net/","client_id":"https://app.example.com/","scope":"create update delete","exp":1632443647,"iat":1632443147,"active":true} diff --git a/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/revocation.golden b/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/revocation.golden new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/internal/token/delivery/http/testdata/TestHandler_ServeHTTP/revocation.golden @@ -0,0 +1 @@ +{} diff --git a/internal/token/delivery/http/token_http_test.go b/internal/token/delivery/http/token_http_test.go index 7a1776c..8b5bd37 100644 --- a/internal/token/delivery/http/token_http_test.go +++ b/internal/token/delivery/http/token_http_test.go @@ -1,140 +1,102 @@ package http_test import ( - "bytes" - "context" - "encoding/json" - "io" "net/http" "net/http/httptest" "strings" "testing" + "time" "source.toby3d.me/toby3d/auth/internal/common" "source.toby3d.me/toby3d/auth/internal/domain" - "source.toby3d.me/toby3d/auth/internal/profile" - profilerepo "source.toby3d.me/toby3d/auth/internal/profile/repository/memory" - "source.toby3d.me/toby3d/auth/internal/session" - sessionrepo "source.toby3d.me/toby3d/auth/internal/session/repository/memory" + "source.toby3d.me/toby3d/auth/internal/domain/scope" "source.toby3d.me/toby3d/auth/internal/token" delivery "source.toby3d.me/toby3d/auth/internal/token/delivery/http" - tokenrepo "source.toby3d.me/toby3d/auth/internal/token/repository/memory" - tokenucase "source.toby3d.me/toby3d/auth/internal/token/usecase" + testutil "source.toby3d.me/toby3d/auth/internal/util/testing" ) type Dependencies struct { - client *http.Client config *domain.Config - profiles profile.Repository - sessions session.Repository token *domain.Token - tokens token.Repository tokenService token.UseCase + profile *domain.Profile } -/* TODO(toby3d) -func TestExchange(t *testing.T) { - t.Parallel() -} -*/ - -func TestIntrospection(t *testing.T) { +func TestHandler_ServeHTTP(t *testing.T) { t.Parallel() deps := NewDependencies(t) - req := httptest.NewRequest(http.MethodPost, "https://app.example.com/introspect", - strings.NewReader("token="+deps.token.AccessToken)) - req.Header.Set(common.HeaderAccept, common.MIMEApplicationJSON) - req.Header.Set(common.HeaderContentType, common.MIMEApplicationForm) + for name, tc := range map[string]struct { + body string + target string + }{ + "introspect": { + target: "https://app.example.com/introspect", + body: `token=` + deps.token.AccessToken, + }, + "revocation": { + target: "https://app.example.com/revocation", + body: `token=` + deps.token.AccessToken, + }, + "action": { + target: "https://app.example.com/token", + body: `action=revoke&token=` + deps.token.AccessToken, + }, + } { + name, tc := name, tc - w := httptest.NewRecorder() - delivery.NewHandler(deps.tokenService, *deps.config). - ServeHTTP(w, req) + t.Run(name, func(t *testing.T) { + t.Parallel() - resp := w.Result() + req := httptest.NewRequest(http.MethodPost, tc.target, strings.NewReader(tc.body)) + req.Header.Set(common.HeaderAccept, common.MIMEApplicationJSON) + req.Header.Set(common.HeaderContentType, common.MIMEApplicationForm) - if result := resp.StatusCode; result != http.StatusOK { - t.Errorf("%s %s = %d, want %d", req.Method, req.RequestURI, result, http.StatusOK) - } + w := httptest.NewRecorder() + delivery.NewHandler(deps.tokenService, *deps.config).ServeHTTP(w, req) - result := new(delivery.TokenIntrospectResponse) - if err := json.NewDecoder(resp.Body).Decode(result); err != nil { - t.Fatal(err) - } + resp := w.Result() - deps.token.AccessToken = "" + if resp.StatusCode != http.StatusOK { + t.Errorf("%s %s = %d, want %d", req.Method, req.RequestURI, resp.StatusCode, + http.StatusOK) + } - if result.ClientID != deps.token.ClientID.String() || - result.Me != deps.token.Me.String() || - result.Scope != deps.token.Scope.String() { - t.Errorf("%s %s = %+v, want %+v", req.Method, req.RequestURI, result, deps.token) - } -} - -func TestRevocation(t *testing.T) { - t.Parallel() - - deps := NewDependencies(t) - - req := httptest.NewRequest(http.MethodPost, "https://app.example.com/revocation", - strings.NewReader(`token=`+deps.token.AccessToken)) - req.Header.Set(common.HeaderContentType, common.MIMEApplicationForm) - req.Header.Set(common.HeaderAccept, common.MIMEApplicationJSON) - - w := httptest.NewRecorder() - delivery.NewHandler(deps.tokenService, *deps.config). - ServeHTTP(w, req) - - resp := w.Result() - - body, err := io.ReadAll(resp.Body) - if err != nil { - t.Fatal(err) - } - - if resp.StatusCode != http.StatusOK { - t.Errorf("%s %s = %d, want %d", req.Method, req.RequestURI, resp.StatusCode, http.StatusOK) - } - - expBody := []byte("{}") //nolint:ifshort - if result := bytes.TrimSpace(body); !bytes.Equal(result, expBody) { - t.Errorf("%s %s = %s, want %s", req.Method, req.RequestURI, result, expBody) - } - - result, err := deps.tokens.Get(context.Background(), deps.token.AccessToken) - if err != nil { - t.Fatal(err) - } - - if result.String() != deps.token.String() { - t.Errorf("Get(%+v) = %s, want %s", deps.token.AccessToken, result, deps.token) + testutil.GoldenEqual(t, resp.Body) + }) } } func NewDependencies(tb testing.TB) Dependencies { tb.Helper() - client := new(http.Client) + // WARN(toby3d): clients MUST NOT expect what any IndieAuth tokens is + // JWT or something hackable. It can be anything in string + // representation. Used static generated random data for safe golden + // output comparing. + tkn := &domain.Token{ + CreatedAt: time.Unix(1632443147, 0), + Expiry: time.Unix(1632443647, 0), + ClientID: *domain.TestClientID(tb, "https://app.example.com/"), + Me: *domain.TestMe(tb, "https://user.example.net/"), + AccessToken: "BKIt4SVoUDqEpJtUhIONc2plu3iorUYy", + RefreshToken: "", + Scope: domain.Scopes{ + scope.Create, + scope.Update, + scope.Delete, + }, + } + config := domain.TestConfig(tb) - token := domain.TestToken(tb) - profiles := profilerepo.NewMemoryProfileRepository() - sessions := sessionrepo.NewMemorySessionRepository(*config) - tokens := tokenrepo.NewMemoryTokenRepository() - tokenService := tokenucase.NewTokenUseCase(tokenucase.Config{ - Config: *config, - Profiles: profiles, - Sessions: sessions, - Tokens: tokens, - }) + profile := domain.TestProfile(tb) + tokenService := token.NewStubTokenUseCase(tkn, profile, nil) return Dependencies{ - client: client, + profile: profile, + token: tkn, config: config, - profiles: profiles, - sessions: sessions, - token: token, - tokens: tokens, tokenService: tokenService, } }