♻️ Added dependencies helper in delivery layer tests

This commit is contained in:
Maxim Lebedev 2022-02-02 02:21:07 +05:00
parent af1ebed585
commit 3f565cb6b3
Signed by: toby3d
GPG Key ID: 1F14E25B7C119FC5
5 changed files with 217 additions and 124 deletions

View File

@ -7,58 +7,55 @@ import (
"testing" "testing"
"github.com/fasthttp/router" "github.com/fasthttp/router"
"github.com/fasthttp/session/v2"
"github.com/fasthttp/session/v2/providers/memory"
http "github.com/valyala/fasthttp" http "github.com/valyala/fasthttp"
"golang.org/x/text/language" "golang.org/x/text/language"
"golang.org/x/text/message" "golang.org/x/text/message"
"source.toby3d.me/website/indieauth/internal/auth"
delivery "source.toby3d.me/website/indieauth/internal/auth/delivery/http" delivery "source.toby3d.me/website/indieauth/internal/auth/delivery/http"
ucase "source.toby3d.me/website/indieauth/internal/auth/usecase" ucase "source.toby3d.me/website/indieauth/internal/auth/usecase"
"source.toby3d.me/website/indieauth/internal/client"
clientrepo "source.toby3d.me/website/indieauth/internal/client/repository/memory" clientrepo "source.toby3d.me/website/indieauth/internal/client/repository/memory"
clientucase "source.toby3d.me/website/indieauth/internal/client/usecase" clientucase "source.toby3d.me/website/indieauth/internal/client/usecase"
"source.toby3d.me/website/indieauth/internal/domain" "source.toby3d.me/website/indieauth/internal/domain"
profilerepo "source.toby3d.me/website/indieauth/internal/profile/repository/memory" profilerepo "source.toby3d.me/website/indieauth/internal/profile/repository/memory"
"source.toby3d.me/website/indieauth/internal/session"
sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory" sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory"
"source.toby3d.me/website/indieauth/internal/testing/httptest" "source.toby3d.me/website/indieauth/internal/testing/httptest"
userrepo "source.toby3d.me/website/indieauth/internal/user/repository/memory" userrepo "source.toby3d.me/website/indieauth/internal/user/repository/memory"
) )
//nolint: funlen type dependencies struct {
authService auth.UseCase
clients client.Repository
clientService client.UseCase
config *domain.Config
matcher language.Matcher
sessions session.Repository
store *sync.Map
}
func TestRender(t *testing.T) { func TestRender(t *testing.T) {
t.Parallel() t.Parallel()
provider, err := memory.New(memory.Config{}) deps := NewDependencies(t)
if err != nil {
t.Fatal(err)
}
s := session.New(session.NewDefaultConfig())
if err = s.SetProvider(provider); err != nil {
t.Fatal(err)
}
me := domain.TestMe(t, "https://user.example.net") me := domain.TestMe(t, "https://user.example.net")
client := domain.TestClient(t)
config := domain.TestConfig(t)
store := new(sync.Map)
user := domain.TestUser(t) user := domain.TestUser(t)
store.Store(path.Join(userrepo.DefaultPathPrefix, me.String()), user) client := domain.TestClient(t)
store.Store(path.Join(clientrepo.DefaultPathPrefix, client.ID.String()), client)
store.Store(path.Join(profilerepo.DefaultPathPrefix, me.String()), user.Profile)
router := router.New() deps.store.Store(path.Join(clientrepo.DefaultPathPrefix, client.ID.String()), client)
deps.store.Store(path.Join(profilerepo.DefaultPathPrefix, me.String()), user.Profile)
deps.store.Store(path.Join(userrepo.DefaultPathPrefix, me.String()), user)
r := router.New()
delivery.NewRequestHandler(delivery.NewRequestHandlerOptions{ delivery.NewRequestHandler(delivery.NewRequestHandlerOptions{
Clients: clientucase.NewClientUseCase(clientrepo.NewMemoryClientRepository(store)), Auth: deps.authService,
Config: config, Clients: deps.clientService,
Matcher: language.NewMatcher(message.DefaultCatalog.Languages()), Config: deps.config,
Auth: ucase.NewAuthUseCase( Matcher: deps.matcher,
sessionrepo.NewMemorySessionRepository(config, store), }).Register(r)
config,
),
}).Register(router)
httpClient, _, cleanup := httptest.New(t, router.Handler) httpClient, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup) t.Cleanup(cleanup)
uri := http.AcquireURI() uri := http.AcquireURI()
@ -97,3 +94,25 @@ func TestRender(t *testing.T) {
t.Errorf("GET %s = %s, want %s", uri.String(), result, expResult) t.Errorf("GET %s = %s, want %s", uri.String(), result, expResult)
} }
} }
func NewDependencies(tb testing.TB) dependencies {
tb.Helper()
config := domain.TestConfig(tb)
matcher := language.NewMatcher(message.DefaultCatalog.Languages())
store := new(sync.Map)
clients := clientrepo.NewMemoryClientRepository(store)
sessions := sessionrepo.NewMemorySessionRepository(config, store)
authService := ucase.NewAuthUseCase(sessions, config)
clientService := clientucase.NewClientUseCase(clients)
return dependencies{
authService: authService,
clients: clients,
clientService: clientService,
config: config,
matcher: matcher,
sessions: sessions,
store: store,
}
}

View File

@ -11,37 +11,47 @@ import (
delivery "source.toby3d.me/website/indieauth/internal/client/delivery/http" delivery "source.toby3d.me/website/indieauth/internal/client/delivery/http"
"source.toby3d.me/website/indieauth/internal/domain" "source.toby3d.me/website/indieauth/internal/domain"
"source.toby3d.me/website/indieauth/internal/session"
sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory" sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory"
"source.toby3d.me/website/indieauth/internal/testing/httptest" "source.toby3d.me/website/indieauth/internal/testing/httptest"
"source.toby3d.me/website/indieauth/internal/token"
tokenrepo "source.toby3d.me/website/indieauth/internal/token/repository/memory" tokenrepo "source.toby3d.me/website/indieauth/internal/token/repository/memory"
tokenucase "source.toby3d.me/website/indieauth/internal/token/usecase" tokenucase "source.toby3d.me/website/indieauth/internal/token/usecase"
) )
type dependencies struct {
client *domain.Client
config *domain.Config
matcher language.Matcher
sessions session.Repository
store *sync.Map
tokens token.Repository
tokenService token.UseCase
}
func TestRead(t *testing.T) { func TestRead(t *testing.T) {
t.Parallel() t.Parallel()
store := new(sync.Map) deps := NewDependencies(t)
config := domain.TestConfig(t)
router := router.New() r := router.New()
delivery.NewRequestHandler(delivery.NewRequestHandlerOptions{ delivery.NewRequestHandler(delivery.NewRequestHandlerOptions{
Client: domain.TestClient(t), Client: deps.client,
Config: config, Config: deps.config,
Matcher: language.NewMatcher(message.DefaultCatalog.Languages()), Matcher: deps.matcher,
Tokens: tokenucase.NewTokenUseCase(tokenrepo.NewMemoryTokenRepository(store), Tokens: deps.tokenService,
sessionrepo.NewMemorySessionRepository(config, store), config), }).Register(r)
}).Register(router)
client, _, cleanup := httptest.New(t, router.Handler) client, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup) t.Cleanup(cleanup)
const requestURI string = "https://app.example.com/" const requestURI string = "https://app.example.com/"
req, resp := httptest.NewRequest(http.MethodGet, requestURI, nil), http.AcquireResponse()
req := httptest.NewRequest(http.MethodGet, requestURI, nil) t.Cleanup(func() {
defer http.ReleaseRequest(req) http.ReleaseRequest(req)
http.ReleaseResponse(resp)
resp := http.AcquireResponse() })
defer http.ReleaseResponse(resp)
if err := client.Do(req, resp); err != nil { if err := client.Do(req, resp); err != nil {
t.Error(err) t.Error(err)
@ -51,3 +61,25 @@ func TestRead(t *testing.T) {
t.Errorf("GET %s = %d, want %d", requestURI, resp.StatusCode(), http.StatusOK) t.Errorf("GET %s = %d, want %d", requestURI, resp.StatusCode(), http.StatusOK)
} }
} }
func NewDependencies(tb testing.TB) dependencies {
tb.Helper()
client := domain.TestClient(tb)
config := domain.TestConfig(tb)
matcher := language.NewMatcher(message.DefaultCatalog.Languages())
store := new(sync.Map)
sessions := sessionrepo.NewMemorySessionRepository(config, store)
tokens := tokenrepo.NewMemoryTokenRepository(store)
tokenService := tokenucase.NewTokenUseCase(tokens, sessions, config)
return dependencies{
client: client,
config: config,
matcher: matcher,
sessions: sessions,
store: store,
tokens: tokens,
tokenService: tokenService,
}
}

View File

@ -20,12 +20,12 @@ func TestRequestHandler(t *testing.T) {
t.Cleanup(cleanup) t.Cleanup(cleanup)
const requestURL = "https://app.example.com/health" const requestURL = "https://app.example.com/health"
req, resp := httptest.NewRequest(http.MethodGet, requestURL, nil), http.AcquireResponse()
req := httptest.NewRequest(http.MethodGet, requestURL, nil) t.Cleanup(func() {
defer http.ReleaseRequest(req) http.ReleaseRequest(req)
http.ReleaseResponse(resp)
resp := http.AcquireResponse() })
defer http.ReleaseResponse(resp)
if err := client.Do(req, resp); err != nil { if err := client.Do(req, resp); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -12,44 +12,30 @@ import (
"source.toby3d.me/website/indieauth/internal/common" "source.toby3d.me/website/indieauth/internal/common"
"source.toby3d.me/website/indieauth/internal/domain" "source.toby3d.me/website/indieauth/internal/domain"
"source.toby3d.me/website/indieauth/internal/testing/httptest" "source.toby3d.me/website/indieauth/internal/testing/httptest"
"source.toby3d.me/website/indieauth/internal/ticket"
delivery "source.toby3d.me/website/indieauth/internal/ticket/delivery/http" delivery "source.toby3d.me/website/indieauth/internal/ticket/delivery/http"
ticketrepo "source.toby3d.me/website/indieauth/internal/ticket/repository/memory" ticketrepo "source.toby3d.me/website/indieauth/internal/ticket/repository/memory"
ucase "source.toby3d.me/website/indieauth/internal/ticket/usecase" ucase "source.toby3d.me/website/indieauth/internal/ticket/usecase"
) )
type dependencies struct {
client *http.Client
config *domain.Config
matcher language.Matcher
store *sync.Map
ticket *domain.Ticket
tickets ticket.Repository
ticketService ticket.UseCase
token *domain.Token
}
func TestUpdate(t *testing.T) { func TestUpdate(t *testing.T) {
t.Parallel() t.Parallel()
config := domain.TestConfig(t) deps := NewDependencies(t)
ticket := domain.TestTicket(t)
token := domain.TestToken(t)
userRouter := router.New()
// NOTE(toby3d): private resource
userRouter.GET(ticket.Resource.URL().EscapedPath(), func(ctx *http.RequestCtx) {
ctx.SuccessString(
common.MIMETextHTMLCharsetUTF8,
`<link rel="token_endpoint" href="https://auth.example.org/token">`,
)
})
// NOTE(toby3d): token endpoint
userRouter.POST("/token", func(ctx *http.RequestCtx) {
ctx.SuccessString(common.MIMEApplicationJSONCharsetUTF8, `{
"access_token": "`+token.AccessToken+`",
"me": "`+token.Me.String()+`",
"scope": "`+token.Scope.String()+`",
"token_type": "Bearer"
}`)
})
userClient, _, userCleanup := httptest.New(t, userRouter.Handler)
t.Cleanup(userCleanup)
r := router.New() r := router.New()
delivery.NewRequestHandler( delivery.NewRequestHandler(deps.ticketService, deps.matcher, deps.config).Register(r)
ucase.NewTicketUseCase(ticketrepo.NewMemoryTicketRepository(new(sync.Map), config), userClient, config),
language.NewMatcher(message.DefaultCatalog.Languages()), config,
).Register(r)
client, _, cleanup := httptest.New(t, r.Handler) client, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup) t.Cleanup(cleanup)
@ -57,9 +43,9 @@ func TestUpdate(t *testing.T) {
const requestURI string = "https://example.com/ticket" const requestURI string = "https://example.com/ticket"
req := httptest.NewRequest(http.MethodPost, requestURI, []byte( req := httptest.NewRequest(http.MethodPost, requestURI, []byte(
`ticket=`+ticket.Ticket+ `ticket=`+deps.ticket.Ticket+
`&resource=`+ticket.Resource.String()+ `&resource=`+deps.ticket.Resource.String()+
`&subject=`+ticket.Subject.String(), `&subject=`+deps.ticket.Subject.String(),
)) ))
defer http.ReleaseRequest(req) defer http.ReleaseRequest(req)
req.Header.SetContentType(common.MIMEApplicationForm) req.Header.SetContentType(common.MIMEApplicationForm)
@ -83,3 +69,46 @@ func TestUpdate(t *testing.T) {
t.Errorf("POST %s = nil, want something", requestURI) t.Errorf("POST %s = nil, want something", requestURI)
} }
} }
func NewDependencies(tb testing.TB) dependencies {
tb.Helper()
config := domain.TestConfig(tb)
matcher := language.NewMatcher(message.DefaultCatalog.Languages())
store := new(sync.Map)
ticket := domain.TestTicket(tb)
token := domain.TestToken(tb)
r := router.New()
// NOTE(toby3d): private resource
r.GET(ticket.Resource.URL().EscapedPath(), func(ctx *http.RequestCtx) {
ctx.SuccessString(common.MIMETextHTMLCharsetUTF8,
`<link rel="token_endpoint" href="https://auth.example.org/token">`)
})
// NOTE(toby3d): token endpoint
r.POST("/token", func(ctx *http.RequestCtx) {
ctx.SuccessString(common.MIMEApplicationJSONCharsetUTF8, `{
"access_token": "`+token.AccessToken+`",
"me": "`+token.Me.String()+`",
"scope": "`+token.Scope.String()+`",
"token_type": "Bearer"
}`)
})
client, _, cleanup := httptest.New(tb, r.Handler)
tb.Cleanup(cleanup)
tickets := ticketrepo.NewMemoryTicketRepository(store, config)
ticketService := ucase.NewTicketUseCase(tickets, client, config)
return dependencies{
client: client,
config: config,
matcher: matcher,
store: store,
ticket: ticket,
tickets: tickets,
ticketService: ticketService,
token: token,
}
}

View File

@ -12,15 +12,30 @@ import (
"source.toby3d.me/website/indieauth/internal/common" "source.toby3d.me/website/indieauth/internal/common"
"source.toby3d.me/website/indieauth/internal/domain" "source.toby3d.me/website/indieauth/internal/domain"
"source.toby3d.me/website/indieauth/internal/session"
sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory" sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory"
"source.toby3d.me/website/indieauth/internal/testing/httptest" "source.toby3d.me/website/indieauth/internal/testing/httptest"
"source.toby3d.me/website/indieauth/internal/ticket"
ticketrepo "source.toby3d.me/website/indieauth/internal/ticket/repository/memory" ticketrepo "source.toby3d.me/website/indieauth/internal/ticket/repository/memory"
ticketucase "source.toby3d.me/website/indieauth/internal/ticket/usecase" ticketucase "source.toby3d.me/website/indieauth/internal/ticket/usecase"
"source.toby3d.me/website/indieauth/internal/token"
delivery "source.toby3d.me/website/indieauth/internal/token/delivery/http" delivery "source.toby3d.me/website/indieauth/internal/token/delivery/http"
tokenrepo "source.toby3d.me/website/indieauth/internal/token/repository/memory" tokenrepo "source.toby3d.me/website/indieauth/internal/token/repository/memory"
tokenucase "source.toby3d.me/website/indieauth/internal/token/usecase" tokenucase "source.toby3d.me/website/indieauth/internal/token/usecase"
) )
type dependencies struct {
client *http.Client
config *domain.Config
sessions session.Repository
store *sync.Map
tickets ticket.Repository
ticketService ticket.UseCase
token *domain.Token
tokens token.Repository
tokenService token.UseCase
}
/* TODO(toby3d) /* TODO(toby3d)
func TestExchange(t *testing.T) { func TestExchange(t *testing.T) {
t.Parallel() t.Parallel()
@ -30,24 +45,10 @@ func TestExchange(t *testing.T) {
func TestVerification(t *testing.T) { func TestVerification(t *testing.T) {
t.Parallel() t.Parallel()
store := new(sync.Map) deps := NewDependencies(t)
config := domain.TestConfig(t)
token := domain.TestToken(t)
router := router.New() router := router.New()
// TODO(toby3d): provide tickets delivery.NewRequestHandler(deps.tokenService, deps.ticketService).Register(router)
delivery.NewRequestHandler(
tokenucase.NewTokenUseCase(
tokenrepo.NewMemoryTokenRepository(store),
sessionrepo.NewMemorySessionRepository(config, store),
config,
),
ticketucase.NewTicketUseCase(
ticketrepo.NewMemoryTicketRepository(store, config),
new(http.Client),
config,
),
).Register(router)
client, _, cleanup := httptest.New(t, router.Handler) client, _, cleanup := httptest.New(t, router.Handler)
t.Cleanup(cleanup) t.Cleanup(cleanup)
@ -57,7 +58,7 @@ func TestVerification(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, requestURL, nil) req := httptest.NewRequest(http.MethodGet, requestURL, nil)
defer http.ReleaseRequest(req) defer http.ReleaseRequest(req)
req.Header.Set(http.HeaderAccept, common.MIMEApplicationJSON) req.Header.Set(http.HeaderAccept, common.MIMEApplicationJSON)
token.SetAuthHeader(req) deps.token.SetAuthHeader(req)
resp := http.AcquireResponse() resp := http.AcquireResponse()
defer http.ReleaseResponse(resp) defer http.ReleaseResponse(resp)
@ -75,38 +76,24 @@ func TestVerification(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
token.AccessToken = "" deps.token.AccessToken = ""
if result.ClientID.String() != token.ClientID.String() || if result.ClientID.String() != deps.token.ClientID.String() ||
result.Me.String() != token.Me.String() || result.Me.String() != deps.token.Me.String() ||
result.Scope.String() != token.Scope.String() { result.Scope.String() != deps.token.Scope.String() {
t.Errorf("GET %s = %+v, want %+v", requestURL, result, token) t.Errorf("GET %s = %+v, want %+v", requestURL, result, deps.token)
} }
} }
func TestRevocation(t *testing.T) { func TestRevocation(t *testing.T) {
t.Parallel() t.Parallel()
config := domain.TestConfig(t) deps := NewDependencies(t)
store := new(sync.Map)
tokens := tokenrepo.NewMemoryTokenRepository(store)
accessToken := domain.TestToken(t)
router := router.New() r := router.New()
delivery.NewRequestHandler( delivery.NewRequestHandler(deps.tokenService, deps.ticketService).Register(r)
tokenucase.NewTokenUseCase(
tokens,
sessionrepo.NewMemorySessionRepository(config, store),
config,
),
ticketucase.NewTicketUseCase(
ticketrepo.NewMemoryTicketRepository(store, config),
new(http.Client),
config,
),
).Register(router)
client, _, cleanup := httptest.New(t, router.Handler) client, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup) t.Cleanup(cleanup)
const requestURL = "https://app.example.com/token" const requestURL = "https://app.example.com/token"
@ -116,7 +103,7 @@ func TestRevocation(t *testing.T) {
req.Header.Set(http.HeaderAccept, common.MIMEApplicationJSON) req.Header.Set(http.HeaderAccept, common.MIMEApplicationJSON)
req.Header.SetContentType(common.MIMEApplicationForm) req.Header.SetContentType(common.MIMEApplicationForm)
req.PostArgs().Set("action", domain.ActionRevoke.String()) req.PostArgs().Set("action", domain.ActionRevoke.String())
req.PostArgs().Set("token", accessToken.AccessToken) req.PostArgs().Set("token", deps.token.AccessToken)
resp := http.AcquireResponse() resp := http.AcquireResponse()
defer http.ReleaseResponse(resp) defer http.ReleaseResponse(resp)
@ -134,12 +121,38 @@ func TestRevocation(t *testing.T) {
t.Errorf("POST %s = %s, want %s", requestURL, result, expBody) t.Errorf("POST %s = %s, want %s", requestURL, result, expBody)
} }
result, err := tokens.Get(context.TODO(), accessToken.AccessToken) result, err := deps.tokens.Get(context.TODO(), deps.token.AccessToken)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if result.String() != accessToken.String() { if result.String() != deps.token.String() {
t.Errorf("Get(%+v) = %s, want %s", accessToken.AccessToken, result, accessToken) t.Errorf("Get(%+v) = %s, want %s", deps.token.AccessToken, result, deps.token)
}
}
func NewDependencies(tb testing.TB) dependencies {
tb.Helper()
client := new(http.Client)
config := domain.TestConfig(tb)
store := new(sync.Map)
token := domain.TestToken(tb)
sessions := sessionrepo.NewMemorySessionRepository(config, store)
tickets := ticketrepo.NewMemoryTicketRepository(store, config)
tokens := tokenrepo.NewMemoryTokenRepository(store)
ticketService := ticketucase.NewTicketUseCase(tickets, client, config)
tokenService := tokenucase.NewTokenUseCase(tokens, sessions, config)
return dependencies{
client: client,
config: config,
sessions: sessions,
store: store,
tickets: tickets,
ticketService: ticketService,
token: token,
tokens: tokens,
tokenService: tokenService,
} }
} }