♻️ 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"
"github.com/fasthttp/router"
"github.com/fasthttp/session/v2"
"github.com/fasthttp/session/v2/providers/memory"
http "github.com/valyala/fasthttp"
"golang.org/x/text/language"
"golang.org/x/text/message"
"source.toby3d.me/website/indieauth/internal/auth"
delivery "source.toby3d.me/website/indieauth/internal/auth/delivery/http"
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"
clientucase "source.toby3d.me/website/indieauth/internal/client/usecase"
"source.toby3d.me/website/indieauth/internal/domain"
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"
"source.toby3d.me/website/indieauth/internal/testing/httptest"
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) {
t.Parallel()
provider, err := memory.New(memory.Config{})
if err != nil {
t.Fatal(err)
}
s := session.New(session.NewDefaultConfig())
if err = s.SetProvider(provider); err != nil {
t.Fatal(err)
}
deps := NewDependencies(t)
me := domain.TestMe(t, "https://user.example.net")
client := domain.TestClient(t)
config := domain.TestConfig(t)
store := new(sync.Map)
user := domain.TestUser(t)
store.Store(path.Join(userrepo.DefaultPathPrefix, me.String()), user)
store.Store(path.Join(clientrepo.DefaultPathPrefix, client.ID.String()), client)
store.Store(path.Join(profilerepo.DefaultPathPrefix, me.String()), user.Profile)
client := domain.TestClient(t)
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{
Clients: clientucase.NewClientUseCase(clientrepo.NewMemoryClientRepository(store)),
Config: config,
Matcher: language.NewMatcher(message.DefaultCatalog.Languages()),
Auth: ucase.NewAuthUseCase(
sessionrepo.NewMemorySessionRepository(config, store),
config,
),
}).Register(router)
Auth: deps.authService,
Clients: deps.clientService,
Config: deps.config,
Matcher: deps.matcher,
}).Register(r)
httpClient, _, cleanup := httptest.New(t, router.Handler)
httpClient, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup)
uri := http.AcquireURI()
@ -97,3 +94,25 @@ func TestRender(t *testing.T) {
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"
"source.toby3d.me/website/indieauth/internal/domain"
"source.toby3d.me/website/indieauth/internal/session"
sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory"
"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"
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) {
t.Parallel()
store := new(sync.Map)
config := domain.TestConfig(t)
deps := NewDependencies(t)
router := router.New()
r := router.New()
delivery.NewRequestHandler(delivery.NewRequestHandlerOptions{
Client: domain.TestClient(t),
Config: config,
Matcher: language.NewMatcher(message.DefaultCatalog.Languages()),
Tokens: tokenucase.NewTokenUseCase(tokenrepo.NewMemoryTokenRepository(store),
sessionrepo.NewMemorySessionRepository(config, store), config),
}).Register(router)
Client: deps.client,
Config: deps.config,
Matcher: deps.matcher,
Tokens: deps.tokenService,
}).Register(r)
client, _, cleanup := httptest.New(t, router.Handler)
client, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup)
const requestURI string = "https://app.example.com/"
req, resp := httptest.NewRequest(http.MethodGet, requestURI, nil), http.AcquireResponse()
req := httptest.NewRequest(http.MethodGet, requestURI, nil)
defer http.ReleaseRequest(req)
resp := http.AcquireResponse()
defer http.ReleaseResponse(resp)
t.Cleanup(func() {
http.ReleaseRequest(req)
http.ReleaseResponse(resp)
})
if err := client.Do(req, resp); err != nil {
t.Error(err)
@ -51,3 +61,25 @@ func TestRead(t *testing.T) {
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)
const requestURL = "https://app.example.com/health"
req, resp := httptest.NewRequest(http.MethodGet, requestURL, nil), http.AcquireResponse()
req := httptest.NewRequest(http.MethodGet, requestURL, nil)
defer http.ReleaseRequest(req)
resp := http.AcquireResponse()
defer http.ReleaseResponse(resp)
t.Cleanup(func() {
http.ReleaseRequest(req)
http.ReleaseResponse(resp)
})
if err := client.Do(req, resp); err != nil {
t.Fatal(err)

View File

@ -12,44 +12,30 @@ import (
"source.toby3d.me/website/indieauth/internal/common"
"source.toby3d.me/website/indieauth/internal/domain"
"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"
ticketrepo "source.toby3d.me/website/indieauth/internal/ticket/repository/memory"
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) {
t.Parallel()
config := domain.TestConfig(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)
deps := NewDependencies(t)
r := router.New()
delivery.NewRequestHandler(
ucase.NewTicketUseCase(ticketrepo.NewMemoryTicketRepository(new(sync.Map), config), userClient, config),
language.NewMatcher(message.DefaultCatalog.Languages()), config,
).Register(r)
delivery.NewRequestHandler(deps.ticketService, deps.matcher, deps.config).Register(r)
client, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup)
@ -57,9 +43,9 @@ func TestUpdate(t *testing.T) {
const requestURI string = "https://example.com/ticket"
req := httptest.NewRequest(http.MethodPost, requestURI, []byte(
`ticket=`+ticket.Ticket+
`&resource=`+ticket.Resource.String()+
`&subject=`+ticket.Subject.String(),
`ticket=`+deps.ticket.Ticket+
`&resource=`+deps.ticket.Resource.String()+
`&subject=`+deps.ticket.Subject.String(),
))
defer http.ReleaseRequest(req)
req.Header.SetContentType(common.MIMEApplicationForm)
@ -83,3 +69,46 @@ func TestUpdate(t *testing.T) {
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/domain"
"source.toby3d.me/website/indieauth/internal/session"
sessionrepo "source.toby3d.me/website/indieauth/internal/session/repository/memory"
"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"
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"
tokenrepo "source.toby3d.me/website/indieauth/internal/token/repository/memory"
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)
func TestExchange(t *testing.T) {
t.Parallel()
@ -30,24 +45,10 @@ func TestExchange(t *testing.T) {
func TestVerification(t *testing.T) {
t.Parallel()
store := new(sync.Map)
config := domain.TestConfig(t)
token := domain.TestToken(t)
deps := NewDependencies(t)
router := router.New()
// TODO(toby3d): provide tickets
delivery.NewRequestHandler(
tokenucase.NewTokenUseCase(
tokenrepo.NewMemoryTokenRepository(store),
sessionrepo.NewMemorySessionRepository(config, store),
config,
),
ticketucase.NewTicketUseCase(
ticketrepo.NewMemoryTicketRepository(store, config),
new(http.Client),
config,
),
).Register(router)
delivery.NewRequestHandler(deps.tokenService, deps.ticketService).Register(router)
client, _, cleanup := httptest.New(t, router.Handler)
t.Cleanup(cleanup)
@ -57,7 +58,7 @@ func TestVerification(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, requestURL, nil)
defer http.ReleaseRequest(req)
req.Header.Set(http.HeaderAccept, common.MIMEApplicationJSON)
token.SetAuthHeader(req)
deps.token.SetAuthHeader(req)
resp := http.AcquireResponse()
defer http.ReleaseResponse(resp)
@ -75,38 +76,24 @@ func TestVerification(t *testing.T) {
t.Fatal(err)
}
token.AccessToken = ""
deps.token.AccessToken = ""
if result.ClientID.String() != token.ClientID.String() ||
result.Me.String() != token.Me.String() ||
result.Scope.String() != token.Scope.String() {
t.Errorf("GET %s = %+v, want %+v", requestURL, result, token)
if result.ClientID.String() != deps.token.ClientID.String() ||
result.Me.String() != deps.token.Me.String() ||
result.Scope.String() != deps.token.Scope.String() {
t.Errorf("GET %s = %+v, want %+v", requestURL, result, deps.token)
}
}
func TestRevocation(t *testing.T) {
t.Parallel()
config := domain.TestConfig(t)
store := new(sync.Map)
tokens := tokenrepo.NewMemoryTokenRepository(store)
accessToken := domain.TestToken(t)
deps := NewDependencies(t)
router := router.New()
delivery.NewRequestHandler(
tokenucase.NewTokenUseCase(
tokens,
sessionrepo.NewMemorySessionRepository(config, store),
config,
),
ticketucase.NewTicketUseCase(
ticketrepo.NewMemoryTicketRepository(store, config),
new(http.Client),
config,
),
).Register(router)
r := router.New()
delivery.NewRequestHandler(deps.tokenService, deps.ticketService).Register(r)
client, _, cleanup := httptest.New(t, router.Handler)
client, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup)
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.SetContentType(common.MIMEApplicationForm)
req.PostArgs().Set("action", domain.ActionRevoke.String())
req.PostArgs().Set("token", accessToken.AccessToken)
req.PostArgs().Set("token", deps.token.AccessToken)
resp := http.AcquireResponse()
defer http.ReleaseResponse(resp)
@ -134,12 +121,38 @@ func TestRevocation(t *testing.T) {
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 {
t.Fatal(err)
}
if result.String() != accessToken.String() {
t.Errorf("Get(%+v) = %s, want %s", accessToken.AccessToken, result, accessToken)
if result.String() != deps.token.String() {
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,
}
}