refactor(ports): declare every cross-layer contract and its types in ports
- use-case interfaces (RepoService, TokenService, BrowseService, EventService, MergeRequestService, SessionService, WebSessionService, AuthService, PushService, PushHookService, SigningKeyService, RepoLookup, HookTokens, FailureLimiter, MaintenanceScheduler, Revalidator) move from rpc, githttp, web and app into ports; duplicates merge into one - their params, pages and results move from app to ports; CreateParams and UpdateParams become CreateRepoParams and UpdateRepoParams, app.CommitPage becomes HistoryPage - adapters no longer import app; app asserts it implements the ports - all mocks are generated in internal/ports/mocks
- commit
- f2f0e1bf6ef9344c8f07974cf655c13a1f5e37f4
- author
- brice · · 2026-10-12 04:42 UTC
- parent
- ffb5f8d
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
91 files · +2065 -2439
M .hexcheck.yaml +4 -2
| @@ -40,6 +40,9 @@ components: | |||
| 40 | 40 | role: ignore | |
| 41 | 41 | paths: | |
| 42 | 42 | - internal/readertest/** | |
| 43 | + | # Cross-layer contracts live in ports: adapters and app import ports and domain, | |
| 44 | + | # never each other. hexcheck has no rule for an adapter importing app (only the | |
| 45 | + | # reverse, no-infra-imports-in-usecase), so that direction is kept by review. | |
| 43 | 46 | rules: | |
| 44 | 47 | no-adapter-imports-in-core: error | |
| 45 | 48 | no-infra-imports-in-usecase: error | |
| @@ -53,8 +56,7 @@ rules: | |||
| 53 | 56 | mocking: | |
| 54 | 57 | generatedMockPaths: | |
| 55 | 58 | - internal/ports/mocks/** | |
| 56 | - | - internal/app/mocks/** | |
| 57 | - | - internal/adapters/*/mocks/** | |
| 59 | + | - internal/adapters/web/mocks/** | |
| 58 | 60 | generatedMockNamePatterns: | |
| 59 | 61 | - '{{Interface}}' | |
| 60 | 62 | allow: | |
M .mockery.yml +3 -10
| @@ -1,5 +1,6 @@ | |||
| 1 | - | # Mocks of the ports and of the consumer-side interfaces of the adapters and | |
| 2 | - | # the use cases. Regenerate with: go generate ./internal/ports | |
| 1 | + | # Mocks of the ports, generated in internal/ports/mocks, and of the generated | |
| 2 | + | # Connect clients the web adapter calls. Regenerate with: | |
| 3 | + | # go generate ./internal/ports | |
| 3 | 4 | template: testify | |
| 4 | 5 | _anchors: | |
| 5 | 6 | mocks: &mocks | |
| @@ -11,14 +12,6 @@ _anchors: | |||
| 11 | 12 | packages: | |
| 12 | 13 | bnema.dev/ermite/internal/ports: | |
| 13 | 14 | config: *mocks | |
| 14 | - | bnema.dev/ermite/internal/adapters/githttp: | |
| 15 | - | config: *mocks | |
| 16 | - | bnema.dev/ermite/internal/adapters/rpc: | |
| 17 | - | config: *mocks | |
| 18 | - | bnema.dev/ermite/internal/app: | |
| 19 | - | config: *mocks | |
| 20 | - | bnema.dev/ermite/internal/adapters/web: | |
| 21 | - | config: *mocks | |
| 22 | 15 | bnema.dev/ermite-api/gen/ermite/ermiteconnect: | |
| 23 | 16 | config: | |
| 24 | 17 | include-auto-generated: true | |
M cmd/ermite/api_helpers_test.go +2 -2
| @@ -19,8 +19,8 @@ import ( | |||
| 19 | 19 | ||
| 20 | 20 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 21 | 21 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 22 | - | "bnema.dev/ermite/internal/app" | |
| 23 | 22 | "bnema.dev/ermite/internal/domain" | |
| 23 | + | "bnema.dev/ermite/internal/ports" | |
| 24 | 24 | ) | |
| 25 | 25 | ||
| 26 | 26 | // clients are the generated Connect clients of one caller. | |
| @@ -105,7 +105,7 @@ func codeName(err error) string { | |||
| 105 | 105 | // commit per file to its main branch with git. | |
| 106 | 106 | func (h *harness) seed(name string, vis domain.Visibility, files ...string) { | |
| 107 | 107 | h.t.Helper() | |
| 108 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name(name), Visibility: vis}) | |
| 108 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name(name), Visibility: vis}) | |
| 109 | 109 | require.NoError(h.t, err) | |
| 110 | 110 | if len(files) == 0 { | |
| 111 | 111 | return | |
M cmd/ermite/api_test.go +3 -3
| @@ -24,9 +24,9 @@ import ( | |||
| 24 | 24 | ||
| 25 | 25 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 26 | 26 | "bnema.dev/ermite/internal/adapters/rpc" | |
| 27 | - | "bnema.dev/ermite/internal/app" | |
| 28 | 27 | "bnema.dev/ermite/internal/clientlimit" | |
| 29 | 28 | "bnema.dev/ermite/internal/domain" | |
| 29 | + | "bnema.dev/ermite/internal/ports" | |
| 30 | 30 | ) | |
| 31 | 31 | ||
| 32 | 32 | // principals of the access tables. | |
| @@ -652,8 +652,8 @@ func TestGetBlobStreamsInChunks(t *testing.T) { | |||
| 652 | 652 | } | |
| 653 | 653 | } | |
| 654 | 654 | ||
| 655 | - | func createParams(h *harness, name string, vis domain.Visibility) app.CreateParams { | |
| 656 | - | return app.CreateParams{Name: h.name(name), Visibility: vis} | |
| 655 | + | func createParams(h *harness, name string, vis domain.Visibility) ports.CreateRepoParams { | |
| 656 | + | return ports.CreateRepoParams{Name: h.name(name), Visibility: vis} | |
| 657 | 657 | } | |
| 658 | 658 | ||
| 659 | 659 | // TestUpdateRepoDefaultBranch: HEAD moves with git symbolic-ref once the | |
M cmd/ermite/e2e_helpers_test.go +2 -2
| @@ -18,9 +18,9 @@ import ( | |||
| 18 | 18 | "github.com/bnema/zerowrap" | |
| 19 | 19 | "github.com/stretchr/testify/require" | |
| 20 | 20 | ||
| 21 | - | "bnema.dev/ermite/internal/app" | |
| 22 | 21 | "bnema.dev/ermite/internal/config" | |
| 23 | 22 | "bnema.dev/ermite/internal/domain" | |
| 23 | + | "bnema.dev/ermite/internal/ports" | |
| 24 | 24 | ) | |
| 25 | 25 | ||
| 26 | 26 | // harness is a forge wired like `ermite serve`, behind an httptest server, | |
| @@ -186,7 +186,7 @@ func (h *harness) status(method, path string, hdr http.Header) int { | |||
| 186 | 186 | // token creates a stored token through the use case, as root. | |
| 187 | 187 | func (h *harness) token(scopes []domain.Scope, repos ...string) string { | |
| 188 | 188 | h.t.Helper() | |
| 189 | - | p := app.CreateTokenParams{Label: "e2e", Scopes: scopes} | |
| 189 | + | p := ports.CreateTokenParams{Label: "e2e", Scopes: scopes} | |
| 190 | 190 | for _, r := range repos { | |
| 191 | 191 | p.Repos = append(p.Repos, h.name(r)) | |
| 192 | 192 | } | |
M cmd/ermite/e2e_test.go +8 -8
| @@ -20,8 +20,8 @@ import ( | |||
| 20 | 20 | "github.com/stretchr/testify/assert" | |
| 21 | 21 | "github.com/stretchr/testify/require" | |
| 22 | 22 | ||
| 23 | - | "bnema.dev/ermite/internal/app" | |
| 24 | 23 | "bnema.dev/ermite/internal/domain" | |
| 24 | + | "bnema.dev/ermite/internal/ports" | |
| 25 | 25 | ) | |
| 26 | 26 | ||
| 27 | 27 | func scopes(s ...domain.Scope) []domain.Scope { return s } | |
| @@ -29,7 +29,7 @@ func scopes(s ...domain.Scope) []domain.Scope { return s } | |||
| 29 | 29 | // publicRepo creates a public repository with one commit pushed by root. | |
| 30 | 30 | func (h *harness) publicRepo(name string, files ...string) { | |
| 31 | 31 | h.t.Helper() | |
| 32 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name(name), Visibility: domain.VisibilityPublic}) | |
| 32 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name(name), Visibility: domain.VisibilityPublic}) | |
| 33 | 33 | require.NoError(h.t, err) | |
| 34 | 34 | wt := h.workTree("main", files...) | |
| 35 | 35 | h.mustGit(wt, "push", "-q", h.urlAuth(adminToken, "/"+name+".git"), "main") | |
| @@ -189,7 +189,7 @@ func TestAC2PushAuthorization(t *testing.T) { | |||
| 189 | 189 | assert.Contains(t, out, "Authentication failed") | |
| 190 | 190 | ||
| 191 | 191 | // Revoked token. | |
| 192 | - | created, err := h.forge.Tokens.Create(h.ctx, domain.Root(), app.CreateTokenParams{Label: "short", Scopes: scopes(domain.ScopeRepoWrite)}) | |
| 192 | + | created, err := h.forge.Tokens.Create(h.ctx, domain.Root(), ports.CreateTokenParams{Label: "short", Scopes: scopes(domain.ScopeRepoWrite)}) | |
| 193 | 193 | require.NoError(t, err) | |
| 194 | 194 | next("before-revoke") | |
| 195 | 195 | out, err = h.git(wt, "push", "-q", h.urlAuth(created.Secret, "/proj.git"), "main") | |
| @@ -570,20 +570,20 @@ func TestAC8TokenCreationThroughTheForge(t *testing.T) { | |||
| 570 | 570 | h := newHarness(t, harnessOpts{}) | |
| 571 | 571 | ctx := context.Background() | |
| 572 | 572 | ||
| 573 | - | admin, err := h.forge.Tokens.Create(ctx, domain.Root(), app.CreateTokenParams{ | |
| 573 | + | admin, err := h.forge.Tokens.Create(ctx, domain.Root(), ports.CreateTokenParams{ | |
| 574 | 574 | Label: "limited admin", Scopes: scopes(domain.ScopeTokenAdmin, domain.ScopeRepoWrite), Repos: []domain.RepoName{h.name("a")}, | |
| 575 | 575 | }) | |
| 576 | 576 | require.NoError(t, err) | |
| 577 | 577 | p, err := h.forge.Auth.Authenticate(ctx, admin.Secret) | |
| 578 | 578 | require.NoError(t, err) | |
| 579 | 579 | ||
| 580 | - | _, err = h.forge.Tokens.Create(ctx, p, app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoAdmin), Repos: []domain.RepoName{h.name("a")}}) | |
| 580 | + | _, err = h.forge.Tokens.Create(ctx, p, ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoAdmin), Repos: []domain.RepoName{h.name("a")}}) | |
| 581 | 581 | assert.ErrorIs(t, err, domain.ErrForbidden, "scope escalation") | |
| 582 | - | _, err = h.forge.Tokens.Create(ctx, p, app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoWrite)}) | |
| 582 | + | _, err = h.forge.Tokens.Create(ctx, p, ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoWrite)}) | |
| 583 | 583 | assert.ErrorIs(t, err, domain.ErrForbidden, "repository list escalation") | |
| 584 | - | _, err = h.forge.Tokens.Create(ctx, p, app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoWrite), Repos: []domain.RepoName{h.name("b")}}) | |
| 584 | + | _, err = h.forge.Tokens.Create(ctx, p, ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoWrite), Repos: []domain.RepoName{h.name("b")}}) | |
| 585 | 585 | assert.ErrorIs(t, err, domain.ErrForbidden, "another repository") | |
| 586 | - | child, err := h.forge.Tokens.Create(ctx, p, app.CreateTokenParams{Label: "child", Scopes: scopes(domain.ScopeRepoWrite), Repos: []domain.RepoName{h.name("a")}}) | |
| 586 | + | child, err := h.forge.Tokens.Create(ctx, p, ports.CreateTokenParams{Label: "child", Scopes: scopes(domain.ScopeRepoWrite), Repos: []domain.RepoName{h.name("a")}}) | |
| 587 | 587 | require.NoError(t, err) | |
| 588 | 588 | ||
| 589 | 589 | // The child works on its repository, and revoking the index entry kills it at once. | |
M cmd/ermite/events_test.go +4 -3
| @@ -21,6 +21,7 @@ import ( | |||
| 21 | 21 | "bnema.dev/ermite/internal/adapters/rpc" | |
| 22 | 22 | "bnema.dev/ermite/internal/app" | |
| 23 | 23 | "bnema.dev/ermite/internal/domain" | |
| 24 | + | "bnema.dev/ermite/internal/ports" | |
| 24 | 25 | ) | |
| 25 | 26 | ||
| 26 | 27 | // watchWait is how long a test waits for an event that must arrive. Only | |
| @@ -222,7 +223,7 @@ func TestAC5NoPrivateEventsToAnonymous(t *testing.T) { | |||
| 222 | 223 | assert.Equal(t, "pub", ev.GetPushed().GetRepo(), name) | |
| 223 | 224 | } | |
| 224 | 225 | // Nothing about priv came before the sentinel, for either of them. | |
| 225 | - | _, err = h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name("sentinel"), Visibility: domain.VisibilityPublic}) | |
| 226 | + | _, err = h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name("sentinel"), Visibility: domain.VisibilityPublic}) | |
| 226 | 227 | require.NoError(t, err) | |
| 227 | 228 | for name, w := range map[string]*stream{"anonymous": anon, "scoped": scoped} { | |
| 228 | 229 | assert.Equal(t, "sentinel", w.next(t, watchWait).GetRepoCreated().GetRepo().GetName(), name) | |
| @@ -340,7 +341,7 @@ func TestServeShutdownEndsWatchStreams(t *testing.T) { | |||
| 340 | 341 | func TestWatchEndsWhenTheTokenIsRevoked(t *testing.T) { | |
| 341 | 342 | h := newHarness(t, harnessOpts{revalidateEvery: 20 * time.Millisecond}) | |
| 342 | 343 | h.seed("priv", domain.VisibilityPrivate) | |
| 343 | - | created, err := h.forge.Tokens.Create(h.ctx, domain.Root(), app.CreateTokenParams{ | |
| 344 | + | created, err := h.forge.Tokens.Create(h.ctx, domain.Root(), ports.CreateTokenParams{ | |
| 344 | 345 | Label: "watcher", Scopes: scopes(domain.ScopeRepoRead), | |
| 345 | 346 | }) | |
| 346 | 347 | require.NoError(t, err) | |
| @@ -396,7 +397,7 @@ func TestWatchLimits(t *testing.T) { | |||
| 396 | 397 | // order they were published. | |
| 397 | 398 | func (h *harness) sentinel(t *testing.T, s *stream, name string) { | |
| 398 | 399 | t.Helper() | |
| 399 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name(name), Visibility: domain.VisibilityPublic}) | |
| 400 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name(name), Visibility: domain.VisibilityPublic}) | |
| 400 | 401 | require.NoError(t, err) | |
| 401 | 402 | ev := s.next(t, watchWait) | |
| 402 | 403 | assert.Equal(t, name, ev.GetRepoCreated().GetRepo().GetName(), "an event came before the sentinel: %v", ev) | |
M cmd/ermite/gitreader_test.go +2 -2
| @@ -10,9 +10,9 @@ import ( | |||
| 10 | 10 | "github.com/stretchr/testify/assert" | |
| 11 | 11 | "github.com/stretchr/testify/require" | |
| 12 | 12 | ||
| 13 | - | "bnema.dev/ermite/internal/app" | |
| 14 | 13 | "bnema.dev/ermite/internal/config" | |
| 15 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 16 | 16 | ) | |
| 17 | 17 | ||
| 18 | 18 | // The suite runs with the reader of ERMITE_GIT_READER (ermite-git by default). | |
| @@ -28,7 +28,7 @@ func TestGitReaderOfTheForgeAndReadAfterPush(t *testing.T) { | |||
| 28 | 28 | assert.Equal(t, want, h.forge.cfg.GitReader) | |
| 29 | 29 | assert.Equal(t, want == config.GitReaderErmiteGit, h.forge.reader != nil, "the ermite-git adapter exists only for ermite-git") | |
| 30 | 30 | ||
| 31 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{ | |
| 31 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{ | |
| 32 | 32 | Name: h.name("fresh"), Visibility: domain.VisibilityPublic, | |
| 33 | 33 | }) | |
| 34 | 34 | require.NoError(t, err) | |
M cmd/ermite/web.go +8 -5
| @@ -21,6 +21,7 @@ import ( | |||
| 21 | 21 | "bnema.dev/ermite/internal/clientlimit" | |
| 22 | 22 | "bnema.dev/ermite/internal/config" | |
| 23 | 23 | "bnema.dev/ermite/internal/domain" | |
| 24 | + | "bnema.dev/ermite/internal/ports" | |
| 24 | 25 | ) | |
| 25 | 26 | ||
| 26 | 27 | // newWeb builds the web pages on the API of this process: the generated | |
| @@ -96,15 +97,17 @@ func warnSharedClientKey(ctx context.Context, trusted []netip.Prefix, maxPerClie | |||
| 96 | 97 | "requests and one budget of failed authentications; set it to the proxy networks") | |
| 97 | 98 | } | |
| 98 | 99 | ||
| 99 | - | // webSessions adapts the session use cases to web.SessionAuth: a valid token | |
| 100 | - | // gives the context of the owner, whose principal the API calls of the page | |
| 101 | - | // carry (rpc.API.InProcessClient). | |
| 100 | + | // webSessions adapts the session use cases to ports.WebSessionService: a valid | |
| 101 | + | // token gives the context of the owner, whose principal the API calls of the | |
| 102 | + | // page carry (rpc.API.InProcessClient). | |
| 102 | 103 | type webSessions struct{ *app.Sessions } | |
| 103 | 104 | ||
| 105 | + | var _ ports.WebSessionService = webSessions{} | |
| 106 | + | ||
| 104 | 107 | func (s webSessions) Login(ctx context.Context, nonce string) (string, time.Duration, error) { | |
| 105 | 108 | token, expiresAt, err := s.Sessions.Login(ctx, nonce) | |
| 106 | 109 | if errors.Is(err, domain.ErrUnauthenticated) { | |
| 107 | - | return "", 0, web.ErrLinkRejected | |
| 110 | + | return "", 0, ports.ErrLinkRejected | |
| 108 | 111 | } | |
| 109 | 112 | if err != nil { | |
| 110 | 113 | return "", 0, err | |
| @@ -118,7 +121,7 @@ func (s webSessions) Login(ctx context.Context, nonce string) (string, time.Dura | |||
| 118 | 121 | lifetime = d.Round(time.Second) | |
| 119 | 122 | } | |
| 120 | 123 | if lifetime < time.Second { | |
| 121 | - | return "", 0, web.ErrLinkRejected | |
| 124 | + | return "", 0, ports.ErrLinkRejected | |
| 122 | 125 | } | |
| 123 | 126 | return token, lifetime, nil | |
| 124 | 127 | } | |
M cmd/ermite/web_commits_test.go +2 -2
| @@ -14,8 +14,8 @@ import ( | |||
| 14 | 14 | "github.com/stretchr/testify/assert" | |
| 15 | 15 | "github.com/stretchr/testify/require" | |
| 16 | 16 | ||
| 17 | - | "bnema.dev/ermite/internal/app" | |
| 18 | 17 | "bnema.dev/ermite/internal/domain" | |
| 18 | + | "bnema.dev/ermite/internal/ports" | |
| 19 | 19 | ) | |
| 20 | 20 | ||
| 21 | 21 | // diffFixture is the repository of the commit pages: one commit for each | |
| @@ -27,7 +27,7 @@ type diffFixture struct { | |||
| 27 | 27 | // createRepo creates a public repository for the pages. | |
| 28 | 28 | func (h *harness) createRepo(name string, vis domain.Visibility) { | |
| 29 | 29 | h.t.Helper() | |
| 30 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name(name), Description: "Diffs", Visibility: vis}) | |
| 30 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name(name), Description: "Diffs", Visibility: vis}) | |
| 31 | 31 | require.NoError(h.t, err) | |
| 32 | 32 | } | |
| 33 | 33 | ||
M cmd/ermite/web_events_test.go +5 -4
| @@ -17,6 +17,7 @@ import ( | |||
| 17 | 17 | ||
| 18 | 18 | "bnema.dev/ermite/internal/app" | |
| 19 | 19 | "bnema.dev/ermite/internal/domain" | |
| 20 | + | "bnema.dev/ermite/internal/ports" | |
| 20 | 21 | ) | |
| 21 | 22 | ||
| 22 | 23 | // sseEvent is one event read from /-/events. | |
| @@ -126,7 +127,7 @@ func TestWebEventsHome(t *testing.T) { | |||
| 126 | 127 | assert.Contains(t, ev.data, `href="/pub"`) | |
| 127 | 128 | ||
| 128 | 129 | // A new repository is a row; so is a repository created by a push. | |
| 129 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name("fresh"), Description: "a <b>fresh</b> one", Visibility: domain.VisibilityPublic}) | |
| 130 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name("fresh"), Description: "a <b>fresh</b> one", Visibility: domain.VisibilityPublic}) | |
| 130 | 131 | require.NoError(t, err) | |
| 131 | 132 | ev = s.next(t, watchWait) | |
| 132 | 133 | assert.Equal(t, "home-list", ev.name) | |
| @@ -136,7 +137,7 @@ func TestWebEventsHome(t *testing.T) { | |||
| 136 | 137 | ||
| 137 | 138 | // A repository that turns private is removed from the anonymous list. | |
| 138 | 139 | priv := domain.VisibilityPrivate | |
| 139 | - | _, err = h.forge.Repos.Update(h.ctx, domain.Root(), h.name("fresh"), app.UpdateParams{Visibility: &priv}) | |
| 140 | + | _, err = h.forge.Repos.Update(h.ctx, domain.Root(), h.name("fresh"), ports.UpdateRepoParams{Visibility: &priv}) | |
| 140 | 141 | require.NoError(t, err) | |
| 141 | 142 | ev = s.next(t, watchWait) | |
| 142 | 143 | assert.Equal(t, "home-list", ev.name) | |
| @@ -286,7 +287,7 @@ func TestWebEventsPrivate(t *testing.T) { | |||
| 286 | 287 | wt := h.workTree("main", "a.txt") | |
| 287 | 288 | h.mustGit(wt, "push", "-q", h.urlAuth(adminToken, "/priv.git"), "main") | |
| 288 | 289 | desc := "secret change" | |
| 289 | - | _, err := h.forge.Repos.Update(h.ctx, domain.Root(), h.name("priv"), app.UpdateParams{Description: &desc}) | |
| 290 | + | _, err := h.forge.Repos.Update(h.ctx, domain.Root(), h.name("priv"), ports.UpdateRepoParams{Description: &desc}) | |
| 290 | 291 | require.NoError(t, err) | |
| 291 | 292 | // Made public later, it does not reveal what happened while it was | |
| 292 | 293 | // private; the update that makes it public is shown. | |
| @@ -303,7 +304,7 @@ func TestWebEventsPrivate(t *testing.T) { | |||
| 303 | 304 | // public repository and requires its row to be the next event. | |
| 304 | 305 | func (h *harness) sentinelSSE(t *testing.T, s *sseStream, name string) { | |
| 305 | 306 | t.Helper() | |
| 306 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name(name), Visibility: domain.VisibilityPublic}) | |
| 307 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name(name), Visibility: domain.VisibilityPublic}) | |
| 307 | 308 | require.NoError(t, err) | |
| 308 | 309 | ev := s.next(t, watchWait) | |
| 309 | 310 | assert.Contains(t, ev.data, `id="repo-`+name+`"`, "an event came before the sentinel: %s", ev.data) | |
M cmd/ermite/web_files_test.go +2 -2
| @@ -16,8 +16,8 @@ import ( | |||
| 16 | 16 | "github.com/stretchr/testify/assert" | |
| 17 | 17 | "github.com/stretchr/testify/require" | |
| 18 | 18 | ||
| 19 | - | "bnema.dev/ermite/internal/app" | |
| 20 | 19 | "bnema.dev/ermite/internal/domain" | |
| 20 | + | "bnema.dev/ermite/internal/ports" | |
| 21 | 21 | ) | |
| 22 | 22 | ||
| 23 | 23 | // Trojan Source: a right-to-left override and an isolate around code. | |
| @@ -37,7 +37,7 @@ func tinyPNG(t *testing.T) []byte { | |||
| 37 | 37 | // tag with a slash. | |
| 38 | 38 | func (h *harness) webFilesRepo(name string) { | |
| 39 | 39 | h.t.Helper() | |
| 40 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{ | |
| 40 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{ | |
| 41 | 41 | Name: h.name(name), Description: "Files of every kind", Visibility: domain.VisibilityPublic, | |
| 42 | 42 | }) | |
| 43 | 43 | require.NoError(h.t, err) | |
M cmd/ermite/web_mr_test.go +2 -2
| @@ -13,8 +13,8 @@ import ( | |||
| 13 | 13 | "github.com/stretchr/testify/assert" | |
| 14 | 14 | "github.com/stretchr/testify/require" | |
| 15 | 15 | ||
| 16 | - | "bnema.dev/ermite/internal/app" | |
| 17 | 16 | "bnema.dev/ermite/internal/domain" | |
| 17 | + | "bnema.dev/ermite/internal/ports" | |
| 18 | 18 | ) | |
| 19 | 19 | ||
| 20 | 20 | // mrRepo is a public repository "proj" with README.md on main and a branch | |
| @@ -466,7 +466,7 @@ func TestWebMergeRequestLimitIsFriendly(t *testing.T) { | |||
| 466 | 466 | token := r.signIn(t) | |
| 467 | 467 | r.cli(t, adminToken, "mr", "create", "proj", "--source", "feat/search", "--title", "t").ok(t) | |
| 468 | 468 | for i := 0; i < 1000; i++ { | |
| 469 | - | _, err := r.forge.MergeRequests.AddComment(r.ctx, domain.Root(), r.name("proj"), 1, app.AddCommentParams{Text: "n"}) | |
| 469 | + | _, err := r.forge.MergeRequests.AddComment(r.ctx, domain.Root(), r.name("proj"), 1, ports.AddCommentParams{Text: "n"}) | |
| 470 | 470 | require.NoError(t, err) | |
| 471 | 471 | } | |
| 472 | 472 | full := b.form("/proj/merge-requests/1/comments", token, url.Values{"text": {"one more"}}) | |
M cmd/ermite/web_session_test.go +2 -2
| @@ -19,8 +19,8 @@ import ( | |||
| 19 | 19 | "github.com/stretchr/testify/require" | |
| 20 | 20 | ||
| 21 | 21 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 22 | - | "bnema.dev/ermite/internal/app" | |
| 23 | 22 | "bnema.dev/ermite/internal/domain" | |
| 23 | + | "bnema.dev/ermite/internal/ports" | |
| 24 | 24 | ) | |
| 25 | 25 | ||
| 26 | 26 | const ( | |
| @@ -311,7 +311,7 @@ func TestWebRevokingAnOwnerTokenSignsEveryoneOut(t *testing.T) { | |||
| 311 | 311 | ||
| 312 | 312 | // The cap: a link made by a token that expires in an hour gives a cookie, | |
| 313 | 313 | // and a session, of an hour. | |
| 314 | - | soon, err := c.forge.Tokens.Create(c.ctx, domain.Root(), app.CreateTokenParams{ | |
| 314 | + | soon, err := c.forge.Tokens.Create(c.ctx, domain.Root(), ports.CreateTokenParams{ | |
| 315 | 315 | Label: "soon", Scopes: domain.AllScopes(), ExpiresAt: time.Now().Add(time.Hour), | |
| 316 | 316 | }) | |
| 317 | 317 | require.NoError(t, err) | |
M cmd/ermite/web_test.go +3 -3
| @@ -16,8 +16,8 @@ import ( | |||
| 16 | 16 | "github.com/stretchr/testify/assert" | |
| 17 | 17 | "github.com/stretchr/testify/require" | |
| 18 | 18 | ||
| 19 | - | "bnema.dev/ermite/internal/app" | |
| 20 | 19 | "bnema.dev/ermite/internal/domain" | |
| 20 | + | "bnema.dev/ermite/internal/ports" | |
| 21 | 21 | ) | |
| 22 | 22 | ||
| 23 | 23 | var updateGolden = flag.Bool("update", false, "rewrite the golden files of the web tests") | |
| @@ -30,7 +30,7 @@ const webFixtureReadme = "# Demo\n\nA small *demo* with a [guide](docs/guide.md) | |||
| 30 | 30 | // branches (one with a slash), two tags and a description. | |
| 31 | 31 | func (h *harness) webRepo(name string) { | |
| 32 | 32 | h.t.Helper() | |
| 33 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{ | |
| 33 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{ | |
| 34 | 34 | Name: h.name(name), Description: "A demo repository", Visibility: domain.VisibilityPublic, | |
| 35 | 35 | }) | |
| 36 | 36 | require.NoError(h.t, err) | |
| @@ -162,7 +162,7 @@ func TestWebPrivateRepoIsInvisible(t *testing.T) { | |||
| 162 | 162 | // AC4, end to end: a README that attacks the page is neutralised. | |
| 163 | 163 | func TestWebReadmeIsNeutralised(t *testing.T) { | |
| 164 | 164 | h := newHarness(t, harnessOpts{}) | |
| 165 | - | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), app.CreateParams{Name: h.name("evil"), Visibility: domain.VisibilityPublic}) | |
| 165 | + | _, err := h.forge.Repos.Create(h.ctx, domain.Root(), ports.CreateRepoParams{Name: h.name("evil"), Visibility: domain.VisibilityPublic}) | |
| 166 | 166 | require.NoError(t, err) | |
| 167 | 167 | wt := h.t.TempDir() | |
| 168 | 168 | h.mustGit(wt, "init", "-q", "--initial-branch=main") | |
M internal/adapters/githttp/handler.go +8 -44
| @@ -61,56 +61,18 @@ const ( | |||
| 61 | 61 | serviceReceive = "git-receive-pack" | |
| 62 | 62 | ) | |
| 63 | 63 | ||
| 64 | - | // Authenticator turns the secret of a request into a principal. It returns | |
| 65 | - | // domain.ErrUnauthenticated for a secret that is not valid. app.Auth fits. | |
| 66 | - | type Authenticator interface { | |
| 67 | - | Authenticate(ctx context.Context, secret string) (domain.Principal, error) | |
| 68 | - | } | |
| 69 | - | ||
| 70 | - | // Repos is the read side of the repository use cases. A repository the | |
| 71 | - | // principal may not read is domain.ErrNotFound. app.Repos fits. | |
| 72 | - | type Repos interface { | |
| 73 | - | Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) | |
| 74 | - | } | |
| 75 | - | ||
| 76 | - | // Pushes opens a repository for a push: it is domain.ErrUnauthenticated for an | |
| 77 | - | // anonymous caller, domain.ErrNotFound for a repository the caller may not | |
| 78 | - | // write and cannot see (or that is missing and may not be created), | |
| 79 | - | // domain.ErrForbidden for one it can see but not write. With create, a missing | |
| 80 | - | // repository the principal may write is created. app.Pushes fits. | |
| 81 | - | type Pushes interface { | |
| 82 | - | Open(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error | |
| 83 | - | } | |
| 84 | - | ||
| 85 | - | // HookTokens hands out the per-request tokens the hooks of a push present | |
| 86 | - | // back to ermite, and the socket they present them on. | |
| 87 | - | type HookTokens interface { | |
| 88 | - | // Register binds a new token to the repository and principal of a push. | |
| 89 | - | // release revokes it and must be called when the request ends. | |
| 90 | - | Register(ctx context.Context, repo domain.RepoName, p domain.Principal) (token string, release func()) | |
| 91 | - | // Socket is the path of the hook socket. | |
| 92 | - | Socket() string | |
| 93 | - | } | |
| 94 | - | ||
| 95 | - | // FailureLimiter counts the failed authentications per client, with the other | |
| 96 | - | // adapters that authenticate. *clientlimit.Limiter fits. | |
| 97 | - | type FailureLimiter interface { | |
| 98 | - | Blocked(ctx context.Context, addr string) (bool, time.Duration) | |
| 99 | - | Fail(ctx context.Context, addr string) | |
| 100 | - | } | |
| 101 | - | ||
| 102 | 64 | // Config configures a Handler. | |
| 103 | 65 | type Config struct { | |
| 104 | - | Auth Authenticator | |
| 105 | - | Repos Repos | |
| 106 | - | Pushes Pushes | |
| 66 | + | Auth ports.AuthService | |
| 67 | + | Repos ports.RepoLookup | |
| 68 | + | Pushes ports.PushService | |
| 107 | 69 | Backend ports.GitBackend | |
| 108 | 70 | // Hooks provides hook tokens for pushes. It is required. | |
| 109 | - | Hooks HookTokens | |
| 71 | + | Hooks ports.HookTokens | |
| 110 | 72 | // TrustedProxies are the networks allowed to set X-Forwarded-For. | |
| 111 | 73 | TrustedProxies []netip.Prefix | |
| 112 | 74 | // Limiter counts failed authentications; nil builds a default one. | |
| 113 | - | Limiter FailureLimiter | |
| 75 | + | Limiter ports.FailureLimiter | |
| 114 | 76 | // MaxBodyBytes bounds the body of a push; 0 means DefaultMaxBodyBytes. | |
| 115 | 77 | // The body of a fetch is bounded by 64 MiB at most. | |
| 116 | 78 | MaxBodyBytes int64 | |
| @@ -148,7 +110,7 @@ const ( | |||
| 148 | 110 | // Handler serves the smart HTTP routes of Patterns. | |
| 149 | 111 | type Handler struct { | |
| 150 | 112 | cfg Config | |
| 151 | - | limiter FailureLimiter | |
| 113 | + | limiter ports.FailureLimiter | |
| 152 | 114 | maxBody int64 | |
| 153 | 115 | ||
| 154 | 116 | upload, receive chan struct{} // slots of the backends, per service | |
| @@ -220,6 +182,7 @@ func parseRoute(r *http.Request) (route, int) { | |||
| 220 | 182 | } | |
| 221 | 183 | ||
| 222 | 184 | // ServeHTTP implements http.Handler. | |
| 185 | + | //hexcheck:ignore suspicious-business-logic-in-adapter transport orchestration: the authorization decisions are the use cases' | |
| 223 | 186 | func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
| 224 | 187 | var rt route | |
| 225 | 188 | var name domain.RepoName | |
| @@ -411,6 +374,7 @@ func (h *Handler) acquire(ctx context.Context, w http.ResponseWriter, rt route, | |||
| 411 | 374 | } | |
| 412 | 375 | ||
| 413 | 376 | // serveBackend runs git http-backend for an authorized request. | |
| 377 | + | //hexcheck:ignore suspicious-business-logic-in-adapter process and CGI plumbing: no business rule is decided here | |
| 414 | 378 | func (h *Handler) serveBackend(w http.ResponseWriter, r *http.Request, rt route, name domain.RepoName, p domain.Principal, client string) { | |
| 415 | 379 | ctx := r.Context() | |
| 416 | 380 | logger := zerowrap.FromCtx(ctx) | |
M internal/adapters/githttp/handler_test.go +10 -11
| @@ -21,7 +21,6 @@ import ( | |||
| 21 | 21 | "github.com/stretchr/testify/require" | |
| 22 | 22 | ||
| 23 | 23 | "bnema.dev/ermite/internal/adapters/githttp" | |
| 24 | - | ghmocks "bnema.dev/ermite/internal/adapters/githttp/mocks" | |
| 25 | 24 | "bnema.dev/ermite/internal/clientlimit" | |
| 26 | 25 | "bnema.dev/ermite/internal/domain" | |
| 27 | 26 | "bnema.dev/ermite/internal/ports" | |
| @@ -43,10 +42,10 @@ func cgiScript(t *testing.T) string { | |||
| 43 | 42 | type rig struct { | |
| 44 | 43 | h *githttp.Handler | |
| 45 | 44 | srv *httptest.Server | |
| 46 | - | pushes *ghmocks.Pushes | |
| 45 | + | pushes *mocks.PushService | |
| 47 | 46 | backend *mocks.GitBackend | |
| 48 | - | hooks *ghmocks.HookTokens | |
| 49 | - | auth *ghmocks.Authenticator | |
| 47 | + | hooks *mocks.HookTokens | |
| 48 | + | auth *mocks.AuthService | |
| 50 | 49 | ||
| 51 | 50 | pushFlags []bool | |
| 52 | 51 | backendErr error | |
| @@ -93,7 +92,7 @@ func (r *rig) hookedRepo() domain.RepoName { | |||
| 93 | 92 | ||
| 94 | 93 | // stubUseCases answers like the use cases behind the handler: a root and a | |
| 95 | 94 | // reader token, a public repository "pub" and a private one "priv". | |
| 96 | - | func (r *rig) stubUseCases(repos *ghmocks.Repos) { | |
| 95 | + | func (r *rig) stubUseCases(repos *mocks.RepoLookup) { | |
| 97 | 96 | r.auth.EXPECT().Authenticate(mock.Anything, mock.Anything).RunAndReturn( | |
| 98 | 97 | func(_ context.Context, secret string) (domain.Principal, error) { | |
| 99 | 98 | r.mu.Lock() | |
| @@ -145,10 +144,10 @@ func (r *rig) stubUseCases(repos *ghmocks.Repos) { | |||
| 145 | 144 | func newRig(t *testing.T, mut func(*githttp.Config)) *rig { | |
| 146 | 145 | t.Helper() | |
| 147 | 146 | r := &rig{ | |
| 148 | - | pushes: ghmocks.NewPushes(t), backend: mocks.NewGitBackend(t), | |
| 149 | - | hooks: ghmocks.NewHookTokens(t), auth: ghmocks.NewAuthenticator(t), | |
| 147 | + | pushes: mocks.NewPushService(t), backend: mocks.NewGitBackend(t), | |
| 148 | + | hooks: mocks.NewHookTokens(t), auth: mocks.NewAuthService(t), | |
| 150 | 149 | } | |
| 151 | - | repos := ghmocks.NewRepos(t) | |
| 150 | + | repos := mocks.NewRepoLookup(t) | |
| 152 | 151 | r.stubUseCases(repos) | |
| 153 | 152 | cfg := githttp.Config{ | |
| 154 | 153 | Auth: r.auth, Repos: repos, Pushes: r.pushes, Backend: r.backend, Hooks: r.hooks, | |
| @@ -511,7 +510,7 @@ func TestHandlerUsesTheFailureLimiter(t *testing.T) { | |||
| 511 | 510 | path := "/pub.git/info/refs?service=git-upload-pack" | |
| 512 | 511 | t.Run("a blocked client is refused before authentication", func(t *testing.T) { | |
| 513 | 512 | t.Parallel() | |
| 514 | - | limiter := ghmocks.NewFailureLimiter(t) | |
| 513 | + | limiter := mocks.NewFailureLimiter(t) | |
| 515 | 514 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(true, 3*time.Second).Once() | |
| 516 | 515 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | |
| 517 | 516 | code, _, hdr := r.do(t, "GET", path, "u", "root-secret", nil, nil) | |
| @@ -521,7 +520,7 @@ func TestHandlerUsesTheFailureLimiter(t *testing.T) { | |||
| 521 | 520 | }) | |
| 522 | 521 | t.Run("an invalid secret is recorded as a failure", func(t *testing.T) { | |
| 523 | 522 | t.Parallel() | |
| 524 | - | limiter := ghmocks.NewFailureLimiter(t) | |
| 523 | + | limiter := mocks.NewFailureLimiter(t) | |
| 525 | 524 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(false, time.Duration(0)).Once() | |
| 526 | 525 | limiter.EXPECT().Fail(mock.Anything, "127.0.0.1").Once() | |
| 527 | 526 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | |
| @@ -530,7 +529,7 @@ func TestHandlerUsesTheFailureLimiter(t *testing.T) { | |||
| 530 | 529 | }) | |
| 531 | 530 | t.Run("a valid secret is not a failure", func(t *testing.T) { | |
| 532 | 531 | t.Parallel() | |
| 533 | - | limiter := ghmocks.NewFailureLimiter(t) | |
| 532 | + | limiter := mocks.NewFailureLimiter(t) | |
| 534 | 533 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(false, time.Duration(0)).Once() | |
| 535 | 534 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | |
| 536 | 535 | code, _, _ := r.do(t, "GET", path, "u", "root-secret", nil, nil) | |
M internal/adapters/githttp/hooks.go +5 -12
| @@ -19,17 +19,9 @@ import ( | |||
| 19 | 19 | "github.com/bnema/zerowrap" | |
| 20 | 20 | ||
| 21 | 21 | "bnema.dev/ermite/internal/domain" | |
| 22 | + | "bnema.dev/ermite/internal/ports" | |
| 22 | 23 | ) | |
| 23 | 24 | ||
| 24 | - | // PushHooks is what the hook socket asks of the use cases. app.Pushes fits. | |
| 25 | - | type PushHooks interface { | |
| 26 | - | // Check decides a push before Git applies it; an error matching | |
| 27 | - | // domain.ErrRejected refuses it, any other error refuses it as a failure. | |
| 28 | - | Check(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error | |
| 29 | - | // Record handles an accepted push. | |
| 30 | - | Record(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error | |
| 31 | - | } | |
| 32 | - | ||
| 33 | 25 | // readTimeout bounds how long a connection may take to send its request line. | |
| 34 | 26 | const readTimeout = 30 * time.Second | |
| 35 | 27 | ||
| @@ -46,7 +38,7 @@ type hookEntry struct { | |||
| 46 | 38 | // socket the hooks call back on. It implements HookTokens. | |
| 47 | 39 | type HookServer struct { | |
| 48 | 40 | path string | |
| 49 | - | hooks PushHooks | |
| 41 | + | hooks ports.PushHookService | |
| 50 | 42 | ||
| 51 | 43 | mu sync.RWMutex | |
| 52 | 44 | tokens map[string]hookEntry | |
| @@ -57,10 +49,10 @@ type HookServer struct { | |||
| 57 | 49 | wg sync.WaitGroup | |
| 58 | 50 | } | |
| 59 | 51 | ||
| 60 | - | var _ HookTokens = (*HookServer)(nil) | |
| 52 | + | var _ ports.HookTokens = (*HookServer)(nil) | |
| 61 | 53 | ||
| 62 | 54 | // NewHookServer builds a server for the socket at path. Call Serve to listen. | |
| 63 | - | func NewHookServer(path string, hooks PushHooks) *HookServer { | |
| 55 | + | func NewHookServer(path string, hooks ports.PushHookService) *HookServer { | |
| 64 | 56 | return &HookServer{path: path, hooks: hooks, tokens: make(map[string]hookEntry), conns: make(map[net.Conn]struct{})} | |
| 65 | 57 | } | |
| 66 | 58 | ||
| @@ -183,6 +175,7 @@ func (s *HookServer) Close(ctx context.Context) { | |||
| 183 | 175 | } | |
| 184 | 176 | ||
| 185 | 177 | // handle serves one connection: one request line, one reply line. | |
| 178 | + | //hexcheck:ignore suspicious-business-logic-in-adapter hook protocol dispatch: the decisions are the use cases' | |
| 186 | 179 | func (s *HookServer) handle(ctx context.Context, conn net.Conn) { | |
| 187 | 180 | log := zerowrap.FromCtx(ctx) | |
| 188 | 181 | _ = conn.SetReadDeadline(time.Now().Add(readTimeout)) | |
M internal/adapters/githttp/hooks_test.go +10 -9
| @@ -22,8 +22,9 @@ import ( | |||
| 22 | 22 | "github.com/stretchr/testify/require" | |
| 23 | 23 | ||
| 24 | 24 | "bnema.dev/ermite/internal/adapters/githttp" | |
| 25 | - | ghmocks "bnema.dev/ermite/internal/adapters/githttp/mocks" | |
| 26 | 25 | "bnema.dev/ermite/internal/domain" | |
| 26 | + | "bnema.dev/ermite/internal/ports" | |
| 27 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 27 | 28 | ) | |
| 28 | 29 | ||
| 29 | 30 | const ( | |
| @@ -39,7 +40,7 @@ func repoName(t *testing.T, s string) domain.RepoName { | |||
| 39 | 40 | } | |
| 40 | 41 | ||
| 41 | 42 | // startHooks serves a hook socket in a short temporary directory. | |
| 42 | - | func startHooks(t *testing.T, h githttp.PushHooks) (*githttp.HookServer, string) { | |
| 43 | + | func startHooks(t *testing.T, h ports.PushHookService) (*githttp.HookServer, string) { | |
| 43 | 44 | t.Helper() | |
| 44 | 45 | dir, err := os.MkdirTemp("", "hk") | |
| 45 | 46 | require.NoError(t, err) | |
| @@ -80,7 +81,7 @@ func raw(t *testing.T, sock, line string) githttp.HookReply { | |||
| 80 | 81 | ||
| 81 | 82 | func TestHookSocketMode(t *testing.T) { | |
| 82 | 83 | t.Parallel() | |
| 83 | - | _, sock := startHooks(t, ghmocks.NewPushHooks(t)) | |
| 84 | + | _, sock := startHooks(t, mocks.NewPushHookService(t)) | |
| 84 | 85 | fi, err := os.Stat(sock) | |
| 85 | 86 | require.NoError(t, err) | |
| 86 | 87 | assert.Equal(t, os.FileMode(0o600), fi.Mode().Perm()) | |
| @@ -94,21 +95,21 @@ func TestHookServerReplacesStaleSocketFile(t *testing.T) { | |||
| 94 | 95 | defer func() { _ = os.RemoveAll(dir) }() | |
| 95 | 96 | sock := filepath.Join(dir, "hook.sock") | |
| 96 | 97 | require.NoError(t, os.WriteFile(sock, []byte("stale"), 0o600)) | |
| 97 | - | s := githttp.NewHookServer(sock, ghmocks.NewPushHooks(t)) | |
| 98 | + | s := githttp.NewHookServer(sock, mocks.NewPushHookService(t)) | |
| 98 | 99 | require.NoError(t, s.Listen(context.Background())) | |
| 99 | 100 | s.Close(context.Background()) | |
| 100 | 101 | } | |
| 101 | 102 | ||
| 102 | 103 | func TestHookServerRejectsTooLongSocketPath(t *testing.T) { | |
| 103 | 104 | t.Parallel() | |
| 104 | - | s := githttp.NewHookServer("/"+strings.Repeat("a", 120)+"/hook.sock", ghmocks.NewPushHooks(t)) | |
| 105 | + | s := githttp.NewHookServer("/"+strings.Repeat("a", 120)+"/hook.sock", mocks.NewPushHookService(t)) | |
| 105 | 106 | err := s.Listen(context.Background()) | |
| 106 | 107 | require.Error(t, err) | |
| 107 | 108 | assert.Contains(t, err.Error(), "too long") | |
| 108 | 109 | } | |
| 109 | 110 | ||
| 110 | 111 | func TestHookProtocol(t *testing.T) { | |
| 111 | - | hooks := ghmocks.NewPushHooks(t) | |
| 112 | + | hooks := mocks.NewPushHookService(t) | |
| 112 | 113 | srv, sock := startHooks(t, hooks) | |
| 113 | 114 | p := domain.TokenPrincipal(domain.Token{ID: "tok1", Scopes: []domain.Scope{domain.ScopeRepoWrite}}) | |
| 114 | 115 | tokenA, releaseA := srv.Register(context.Background(), repoName(t, "alpha"), p) | |
| @@ -202,7 +203,7 @@ func TestHookProtocol(t *testing.T) { | |||
| 202 | 203 | // push is already in the repository. | |
| 203 | 204 | func TestHookRecordSurvivesShutdown(t *testing.T) { | |
| 204 | 205 | t.Parallel() | |
| 205 | - | hooks := ghmocks.NewPushHooks(t) | |
| 206 | + | hooks := mocks.NewPushHookService(t) | |
| 206 | 207 | started, proceed := make(chan struct{}), make(chan struct{}) | |
| 207 | 208 | var cancelled, hasDeadline bool | |
| 208 | 209 | var ctxMu sync.Mutex | |
| @@ -257,7 +258,7 @@ func TestHookRecordSurvivesShutdown(t *testing.T) { | |||
| 257 | 258 | ||
| 258 | 259 | func TestHookConcurrentTokens(t *testing.T) { | |
| 259 | 260 | t.Parallel() | |
| 260 | - | hooks := ghmocks.NewPushHooks(t) | |
| 261 | + | hooks := mocks.NewPushHookService(t) | |
| 261 | 262 | srv, sock := startHooks(t, hooks) | |
| 262 | 263 | var wg sync.WaitGroup | |
| 263 | 264 | // Each of the 16 tokens reaches the use case for its own repository, once. | |
| @@ -280,7 +281,7 @@ func TestHookConcurrentTokens(t *testing.T) { | |||
| 280 | 281 | ||
| 281 | 282 | func TestRunHook(t *testing.T) { | |
| 282 | 283 | ctx := context.Background() | |
| 283 | - | hooks := ghmocks.NewPushHooks(t) | |
| 284 | + | hooks := mocks.NewPushHookService(t) | |
| 284 | 285 | srv, sock := startHooks(t, hooks) | |
| 285 | 286 | tok, rel := srv.Register(context.Background(), repoName(t, "alpha"), domain.Root()) | |
| 286 | 287 | defer rel() | |
M internal/adapters/rpc/api.go +10 -15
| @@ -18,6 +18,7 @@ import ( | |||
| 18 | 18 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 19 | 19 | "bnema.dev/ermite/internal/clientlimit" | |
| 20 | 20 | "bnema.dev/ermite/internal/domain" | |
| 21 | + | "bnema.dev/ermite/internal/ports" | |
| 21 | 22 | ) | |
| 22 | 23 | ||
| 23 | 24 | // MaxRequestBytes bounds the size of a request message. Responses are not | |
| @@ -28,22 +29,16 @@ const MaxRequestBytes = 1 << 20 | |||
| 28 | 29 | // implements, as GetVersion lists them. | |
| 29 | 30 | var Features = []string{"repo.update", "events.resume", "merge_requests", "merge_requests.delete_branch", "signing_key", "session"} | |
| 30 | 31 | ||
| 31 | - | // Authenticator turns a token secret into a principal, or | |
| 32 | - | // domain.ErrUnauthenticated. app.Auth fits. | |
| 33 | - | type Authenticator interface { | |
| 34 | - | Authenticate(ctx context.Context, secret string) (domain.Principal, error) | |
| 35 | - | } | |
| 36 | - | ||
| 37 | 32 | // Config configures the API. | |
| 38 | 33 | type Config struct { | |
| 39 | - | Auth Authenticator | |
| 40 | - | Repos Repos | |
| 41 | - | Tokens Tokens | |
| 42 | - | Browse Browse | |
| 43 | - | Events Events | |
| 34 | + | Auth ports.AuthService | |
| 35 | + | Repos ports.RepoService | |
| 36 | + | Tokens ports.TokenService | |
| 37 | + | Browse ports.BrowseService | |
| 38 | + | Events ports.EventService | |
| 44 | 39 | // MergeRequests serves MergeRequestService, SigningKey GetSigningKey. | |
| 45 | - | MergeRequests MergeRequests | |
| 46 | - | SigningKey SigningKey | |
| 40 | + | MergeRequests ports.MergeRequestService | |
| 41 | + | SigningKey ports.SigningKeyService | |
| 47 | 42 | Version string | |
| 48 | 43 | // TrustedProxies are the networks allowed to set X-Forwarded-For. | |
| 49 | 44 | TrustedProxies []netip.Prefix | |
| @@ -51,11 +46,11 @@ type Config struct { | |||
| 51 | 46 | // it with the other adapters that authenticate, so that a client has one | |
| 52 | 47 | // budget of failures. Leave it unset rather than assigning a typed nil | |
| 53 | 48 | // pointer (a nil *T in the interface is not nil, and would be called). | |
| 54 | - | Limiter FailureLimiter | |
| 49 | + | Limiter ports.FailureLimiter | |
| 55 | 50 | // Sessions are the owner's web sessions; nil serves no SessionService. | |
| 56 | 51 | // Leave it unset rather than assigning a typed nil pointer (a nil *T in | |
| 57 | 52 | // the interface is not nil, and the service would be served and called). | |
| 58 | - | Sessions Sessions | |
| 53 | + | Sessions ports.SessionService | |
| 59 | 54 | } | |
| 60 | 55 | ||
| 61 | 56 | // API is the set of Connect handlers of the contract. | |
M internal/adapters/rpc/convert.go +4 -4
| @@ -9,8 +9,8 @@ import ( | |||
| 9 | 9 | "google.golang.org/protobuf/types/known/timestamppb" | |
| 10 | 10 | ||
| 11 | 11 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 12 | - | "bnema.dev/ermite/internal/app" | |
| 13 | 12 | "bnema.dev/ermite/internal/domain" | |
| 13 | + | "bnema.dev/ermite/internal/ports" | |
| 14 | 14 | ) | |
| 15 | 15 | ||
| 16 | 16 | // This file maps domain values to the messages of the contract and back. | |
| @@ -55,7 +55,7 @@ func visibilityFromPB(v pb.Visibility) (domain.Visibility, error) { | |||
| 55 | 55 | return "", fmt.Errorf("%w: %v", domain.ErrInvalidVisibility, v) | |
| 56 | 56 | } | |
| 57 | 57 | ||
| 58 | - | func repoToPB(v app.RepoView) *pb.Repo { | |
| 58 | + | func repoToPB(v ports.RepoView) *pb.Repo { | |
| 59 | 59 | settings := v.Settings | |
| 60 | 60 | if settings.IsZero() { | |
| 61 | 61 | settings = domain.DefaultRepoSettings() | |
| @@ -361,7 +361,7 @@ func refUpdatesToPB(updates []domain.RefUpdate) []*pb.RefUpdate { | |||
| 361 | 361 | ||
| 362 | 362 | // watchEventToPB maps one item of a watch; nil when the event has no | |
| 363 | 363 | // representation in the contract. | |
| 364 | - | func watchEventToPB(we app.WatchEvent) *pb.Event { | |
| 364 | + | func watchEventToPB(we ports.WatchEvent) *pb.Event { | |
| 365 | 365 | if we.Gap { | |
| 366 | 366 | return &pb.Event{Kind: &pb.Event_Gap{Gap: &pb.Gap{}}} | |
| 367 | 367 | } | |
| @@ -397,7 +397,7 @@ func watchEventToPB(we app.WatchEvent) *pb.Event { | |||
| 397 | 397 | return out | |
| 398 | 398 | } | |
| 399 | 399 | ||
| 400 | - | func repoOrName(we app.WatchEvent, name domain.RepoName, vis domain.Visibility) *pb.Repo { | |
| 400 | + | func repoOrName(we ports.WatchEvent, name domain.RepoName, vis domain.Visibility) *pb.Repo { | |
| 401 | 401 | if we.Repo != nil { | |
| 402 | 402 | return repoToPB(*we.Repo) | |
| 403 | 403 | } | |
M internal/adapters/rpc/convert_test.go +5 -5
| @@ -15,8 +15,8 @@ import ( | |||
| 15 | 15 | "google.golang.org/protobuf/types/known/fieldmaskpb" | |
| 16 | 16 | ||
| 17 | 17 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 18 | - | "bnema.dev/ermite/internal/app" | |
| 19 | 18 | "bnema.dev/ermite/internal/domain" | |
| 19 | + | "bnema.dev/ermite/internal/ports" | |
| 20 | 20 | ) | |
| 21 | 21 | ||
| 22 | 22 | // Every value of the domain maps to a real value of the contract, never to | |
| @@ -212,12 +212,12 @@ func TestCommentID(t *testing.T) { | |||
| 212 | 212 | func TestRepoToPBAlwaysHasSettings(t *testing.T) { | |
| 213 | 213 | t.Parallel() | |
| 214 | 214 | // A repository value without settings (never stored with them) reads as the defaults. | |
| 215 | - | r := repoToPB(app.RepoView{Repo: domain.Repo{Name: mustName(t, "x")}}) | |
| 215 | + | r := repoToPB(ports.RepoView{Repo: domain.Repo{Name: mustName(t, "x")}}) | |
| 216 | 216 | assert.Equal(t, []pb.MergeMode{pb.MergeMode_MERGE_MODE_FAST_FORWARD, pb.MergeMode_MERGE_MODE_SQUASH}, r.GetSettings().GetAllowedMergeModes()) | |
| 217 | 217 | assert.True(t, r.GetSettings().GetFailingChecksBlock()) | |
| 218 | 218 | ||
| 219 | 219 | custom := domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}} | |
| 220 | - | r = repoToPB(app.RepoView{Repo: domain.Repo{Name: mustName(t, "x"), Settings: custom}}) | |
| 220 | + | r = repoToPB(ports.RepoView{Repo: domain.Repo{Name: mustName(t, "x"), Settings: custom}}) | |
| 221 | 221 | assert.Equal(t, []pb.MergeMode{pb.MergeMode_MERGE_MODE_SQUASH}, r.GetSettings().GetAllowedMergeModes()) | |
| 222 | 222 | assert.False(t, r.GetSettings().GetFailingChecksBlock()) | |
| 223 | 223 | } | |
| @@ -313,7 +313,7 @@ func TestWatchEventToPBMergeRequestEvents(t *testing.T) { | |||
| 313 | 313 | } { | |
| 314 | 314 | t.Run(name, func(t *testing.T) { | |
| 315 | 315 | t.Parallel() | |
| 316 | - | got := watchEventToPB(app.WatchEvent{ID: "e1", Event: tc.ev}) | |
| 316 | + | got := watchEventToPB(ports.WatchEvent{ID: "e1", Event: tc.ev}) | |
| 317 | 317 | require.NotNil(t, got) | |
| 318 | 318 | assert.Equal(t, "e1", got.GetId()) | |
| 319 | 319 | assert.Equal(t, at, got.GetTime().AsTime()) | |
| @@ -327,7 +327,7 @@ func TestWatchEventToPBMergeRequestEvents(t *testing.T) { | |||
| 327 | 327 | } | |
| 328 | 328 | ||
| 329 | 329 | c := domain.Comment{ID: 9, Author: "root", Path: "a.txt", Line: 3, Side: domain.SideOld, CreatedAt: at} | |
| 330 | - | got := watchEventToPB(app.WatchEvent{ID: "e2", Event: domain.CommentAdded{Repo: repo, Number: 4, Comment: c, At: at}}) | |
| 330 | + | got := watchEventToPB(ports.WatchEvent{ID: "e2", Event: domain.CommentAdded{Repo: repo, Number: 4, Comment: c, At: at}}) | |
| 331 | 331 | added := got.GetCommentAdded() | |
| 332 | 332 | require.NotNil(t, added) | |
| 333 | 333 | assert.Equal(t, "proj", added.GetRepo()) | |
M internal/adapters/rpc/event.go +4 -4
| @@ -8,11 +8,11 @@ import ( | |||
| 8 | 8 | "connectrpc.com/connect" | |
| 9 | 9 | ||
| 10 | 10 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 11 | - | "bnema.dev/ermite/internal/app" | |
| 11 | + | "bnema.dev/ermite/internal/ports" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | 14 | // eventService implements ermiteconnect.EventServiceHandler. | |
| 15 | - | type eventService struct{ events Events } | |
| 15 | + | type eventService struct{ events ports.EventService } | |
| 16 | 16 | ||
| 17 | 17 | // Watch streams events until the client goes away or the server stops. The | |
| 18 | 18 | // stream ends with success in both cases: the contract has no error for | |
| @@ -20,7 +20,7 @@ type eventService struct{ events Events } | |||
| 20 | 20 | // the caller is revoked or expires, and a caller that has too many streams | |
| 21 | 21 | // open gets resource_exhausted. | |
| 22 | 22 | func (s *eventService) Watch(ctx context.Context, req *connect.Request[pb.WatchRequest], stream *connect.ServerStream[pb.WatchResponse]) error { | |
| 23 | - | params := app.WatchParams{ | |
| 23 | + | params := ports.WatchParams{ | |
| 24 | 24 | Topics: req.Msg.GetTopics(), ResumeAfter: req.Msg.GetResumeAfter(), | |
| 25 | 25 | Client: clientFromContext(ctx), | |
| 26 | 26 | // A client's call returns when the response begins: send the headers | |
| @@ -28,7 +28,7 @@ func (s *eventService) Watch(ctx context.Context, req *connect.Request[pb.WatchR | |||
| 28 | 28 | // them for a nil message. A failure shows on the first real send. | |
| 29 | 29 | Ready: func() { _ = stream.Send(nil) }, | |
| 30 | 30 | } | |
| 31 | - | err := s.events.Watch(ctx, caller(ctx), params, func(we app.WatchEvent) error { | |
| 31 | + | err := s.events.Watch(ctx, caller(ctx), params, func(we ports.WatchEvent) error { | |
| 32 | 32 | ev := watchEventToPB(we) | |
| 33 | 33 | if ev == nil { | |
| 34 | 34 | return nil | |
M internal/adapters/rpc/git.go +4 -4
| @@ -11,15 +11,15 @@ import ( | |||
| 11 | 11 | "connectrpc.com/connect" | |
| 12 | 12 | ||
| 13 | 13 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 14 | - | "bnema.dev/ermite/internal/app" | |
| 15 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 16 | 16 | ) | |
| 17 | 17 | ||
| 18 | 18 | // BlobChunkSize is the largest chunk of a GetBlob stream. | |
| 19 | 19 | const BlobChunkSize = 64 << 10 | |
| 20 | 20 | ||
| 21 | 21 | // gitService implements ermiteconnect.GitServiceHandler. | |
| 22 | - | type gitService struct{ browse Browse } | |
| 22 | + | type gitService struct{ browse ports.BrowseService } | |
| 23 | 23 | ||
| 24 | 24 | // target is the repository and revision most requests start with. | |
| 25 | 25 | func target(repo, revision string) (domain.RepoName, domain.Revision, error) { | |
| @@ -39,7 +39,7 @@ func (s *gitService) ListRefs(ctx context.Context, req *connect.Request[pb.ListR | |||
| 39 | 39 | if err != nil { | |
| 40 | 40 | return nil, connectError(ctx, err) | |
| 41 | 41 | } | |
| 42 | - | params := app.ListRefsParams{PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken()} | |
| 42 | + | params := ports.ListRefsParams{PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken()} | |
| 43 | 43 | for _, k := range req.Msg.GetKinds() { | |
| 44 | 44 | kind, err := refKindFromPB(k) | |
| 45 | 45 | if err != nil { | |
| @@ -144,7 +144,7 @@ func (s *gitService) ListCommits(ctx context.Context, req *connect.Request[pb.Li | |||
| 144 | 144 | if err != nil { | |
| 145 | 145 | return nil, connectError(ctx, err) | |
| 146 | 146 | } | |
| 147 | - | page, err := s.browse.ListCommits(ctx, caller(ctx), name, app.ListCommitsParams{ | |
| 147 | + | page, err := s.browse.ListCommits(ctx, caller(ctx), name, ports.ListCommitsParams{ | |
| 148 | 148 | Revision: rev, Path: path, PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken(), | |
| 149 | 149 | }) | |
| 150 | 150 | if err != nil { | |
M internal/adapters/rpc/git_test.go +12 -12
| @@ -11,9 +11,9 @@ import ( | |||
| 11 | 11 | "github.com/stretchr/testify/require" | |
| 12 | 12 | ||
| 13 | 13 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |
| 15 | - | "bnema.dev/ermite/internal/app" | |
| 16 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 16 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 17 | 17 | ) | |
| 18 | 18 | ||
| 19 | 19 | func TestGitServiceGetTree(t *testing.T) { | |
| @@ -34,7 +34,7 @@ func TestGitServiceGetTree(t *testing.T) { | |||
| 34 | 34 | for _, tt := range tests { | |
| 35 | 35 | t.Run(tt.name, func(t *testing.T) { | |
| 36 | 36 | t.Parallel() | |
| 37 | - | browse := mocks.NewBrowse(t) | |
| 37 | + | browse := mocks.NewBrowseService(t) | |
| 38 | 38 | if tt.wantCall { | |
| 39 | 39 | browse.EXPECT().GetTree(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything, mock.Anything, false). | |
| 40 | 40 | Return(domain.Tree{}, tt.usecase).Once() | |
| @@ -68,10 +68,10 @@ func TestGitServiceListRefs(t *testing.T) { | |||
| 68 | 68 | for _, tt := range tests { | |
| 69 | 69 | t.Run(tt.name, func(t *testing.T) { | |
| 70 | 70 | t.Parallel() | |
| 71 | - | browse := mocks.NewBrowse(t) | |
| 71 | + | browse := mocks.NewBrowseService(t) | |
| 72 | 72 | if tt.wantCall { | |
| 73 | 73 | browse.EXPECT().ListRefs(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything). | |
| 74 | - | Return(app.RefPage{NextPageToken: "n"}, tt.usecase).Once() | |
| 74 | + | Return(ports.RefPage{NextPageToken: "n"}, tt.usecase).Once() | |
| 75 | 75 | } | |
| 76 | 76 | resp, err := (&gitService{browse}).ListRefs(ownerCtx(), connect.NewRequest(tt.req)) | |
| 77 | 77 | if tt.wantCode != 0 { | |
| @@ -93,26 +93,26 @@ func TestGitServiceGetCommitAndResolveRevision(t *testing.T) { | |||
| 93 | 93 | for _, tt := range invalid { | |
| 94 | 94 | t.Run("GetCommit "+tt.name, func(t *testing.T) { | |
| 95 | 95 | t.Parallel() | |
| 96 | - | _, err := (&gitService{mocks.NewBrowse(t)}).GetCommit(ownerCtx(), connect.NewRequest(&pb.GetCommitRequest{Repo: tt.repo, Revision: tt.rev})) | |
| 96 | + | _, err := (&gitService{mocks.NewBrowseService(t)}).GetCommit(ownerCtx(), connect.NewRequest(&pb.GetCommitRequest{Repo: tt.repo, Revision: tt.rev})) | |
| 97 | 97 | requireCode(t, connect.CodeInvalidArgument, err) | |
| 98 | 98 | }) | |
| 99 | 99 | t.Run("ResolveRevision "+tt.name, func(t *testing.T) { | |
| 100 | 100 | t.Parallel() | |
| 101 | - | _, err := (&gitService{mocks.NewBrowse(t)}).ResolveRevision(ownerCtx(), connect.NewRequest(&pb.ResolveRevisionRequest{Repo: tt.repo, Revision: tt.rev})) | |
| 101 | + | _, err := (&gitService{mocks.NewBrowseService(t)}).ResolveRevision(ownerCtx(), connect.NewRequest(&pb.ResolveRevisionRequest{Repo: tt.repo, Revision: tt.rev})) | |
| 102 | 102 | requireCode(t, connect.CodeInvalidArgument, err) | |
| 103 | 103 | }) | |
| 104 | 104 | } | |
| 105 | 105 | ||
| 106 | 106 | t.Run("GetCommit not found", func(t *testing.T) { | |
| 107 | 107 | t.Parallel() | |
| 108 | - | browse := mocks.NewBrowse(t) | |
| 108 | + | browse := mocks.NewBrowseService(t) | |
| 109 | 109 | browse.EXPECT().GetCommit(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything).Return(domain.CommitDetail{}, domain.ErrNotFound).Once() | |
| 110 | 110 | _, err := (&gitService{browse}).GetCommit(ownerCtx(), connect.NewRequest(&pb.GetCommitRequest{Repo: "demo", Revision: "main"})) | |
| 111 | 111 | requireCode(t, connect.CodeNotFound, err) | |
| 112 | 112 | }) | |
| 113 | 113 | t.Run("ResolveRevision ok", func(t *testing.T) { | |
| 114 | 114 | t.Parallel() | |
| 115 | - | browse := mocks.NewBrowse(t) | |
| 115 | + | browse := mocks.NewBrowseService(t) | |
| 116 | 116 | browse.EXPECT().ResolveRevision(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything). | |
| 117 | 117 | Return(domain.ResolvedRevision{Ref: "refs/heads/main"}, nil).Once() | |
| 118 | 118 | resp, err := (&gitService{browse}).ResolveRevision(ownerCtx(), connect.NewRequest(&pb.ResolveRevisionRequest{Repo: "demo", Revision: "main"})) | |
| @@ -138,10 +138,10 @@ func TestGitServiceListCommits(t *testing.T) { | |||
| 138 | 138 | for _, tt := range tests { | |
| 139 | 139 | t.Run(tt.name, func(t *testing.T) { | |
| 140 | 140 | t.Parallel() | |
| 141 | - | browse := mocks.NewBrowse(t) | |
| 141 | + | browse := mocks.NewBrowseService(t) | |
| 142 | 142 | if tt.wantCall { | |
| 143 | 143 | browse.EXPECT().ListCommits(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything). | |
| 144 | - | Return(app.CommitPage{}, tt.usecase).Once() | |
| 144 | + | Return(ports.HistoryPage{}, tt.usecase).Once() | |
| 145 | 145 | } | |
| 146 | 146 | _, err := (&gitService{browse}).ListCommits(ownerCtx(), connect.NewRequest(tt.req)) | |
| 147 | 147 | if tt.wantCode != 0 { | |
| @@ -167,7 +167,7 @@ func TestGitServiceGetBlobRejectsBadInput(t *testing.T) { | |||
| 167 | 167 | for _, tt := range tests { | |
| 168 | 168 | t.Run(tt.name, func(t *testing.T) { | |
| 169 | 169 | t.Parallel() | |
| 170 | - | err := (&gitService{mocks.NewBrowse(t)}).GetBlob(ownerCtx(), connect.NewRequest(tt.req), nil) | |
| 170 | + | err := (&gitService{mocks.NewBrowseService(t)}).GetBlob(ownerCtx(), connect.NewRequest(tt.req), nil) | |
| 171 | 171 | requireCode(t, connect.CodeInvalidArgument, err) | |
| 172 | 172 | }) | |
| 173 | 173 | } | |
M internal/adapters/rpc/interceptor.go +3 -2
| @@ -18,6 +18,7 @@ import ( | |||
| 18 | 18 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 19 | 19 | "bnema.dev/ermite/internal/clientlimit" | |
| 20 | 20 | "bnema.dev/ermite/internal/domain" | |
| 21 | + | "bnema.dev/ermite/internal/ports" | |
| 21 | 22 | ) | |
| 22 | 23 | ||
| 23 | 24 | var errInternal = errors.New("internal error") | |
| @@ -37,8 +38,8 @@ var errInternal = errors.New("internal error") | |||
| 37 | 38 | // put there by a server's base context, is ignored and the request is | |
| 38 | 39 | // authenticated from its headers. | |
| 39 | 40 | type interceptor struct { | |
| 40 | - | auth Authenticator | |
| 41 | - | limiter FailureLimiter | |
| 41 | + | auth ports.AuthService | |
| 42 | + | limiter ports.FailureLimiter | |
| 42 | 43 | trusted []netip.Prefix | |
| 43 | 44 | } | |
| 44 | 45 | ||
M internal/adapters/rpc/interceptor_test.go +3 -3
| @@ -15,8 +15,8 @@ import ( | |||
| 15 | 15 | "github.com/stretchr/testify/require" | |
| 16 | 16 | ||
| 17 | 17 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 18 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |
| 19 | 18 | "bnema.dev/ermite/internal/domain" | |
| 19 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 20 | 20 | ) | |
| 21 | 21 | ||
| 22 | 22 | const peer = "203.0.113.7:4242" | |
| @@ -69,7 +69,7 @@ func TestInterceptorAuthenticate(t *testing.T) { | |||
| 69 | 69 | for _, tt := range tests { | |
| 70 | 70 | t.Run(tt.name, func(t *testing.T) { | |
| 71 | 71 | t.Parallel() | |
| 72 | - | auth := mocks.NewAuthenticator(t) | |
| 72 | + | auth := mocks.NewAuthService(t) | |
| 73 | 73 | limiter := mocks.NewFailureLimiter(t) | |
| 74 | 74 | if tt.wantLimit { | |
| 75 | 75 | wait := time.Duration(0) | |
| @@ -117,7 +117,7 @@ func TestInterceptorIgnoresForwardedForFromUntrustedPeer(t *testing.T) { | |||
| 117 | 117 | limiter.EXPECT().Blocked(mock.Anything, "203.0.113.7").Return(false, time.Duration(0)).Once() | |
| 118 | 118 | h := bearerHeader("") | |
| 119 | 119 | h.Set("X-Forwarded-For", "198.51.100.1") | |
| 120 | - | i := newInterceptor(Config{Auth: mocks.NewAuthenticator(t), Limiter: limiter}) | |
| 120 | + | i := newInterceptor(Config{Auth: mocks.NewAuthService(t), Limiter: limiter}) | |
| 121 | 121 | _, err := i.authenticate(context.Background(), ermiteconnect.RepoServiceListReposProcedure, peer, h) | |
| 122 | 122 | require.NoError(t, err) | |
| 123 | 123 | } | |
M internal/adapters/rpc/mergerequest.go +6 -6
| @@ -10,12 +10,12 @@ import ( | |||
| 10 | 10 | "connectrpc.com/connect" | |
| 11 | 11 | ||
| 12 | 12 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 13 | - | "bnema.dev/ermite/internal/app" | |
| 14 | 13 | "bnema.dev/ermite/internal/domain" | |
| 14 | + | "bnema.dev/ermite/internal/ports" | |
| 15 | 15 | ) | |
| 16 | 16 | ||
| 17 | 17 | // mergeRequestService implements ermiteconnect.MergeRequestServiceHandler. | |
| 18 | - | type mergeRequestService struct{ mrs MergeRequests } | |
| 18 | + | type mergeRequestService struct{ mrs ports.MergeRequestService } | |
| 19 | 19 | ||
| 20 | 20 | func mergeRequestStateToPB(s domain.MRState) pb.MergeRequestState { | |
| 21 | 21 | switch s { | |
| @@ -129,7 +129,7 @@ func (s *mergeRequestService) CreateMergeRequest(ctx context.Context, req *conne | |||
| 129 | 129 | if err != nil { | |
| 130 | 130 | return nil, connectError(ctx, err) | |
| 131 | 131 | } | |
| 132 | - | mr, err := s.mrs.Create(ctx, caller(ctx), name, app.CreateMergeRequestParams{ | |
| 132 | + | mr, err := s.mrs.Create(ctx, caller(ctx), name, ports.CreateMergeRequestParams{ | |
| 133 | 133 | Title: req.Msg.GetTitle(), Description: req.Msg.GetDescription(), | |
| 134 | 134 | Source: req.Msg.GetSourceBranch(), Target: req.Msg.GetTargetBranch(), | |
| 135 | 135 | }) | |
| @@ -148,7 +148,7 @@ func (s *mergeRequestService) ListMergeRequests(ctx context.Context, req *connec | |||
| 148 | 148 | if err != nil { | |
| 149 | 149 | return nil, connectError(ctx, err) | |
| 150 | 150 | } | |
| 151 | - | page, err := s.mrs.List(ctx, caller(ctx), name, app.ListMergeRequestsParams{ | |
| 151 | + | page, err := s.mrs.List(ctx, caller(ctx), name, ports.ListMergeRequestsParams{ | |
| 152 | 152 | State: state, PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken(), | |
| 153 | 153 | }) | |
| 154 | 154 | if err != nil { | |
| @@ -197,7 +197,7 @@ func (s *mergeRequestService) AddComment(ctx context.Context, req *connect.Reque | |||
| 197 | 197 | if err != nil { | |
| 198 | 198 | return nil, connectError(ctx, err) | |
| 199 | 199 | } | |
| 200 | - | c, err := s.mrs.AddComment(ctx, caller(ctx), name, req.Msg.GetNumber(), app.AddCommentParams{ | |
| 200 | + | c, err := s.mrs.AddComment(ctx, caller(ctx), name, req.Msg.GetNumber(), ports.AddCommentParams{ | |
| 201 | 201 | Path: req.Msg.GetPath(), Line: int(req.Msg.GetLine()), Side: side, Text: req.Msg.GetText(), | |
| 202 | 202 | }) | |
| 203 | 203 | if err != nil { | |
| @@ -245,7 +245,7 @@ func (s *mergeRequestService) MergeMergeRequest(ctx context.Context, req *connec | |||
| 245 | 245 | if err != nil { | |
| 246 | 246 | return nil, connectError(ctx, err) | |
| 247 | 247 | } | |
| 248 | - | res, err := s.mrs.Merge(ctx, caller(ctx), name, req.Msg.GetNumber(), app.MergeParams{ | |
| 248 | + | res, err := s.mrs.Merge(ctx, caller(ctx), name, req.Msg.GetNumber(), ports.MergeParams{ | |
| 249 | 249 | Mode: mode, HeadID: head, DeleteSource: req.Msg.GetDeleteSourceBranch(), | |
| 250 | 250 | }) | |
| 251 | 251 | if err != nil { | |
M internal/adapters/rpc/mergerequest_test.go +19 -19
| @@ -11,9 +11,9 @@ import ( | |||
| 11 | 11 | "github.com/stretchr/testify/require" | |
| 12 | 12 | ||
| 13 | 13 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |
| 15 | - | "bnema.dev/ermite/internal/app" | |
| 16 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 16 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 17 | 17 | ) | |
| 18 | 18 | ||
| 19 | 19 | func TestMergeRequestServiceCreate(t *testing.T) { | |
| @@ -35,9 +35,9 @@ func TestMergeRequestServiceCreate(t *testing.T) { | |||
| 35 | 35 | for _, tt := range tests { | |
| 36 | 36 | t.Run(tt.name, func(t *testing.T) { | |
| 37 | 37 | t.Parallel() | |
| 38 | - | mrs := mocks.NewMergeRequests(t) | |
| 38 | + | mrs := mocks.NewMergeRequestService(t) | |
| 39 | 39 | if tt.wantCall { | |
| 40 | - | mrs.EXPECT().Create(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), app.CreateMergeRequestParams{ | |
| 40 | + | mrs.EXPECT().Create(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), ports.CreateMergeRequestParams{ | |
| 41 | 41 | Title: "t", Description: "d", Source: "feat", Target: "main", | |
| 42 | 42 | }).Return(domain.MergeRequest{Number: 7, Source: "feat", Target: "main", State: domain.MRStateOpen}, tt.usecase).Once() | |
| 43 | 43 | } | |
| @@ -57,17 +57,17 @@ func TestMergeRequestServiceCreate(t *testing.T) { | |||
| 57 | 57 | ||
| 58 | 58 | func TestMergeRequestServiceListRejectsUnknownState(t *testing.T) { | |
| 59 | 59 | t.Parallel() | |
| 60 | - | _, err := (&mergeRequestService{mocks.NewMergeRequests(t)}).ListMergeRequests(ownerCtx(), | |
| 60 | + | _, err := (&mergeRequestService{mocks.NewMergeRequestService(t)}).ListMergeRequests(ownerCtx(), | |
| 61 | 61 | connect.NewRequest(&pb.ListMergeRequestsRequest{Repo: "demo", State: pb.MergeRequestState(99)})) | |
| 62 | 62 | requireCode(t, connect.CodeInvalidArgument, err) | |
| 63 | 63 | } | |
| 64 | 64 | ||
| 65 | 65 | func TestMergeRequestServiceListFiltersByState(t *testing.T) { | |
| 66 | 66 | t.Parallel() | |
| 67 | - | mrs := mocks.NewMergeRequests(t) | |
| 68 | - | mrs.EXPECT().List(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), app.ListMergeRequestsParams{ | |
| 67 | + | mrs := mocks.NewMergeRequestService(t) | |
| 68 | + | mrs.EXPECT().List(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), ports.ListMergeRequestsParams{ | |
| 69 | 69 | State: domain.MRStateMerged, PageSize: 3, PageToken: "tok", | |
| 70 | - | }).Return(app.MergeRequestPage{MergeRequests: []domain.MergeRequest{{Number: 1}}, NextPageToken: "n"}, nil).Once() | |
| 70 | + | }).Return(ports.MergeRequestPage{MergeRequests: []domain.MergeRequest{{Number: 1}}, NextPageToken: "n"}, nil).Once() | |
| 71 | 71 | resp, err := (&mergeRequestService{mrs}).ListMergeRequests(ownerCtx(), connect.NewRequest(&pb.ListMergeRequestsRequest{ | |
| 72 | 72 | Repo: "demo", State: pb.MergeRequestState_MERGE_REQUEST_STATE_MERGED, PageSize: 3, PageToken: "tok", | |
| 73 | 73 | })) | |
| @@ -94,7 +94,7 @@ func TestMergeRequestServiceAddComment(t *testing.T) { | |||
| 94 | 94 | for _, tt := range tests { | |
| 95 | 95 | t.Run(tt.name, func(t *testing.T) { | |
| 96 | 96 | t.Parallel() | |
| 97 | - | mrs := mocks.NewMergeRequests(t) | |
| 97 | + | mrs := mocks.NewMergeRequestService(t) | |
| 98 | 98 | if tt.wantCall { | |
| 99 | 99 | mrs.EXPECT().AddComment(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(2), mock.Anything). | |
| 100 | 100 | Return(domain.Comment{ID: 5}, tt.usecase).Once() | |
| @@ -117,7 +117,7 @@ func TestMergeRequestServiceResolveCommentMapsUnissuedIDsToZero(t *testing.T) { | |||
| 117 | 117 | for _, id := range []string{"", "abc", "-1", "0", "007", "99999999999999999999"} { | |
| 118 | 118 | t.Run(id, func(t *testing.T) { | |
| 119 | 119 | t.Parallel() | |
| 120 | - | mrs := mocks.NewMergeRequests(t) | |
| 120 | + | mrs := mocks.NewMergeRequestService(t) | |
| 121 | 121 | mrs.EXPECT().ResolveComment(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), int64(0), true). | |
| 122 | 122 | Return(domain.Comment{}, domain.ErrNotFound).Once() | |
| 123 | 123 | _, err := (&mergeRequestService{mrs}).ResolveComment(ownerCtx(), connect.NewRequest(&pb.ResolveCommentRequest{ | |
| @@ -148,11 +148,11 @@ func TestMergeRequestServiceMerge(t *testing.T) { | |||
| 148 | 148 | for _, tt := range tests { | |
| 149 | 149 | t.Run(tt.name, func(t *testing.T) { | |
| 150 | 150 | t.Parallel() | |
| 151 | - | mrs := mocks.NewMergeRequests(t) | |
| 151 | + | mrs := mocks.NewMergeRequestService(t) | |
| 152 | 152 | if tt.wantCall { | |
| 153 | - | mrs.EXPECT().Merge(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), mock.MatchedBy(func(p app.MergeParams) bool { | |
| 153 | + | mrs.EXPECT().Merge(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), mock.MatchedBy(func(p ports.MergeParams) bool { | |
| 154 | 154 | return p.DeleteSource == tt.req.GetDeleteSourceBranch() && (tt.req.GetHeadId() == "") == p.HeadID.IsZero() | |
| 155 | - | })).Return(app.MergeResult{MergeRequest: domain.MergeRequest{Number: 1}, SourceDeleted: true}, tt.usecase).Once() | |
| 155 | + | })).Return(ports.MergeResult{MergeRequest: domain.MergeRequest{Number: 1}, SourceDeleted: true}, tt.usecase).Once() | |
| 156 | 156 | } | |
| 157 | 157 | resp, err := (&mergeRequestService{mrs}).MergeMergeRequest(ownerCtx(), connect.NewRequest(tt.req)) | |
| 158 | 158 | if tt.wantCode != 0 { | |
| @@ -169,14 +169,14 @@ func TestMergeRequestServiceCloseAndMarkRead(t *testing.T) { | |||
| 169 | 169 | t.Parallel() | |
| 170 | 170 | t.Run("close not found", func(t *testing.T) { | |
| 171 | 171 | t.Parallel() | |
| 172 | - | mrs := mocks.NewMergeRequests(t) | |
| 172 | + | mrs := mocks.NewMergeRequestService(t) | |
| 173 | 173 | mrs.EXPECT().Close(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(9)).Return(domain.MergeRequest{}, domain.ErrNotFound).Once() | |
| 174 | 174 | _, err := (&mergeRequestService{mrs}).CloseMergeRequest(ownerCtx(), connect.NewRequest(&pb.CloseMergeRequestRequest{Repo: "demo", Number: 9})) | |
| 175 | 175 | requireCode(t, connect.CodeNotFound, err) | |
| 176 | 176 | }) | |
| 177 | 177 | t.Run("close ok", func(t *testing.T) { | |
| 178 | 178 | t.Parallel() | |
| 179 | - | mrs := mocks.NewMergeRequests(t) | |
| 179 | + | mrs := mocks.NewMergeRequestService(t) | |
| 180 | 180 | mrs.EXPECT().Close(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(9)).Return(domain.MergeRequest{Number: 9, State: domain.MRStateClosed}, nil).Once() | |
| 181 | 181 | resp, err := (&mergeRequestService{mrs}).CloseMergeRequest(ownerCtx(), connect.NewRequest(&pb.CloseMergeRequestRequest{Repo: "demo", Number: 9})) | |
| 182 | 182 | require.NoError(t, err) | |
| @@ -184,13 +184,13 @@ func TestMergeRequestServiceCloseAndMarkRead(t *testing.T) { | |||
| 184 | 184 | }) | |
| 185 | 185 | t.Run("mark read rejects a short head", func(t *testing.T) { | |
| 186 | 186 | t.Parallel() | |
| 187 | - | _, err := (&mergeRequestService{mocks.NewMergeRequests(t)}).MarkRead(ownerCtx(), | |
| 187 | + | _, err := (&mergeRequestService{mocks.NewMergeRequestService(t)}).MarkRead(ownerCtx(), | |
| 188 | 188 | connect.NewRequest(&pb.MarkReadRequest{Repo: "demo", Number: 1, HeadId: "abc"})) | |
| 189 | 189 | requireCode(t, connect.CodeInvalidArgument, err) | |
| 190 | 190 | }) | |
| 191 | 191 | t.Run("mark read unauthenticated", func(t *testing.T) { | |
| 192 | 192 | t.Parallel() | |
| 193 | - | mrs := mocks.NewMergeRequests(t) | |
| 193 | + | mrs := mocks.NewMergeRequestService(t) | |
| 194 | 194 | mrs.EXPECT().MarkRead(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), domain.ObjectID{}).Return(domain.ObjectID{}, domain.ErrUnauthenticated).Once() | |
| 195 | 195 | _, err := (&mergeRequestService{mrs}).MarkRead(ownerCtx(), connect.NewRequest(&pb.MarkReadRequest{Repo: "demo", Number: 1})) | |
| 196 | 196 | requireCode(t, connect.CodeUnauthenticated, err) | |
| @@ -211,9 +211,9 @@ func TestMergeRequestServiceGet(t *testing.T) { | |||
| 211 | 211 | for _, tt := range tests { | |
| 212 | 212 | t.Run(tt.name, func(t *testing.T) { | |
| 213 | 213 | t.Parallel() | |
| 214 | - | mrs := mocks.NewMergeRequests(t) | |
| 214 | + | mrs := mocks.NewMergeRequestService(t) | |
| 215 | 215 | mrs.EXPECT().Get(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(4), true). | |
| 216 | - | Return(app.MergeRequestDetail{MergeRequest: domain.MergeRequest{Number: 4}, CommitsTruncated: true}, tt.usecase).Once() | |
| 216 | + | Return(ports.MergeRequestDetail{MergeRequest: domain.MergeRequest{Number: 4}, CommitsTruncated: true}, tt.usecase).Once() | |
| 217 | 217 | resp, err := (&mergeRequestService{mrs}).GetMergeRequest(ownerCtx(), connect.NewRequest(&pb.GetMergeRequestRequest{Repo: "demo", Number: 4, SinceLastRead: true})) | |
| 218 | 218 | if tt.wantCode != 0 { | |
| 219 | 219 | requireCode(t, tt.wantCode, err) | |
D internal/adapters/rpc/mocks/Authenticator.go +0 -114
| @@ -1,114 +0,0 @@ | |||
| 1 | - | // Code generated by mockery; DO NOT EDIT. | |
| 2 | - | // github.com/vektra/mockery | |
| 3 | - | // template: testify | |
| 4 | - | ||
| 5 | - | package mocks | |
| 6 | - | ||
| 7 | - | import ( | |
| 8 | - | "context" | |
| 9 | - | ||
| 10 | - | "bnema.dev/ermite/internal/domain" | |
| 11 | - | mock "github.com/stretchr/testify/mock" | |
| 12 | - | ) | |
| 13 | - | ||
| 14 | - | // NewAuthenticator creates a new instance of Authenticator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | - | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewAuthenticator(t interface { | |
| 17 | - | mock.TestingT | |
| 18 | - | Cleanup(func()) | |
| 19 | - | }) *Authenticator { | |
| 20 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | - | helper.Helper() | |
| 22 | - | } | |
| 23 | - | ||
| 24 | - | mock := &Authenticator{} | |
| 25 | - | mock.Mock.Test(t) | |
| 26 | - | ||
| 27 | - | t.Cleanup(func() { | |
| 28 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 29 | - | helper.Helper() | |
| 30 | - | } | |
| 31 | - | mock.AssertExpectations(t) | |
| 32 | - | }) | |
| 33 | - | ||
| 34 | - | return mock | |
| 35 | - | } | |
| 36 | - | ||
| 37 | - | // Authenticator is an autogenerated mock type for the Authenticator type | |
| 38 | - | type Authenticator struct { | |
| 39 | - | mock.Mock | |
| 40 | - | } | |
| 41 | - | ||
| 42 | - | type Authenticator_Expecter struct { | |
| 43 | - | mock *mock.Mock | |
| 44 | - | } | |
| 45 | - | ||
| 46 | - | func (_m *Authenticator) EXPECT() *Authenticator_Expecter { | |
| 47 | - | return &Authenticator_Expecter{mock: &_m.Mock} | |
| 48 | - | } | |
| 49 | - | ||
| 50 | - | // Authenticate provides a mock function for the type Authenticator | |
| 51 | - | func (_mock *Authenticator) Authenticate(ctx context.Context, secret string) (domain.Principal, error) { | |
| 52 | - | ret := _mock.Called(ctx, secret) | |
| 53 | - | ||
| 54 | - | if len(ret) == 0 { | |
| 55 | - | panic("no return value specified for Authenticate") | |
| 56 | - | } | |
| 57 | - | ||
| 58 | - | var r0 domain.Principal | |
| 59 | - | var r1 error | |
| 60 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, string) (domain.Principal, error)); ok { | |
| 61 | - | return returnFunc(ctx, secret) | |
| 62 | - | } | |
| 63 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, string) domain.Principal); ok { | |
| 64 | - | r0 = returnFunc(ctx, secret) | |
| 65 | - | } else { | |
| 66 | - | r0 = ret.Get(0).(domain.Principal) | |
| 67 | - | } | |
| 68 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok { | |
| 69 | - | r1 = returnFunc(ctx, secret) | |
| 70 | - | } else { | |
| 71 | - | r1 = ret.Error(1) | |
| 72 | - | } | |
| 73 | - | return r0, r1 | |
| 74 | - | } | |
| 75 | - | ||
| 76 | - | // Authenticator_Authenticate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Authenticate' | |
| 77 | - | type Authenticator_Authenticate_Call struct { | |
| 78 | - | *mock.Call | |
| 79 | - | } | |
| 80 | - | ||
| 81 | - | // Authenticate is a helper method to define mock.On call | |
| 82 | - | // - ctx context.Context | |
| 83 | - | // - secret string | |
| 84 | - | func (_e *Authenticator_Expecter) Authenticate(ctx any, secret any) *Authenticator_Authenticate_Call { | |
| 85 | - | return &Authenticator_Authenticate_Call{Call: _e.mock.On("Authenticate", ctx, secret)} | |
| 86 | - | } | |
| 87 | - | ||
| 88 | - | func (_c *Authenticator_Authenticate_Call) Run(run func(ctx context.Context, secret string)) *Authenticator_Authenticate_Call { | |
| 89 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 90 | - | var arg0 context.Context | |
| 91 | - | if args[0] != nil { | |
| 92 | - | arg0 = args[0].(context.Context) | |
| 93 | - | } | |
| 94 | - | var arg1 string | |
| 95 | - | if args[1] != nil { | |
| 96 | - | arg1 = args[1].(string) | |
| 97 | - | } | |
| 98 | - | run( | |
| 99 | - | arg0, | |
| 100 | - | arg1, | |
| 101 | - | ) | |
| 102 | - | }) | |
| 103 | - | return _c | |
| 104 | - | } | |
| 105 | - | ||
| 106 | - | func (_c *Authenticator_Authenticate_Call) Return(principal domain.Principal, err error) *Authenticator_Authenticate_Call { | |
| 107 | - | _c.Call.Return(principal, err) | |
| 108 | - | return _c | |
| 109 | - | } | |
| 110 | - | ||
| 111 | - | func (_c *Authenticator_Authenticate_Call) RunAndReturn(run func(ctx context.Context, secret string) (domain.Principal, error)) *Authenticator_Authenticate_Call { | |
| 112 | - | _c.Call.Return(run) | |
| 113 | - | return _c | |
| 114 | - | } | |
D internal/adapters/rpc/mocks/Events.go +0 -118
| @@ -1,118 +0,0 @@ | |||
| 1 | - | // Code generated by mockery; DO NOT EDIT. | |
| 2 | - | // github.com/vektra/mockery | |
| 3 | - | // template: testify | |
| 4 | - | ||
| 5 | - | package mocks | |
| 6 | - | ||
| 7 | - | import ( | |
| 8 | - | "context" | |
| 9 | - | ||
| 10 | - | "bnema.dev/ermite/internal/app" | |
| 11 | - | "bnema.dev/ermite/internal/domain" | |
| 12 | - | mock "github.com/stretchr/testify/mock" | |
| 13 | - | ) | |
| 14 | - | ||
| 15 | - | // NewEvents creates a new instance of Events. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | - | // The first argument is typically a *testing.T value. | |
| 17 | - | func NewEvents(t interface { | |
| 18 | - | mock.TestingT | |
| 19 | - | Cleanup(func()) | |
| 20 | - | }) *Events { | |
| 21 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | - | helper.Helper() | |
| 23 | - | } | |
| 24 | - | ||
| 25 | - | mock := &Events{} | |
| 26 | - | mock.Mock.Test(t) | |
| 27 | - | ||
| 28 | - | t.Cleanup(func() { | |
| 29 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 30 | - | helper.Helper() | |
| 31 | - | } | |
| 32 | - | mock.AssertExpectations(t) | |
| 33 | - | }) | |
| 34 | - | ||
| 35 | - | return mock | |
| 36 | - | } | |
| 37 | - | ||
| 38 | - | // Events is an autogenerated mock type for the Events type | |
| 39 | - | type Events struct { | |
| 40 | - | mock.Mock | |
| 41 | - | } | |
| 42 | - | ||
| 43 | - | type Events_Expecter struct { | |
| 44 | - | mock *mock.Mock | |
| 45 | - | } | |
| 46 | - | ||
| 47 | - | func (_m *Events) EXPECT() *Events_Expecter { | |
| 48 | - | return &Events_Expecter{mock: &_m.Mock} | |
| 49 | - | } | |
| 50 | - | ||
| 51 | - | // Watch provides a mock function for the type Events | |
| 52 | - | func (_mock *Events) Watch(ctx context.Context, p domain.Principal, params app.WatchParams, send func(app.WatchEvent) error) error { | |
| 53 | - | ret := _mock.Called(ctx, p, params, send) | |
| 54 | - | ||
| 55 | - | if len(ret) == 0 { | |
| 56 | - | panic("no return value specified for Watch") | |
| 57 | - | } | |
| 58 | - | ||
| 59 | - | var r0 error | |
| 60 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, app.WatchParams, func(app.WatchEvent) error) error); ok { | |
| 61 | - | r0 = returnFunc(ctx, p, params, send) | |
| 62 | - | } else { | |
| 63 | - | r0 = ret.Error(0) | |
| 64 | - | } | |
| 65 | - | return r0 | |
| 66 | - | } | |
| 67 | - | ||
| 68 | - | // Events_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' | |
| 69 | - | type Events_Watch_Call struct { | |
| 70 | - | *mock.Call | |
| 71 | - | } | |
| 72 | - | ||
| 73 | - | // Watch is a helper method to define mock.On call | |
| 74 | - | // - ctx context.Context | |
| 75 | - | // - p domain.Principal | |
| 76 | - | // - params app.WatchParams | |
| 77 | - | // - send func(app.WatchEvent) error | |
| 78 | - | func (_e *Events_Expecter) Watch(ctx any, p any, params any, send any) *Events_Watch_Call { | |
| 79 | - | return &Events_Watch_Call{Call: _e.mock.On("Watch", ctx, p, params, send)} | |
| 80 | - | } | |
| 81 | - | ||
| 82 | - | func (_c *Events_Watch_Call) Run(run func(ctx context.Context, p domain.Principal, params app.WatchParams, send func(app.WatchEvent) error)) *Events_Watch_Call { | |
| 83 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 84 | - | var arg0 context.Context | |
| 85 | - | if args[0] != nil { | |
| 86 | - | arg0 = args[0].(context.Context) | |
| 87 | - | } | |
| 88 | - | var arg1 domain.Principal | |
| 89 | - | if args[1] != nil { | |
| 90 | - | arg1 = args[1].(domain.Principal) | |
| 91 | - | } | |
| 92 | - | var arg2 app.WatchParams | |
| 93 | - | if args[2] != nil { | |
| 94 | - | arg2 = args[2].(app.WatchParams) | |
| 95 | - | } | |
| 96 | - | var arg3 func(app.WatchEvent) error | |
| 97 | - | if args[3] != nil { | |
| 98 | - | arg3 = args[3].(func(app.WatchEvent) error) | |
| 99 | - | } | |
| 100 | - | run( | |
| 101 | - | arg0, | |
| 102 | - | arg1, | |
| 103 | - | arg2, | |
| 104 | - | arg3, | |
| 105 | - | ) | |
| 106 | - | }) | |
| 107 | - | return _c | |
| 108 | - | } | |
| 109 | - | ||
| 110 | - | func (_c *Events_Watch_Call) Return(err error) *Events_Watch_Call { | |
| 111 | - | _c.Call.Return(err) | |
| 112 | - | return _c | |
| 113 | - | } | |
| 114 | - | ||
| 115 | - | func (_c *Events_Watch_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, params app.WatchParams, send func(app.WatchEvent) error) error) *Events_Watch_Call { | |
| 116 | - | _c.Call.Return(run) | |
| 117 | - | return _c | |
| 118 | - | } | |
D internal/adapters/rpc/mocks/FailureLimiter.go +0 -160
| @@ -1,160 +0,0 @@ | |||
| 1 | - | // Code generated by mockery; DO NOT EDIT. | |
| 2 | - | // github.com/vektra/mockery | |
| 3 | - | // template: testify | |
| 4 | - | ||
| 5 | - | package mocks | |
| 6 | - | ||
| 7 | - | import ( | |
| 8 | - | "context" | |
| 9 | - | "time" | |
| 10 | - | ||
| 11 | - | mock "github.com/stretchr/testify/mock" | |
| 12 | - | ) | |
| 13 | - | ||
| 14 | - | // NewFailureLimiter creates a new instance of FailureLimiter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | - | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewFailureLimiter(t interface { | |
| 17 | - | mock.TestingT | |
| 18 | - | Cleanup(func()) | |
| 19 | - | }) *FailureLimiter { | |
| 20 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | - | helper.Helper() | |
| 22 | - | } | |
| 23 | - | ||
| 24 | - | mock := &FailureLimiter{} | |
| 25 | - | mock.Mock.Test(t) | |
| 26 | - | ||
| 27 | - | t.Cleanup(func() { | |
| 28 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 29 | - | helper.Helper() | |
| 30 | - | } | |
| 31 | - | mock.AssertExpectations(t) | |
| 32 | - | }) | |
| 33 | - | ||
| 34 | - | return mock | |
| 35 | - | } | |
| 36 | - | ||
| 37 | - | // FailureLimiter is an autogenerated mock type for the FailureLimiter type | |
| 38 | - | type FailureLimiter struct { | |
| 39 | - | mock.Mock | |
| 40 | - | } | |
| 41 | - | ||
| 42 | - | type FailureLimiter_Expecter struct { | |
| 43 | - | mock *mock.Mock | |
| 44 | - | } | |
| 45 | - | ||
| 46 | - | func (_m *FailureLimiter) EXPECT() *FailureLimiter_Expecter { | |
| 47 | - | return &FailureLimiter_Expecter{mock: &_m.Mock} | |
| 48 | - | } | |
| 49 | - | ||
| 50 | - | // Blocked provides a mock function for the type FailureLimiter | |
| 51 | - | func (_mock *FailureLimiter) Blocked(ctx context.Context, addr string) (bool, time.Duration) { | |
| 52 | - | ret := _mock.Called(ctx, addr) | |
| 53 | - | ||
| 54 | - | if len(ret) == 0 { | |
| 55 | - | panic("no return value specified for Blocked") | |
| 56 | - | } | |
| 57 | - | ||
| 58 | - | var r0 bool | |
| 59 | - | var r1 time.Duration | |
| 60 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, string) (bool, time.Duration)); ok { | |
| 61 | - | return returnFunc(ctx, addr) | |
| 62 | - | } | |
| 63 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, string) bool); ok { | |
| 64 | - | r0 = returnFunc(ctx, addr) | |
| 65 | - | } else { | |
| 66 | - | r0 = ret.Get(0).(bool) | |
| 67 | - | } | |
| 68 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, string) time.Duration); ok { | |
| 69 | - | r1 = returnFunc(ctx, addr) | |
| 70 | - | } else { | |
| 71 | - | r1 = ret.Get(1).(time.Duration) | |
| 72 | - | } | |
| 73 | - | return r0, r1 | |
| 74 | - | } | |
| 75 | - | ||
| 76 | - | // FailureLimiter_Blocked_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Blocked' | |
| 77 | - | type FailureLimiter_Blocked_Call struct { | |
| 78 | - | *mock.Call | |
| 79 | - | } | |
| 80 | - | ||
| 81 | - | // Blocked is a helper method to define mock.On call | |
| 82 | - | // - ctx context.Context | |
| 83 | - | // - addr string | |
| 84 | - | func (_e *FailureLimiter_Expecter) Blocked(ctx any, addr any) *FailureLimiter_Blocked_Call { | |
| 85 | - | return &FailureLimiter_Blocked_Call{Call: _e.mock.On("Blocked", ctx, addr)} | |
| 86 | - | } | |
| 87 | - | ||
| 88 | - | func (_c *FailureLimiter_Blocked_Call) Run(run func(ctx context.Context, addr string)) *FailureLimiter_Blocked_Call { | |
| 89 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 90 | - | var arg0 context.Context | |
| 91 | - | if args[0] != nil { | |
| 92 | - | arg0 = args[0].(context.Context) | |
| 93 | - | } | |
| 94 | - | var arg1 string | |
| 95 | - | if args[1] != nil { | |
| 96 | - | arg1 = args[1].(string) | |
| 97 | - | } | |
| 98 | - | run( | |
| 99 | - | arg0, | |
| 100 | - | arg1, | |
| 101 | - | ) | |
| 102 | - | }) | |
| 103 | - | return _c | |
| 104 | - | } | |
| 105 | - | ||
| 106 | - | func (_c *FailureLimiter_Blocked_Call) Return(b bool, duration time.Duration) *FailureLimiter_Blocked_Call { | |
| 107 | - | _c.Call.Return(b, duration) | |
| 108 | - | return _c | |
| 109 | - | } | |
| 110 | - | ||
| 111 | - | func (_c *FailureLimiter_Blocked_Call) RunAndReturn(run func(ctx context.Context, addr string) (bool, time.Duration)) *FailureLimiter_Blocked_Call { | |
| 112 | - | _c.Call.Return(run) | |
| 113 | - | return _c | |
| 114 | - | } | |
| 115 | - | ||
| 116 | - | // Fail provides a mock function for the type FailureLimiter | |
| 117 | - | func (_mock *FailureLimiter) Fail(ctx context.Context, addr string) { | |
| 118 | - | _mock.Called(ctx, addr) | |
| 119 | - | return | |
| 120 | - | } | |
| 121 | - | ||
| 122 | - | // FailureLimiter_Fail_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Fail' | |
| 123 | - | type FailureLimiter_Fail_Call struct { | |
| 124 | - | *mock.Call | |
| 125 | - | } | |
| 126 | - | ||
| 127 | - | // Fail is a helper method to define mock.On call | |
| 128 | - | // - ctx context.Context | |
| 129 | - | // - addr string | |
| 130 | - | func (_e *FailureLimiter_Expecter) Fail(ctx any, addr any) *FailureLimiter_Fail_Call { | |
| 131 | - | return &FailureLimiter_Fail_Call{Call: _e.mock.On("Fail", ctx, addr)} | |
| 132 | - | } | |
| 133 | - | ||
| 134 | - | func (_c *FailureLimiter_Fail_Call) Run(run func(ctx context.Context, addr string)) *FailureLimiter_Fail_Call { | |
| 135 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 136 | - | var arg0 context.Context | |
| 137 | - | if args[0] != nil { | |
| 138 | - | arg0 = args[0].(context.Context) | |
| 139 | - | } | |
| 140 | - | var arg1 string | |
| 141 | - | if args[1] != nil { | |
| 142 | - | arg1 = args[1].(string) | |
| 143 | - | } | |
| 144 | - | run( | |
| 145 | - | arg0, | |
| 146 | - | arg1, | |
| 147 | - | ) | |
| 148 | - | }) | |
| 149 | - | return _c | |
| 150 | - | } | |
| 151 | - | ||
| 152 | - | func (_c *FailureLimiter_Fail_Call) Return() *FailureLimiter_Fail_Call { | |
| 153 | - | _c.Call.Return() | |
| 154 | - | return _c | |
| 155 | - | } | |
| 156 | - | ||
| 157 | - | func (_c *FailureLimiter_Fail_Call) RunAndReturn(run func(ctx context.Context, addr string)) *FailureLimiter_Fail_Call { | |
| 158 | - | _c.Run(run) | |
| 159 | - | return _c | |
| 160 | - | } | |
D internal/adapters/rpc/mocks/Sessions.go +0 -172
| @@ -1,172 +0,0 @@ | |||
| 1 | - | // Code generated by mockery; DO NOT EDIT. | |
| 2 | - | // github.com/vektra/mockery | |
| 3 | - | // template: testify | |
| 4 | - | ||
| 5 | - | package mocks | |
| 6 | - | ||
| 7 | - | import ( | |
| 8 | - | "context" | |
| 9 | - | ||
| 10 | - | "bnema.dev/ermite/internal/app" | |
| 11 | - | "bnema.dev/ermite/internal/domain" | |
| 12 | - | mock "github.com/stretchr/testify/mock" | |
| 13 | - | ) | |
| 14 | - | ||
| 15 | - | // NewSessions creates a new instance of Sessions. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | - | // The first argument is typically a *testing.T value. | |
| 17 | - | func NewSessions(t interface { | |
| 18 | - | mock.TestingT | |
| 19 | - | Cleanup(func()) | |
| 20 | - | }) *Sessions { | |
| 21 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | - | helper.Helper() | |
| 23 | - | } | |
| 24 | - | ||
| 25 | - | mock := &Sessions{} | |
| 26 | - | mock.Mock.Test(t) | |
| 27 | - | ||
| 28 | - | t.Cleanup(func() { | |
| 29 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 30 | - | helper.Helper() | |
| 31 | - | } | |
| 32 | - | mock.AssertExpectations(t) | |
| 33 | - | }) | |
| 34 | - | ||
| 35 | - | return mock | |
| 36 | - | } | |
| 37 | - | ||
| 38 | - | // Sessions is an autogenerated mock type for the Sessions type | |
| 39 | - | type Sessions struct { | |
| 40 | - | mock.Mock | |
| 41 | - | } | |
| 42 | - | ||
| 43 | - | type Sessions_Expecter struct { | |
| 44 | - | mock *mock.Mock | |
| 45 | - | } | |
| 46 | - | ||
| 47 | - | func (_m *Sessions) EXPECT() *Sessions_Expecter { | |
| 48 | - | return &Sessions_Expecter{mock: &_m.Mock} | |
| 49 | - | } | |
| 50 | - | ||
| 51 | - | // CreateLoginLink provides a mock function for the type Sessions | |
| 52 | - | func (_mock *Sessions) CreateLoginLink(ctx context.Context, p domain.Principal) (app.LoginLink, error) { | |
| 53 | - | ret := _mock.Called(ctx, p) | |
| 54 | - | ||
| 55 | - | if len(ret) == 0 { | |
| 56 | - | panic("no return value specified for CreateLoginLink") | |
| 57 | - | } | |
| 58 | - | ||
| 59 | - | var r0 app.LoginLink | |
| 60 | - | var r1 error | |
| 61 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal) (app.LoginLink, error)); ok { | |
| 62 | - | return returnFunc(ctx, p) | |
| 63 | - | } | |
| 64 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal) app.LoginLink); ok { | |
| 65 | - | r0 = returnFunc(ctx, p) | |
| 66 | - | } else { | |
| 67 | - | r0 = ret.Get(0).(app.LoginLink) | |
| 68 | - | } | |
| 69 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal) error); ok { | |
| 70 | - | r1 = returnFunc(ctx, p) | |
| 71 | - | } else { | |
| 72 | - | r1 = ret.Error(1) | |
| 73 | - | } | |
| 74 | - | return r0, r1 | |
| 75 | - | } | |
| 76 | - | ||
| 77 | - | // Sessions_CreateLoginLink_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateLoginLink' | |
| 78 | - | type Sessions_CreateLoginLink_Call struct { | |
| 79 | - | *mock.Call | |
| 80 | - | } | |
| 81 | - | ||
| 82 | - | // CreateLoginLink is a helper method to define mock.On call | |
| 83 | - | // - ctx context.Context | |
| 84 | - | // - p domain.Principal | |
| 85 | - | func (_e *Sessions_Expecter) CreateLoginLink(ctx any, p any) *Sessions_CreateLoginLink_Call { | |
| 86 | - | return &Sessions_CreateLoginLink_Call{Call: _e.mock.On("CreateLoginLink", ctx, p)} | |
| 87 | - | } | |
| 88 | - | ||
| 89 | - | func (_c *Sessions_CreateLoginLink_Call) Run(run func(ctx context.Context, p domain.Principal)) *Sessions_CreateLoginLink_Call { | |
| 90 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 91 | - | var arg0 context.Context | |
| 92 | - | if args[0] != nil { | |
| 93 | - | arg0 = args[0].(context.Context) | |
| 94 | - | } | |
| 95 | - | var arg1 domain.Principal | |
| 96 | - | if args[1] != nil { | |
| 97 | - | arg1 = args[1].(domain.Principal) | |
| 98 | - | } | |
| 99 | - | run( | |
| 100 | - | arg0, | |
| 101 | - | arg1, | |
| 102 | - | ) | |
| 103 | - | }) | |
| 104 | - | return _c | |
| 105 | - | } | |
| 106 | - | ||
| 107 | - | func (_c *Sessions_CreateLoginLink_Call) Return(loginLink app.LoginLink, err error) *Sessions_CreateLoginLink_Call { | |
| 108 | - | _c.Call.Return(loginLink, err) | |
| 109 | - | return _c | |
| 110 | - | } | |
| 111 | - | ||
| 112 | - | func (_c *Sessions_CreateLoginLink_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal) (app.LoginLink, error)) *Sessions_CreateLoginLink_Call { | |
| 113 | - | _c.Call.Return(run) | |
| 114 | - | return _c | |
| 115 | - | } | |
| 116 | - | ||
| 117 | - | // SignOutEverywhere provides a mock function for the type Sessions | |
| 118 | - | func (_mock *Sessions) SignOutEverywhere(ctx context.Context, p domain.Principal) error { | |
| 119 | - | ret := _mock.Called(ctx, p) | |
| 120 | - | ||
| 121 | - | if len(ret) == 0 { | |
| 122 | - | panic("no return value specified for SignOutEverywhere") | |
| 123 | - | } | |
| 124 | - | ||
| 125 | - | var r0 error | |
| 126 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal) error); ok { | |
| 127 | - | r0 = returnFunc(ctx, p) | |
| 128 | - | } else { | |
| 129 | - | r0 = ret.Error(0) | |
| 130 | - | } | |
| 131 | - | return r0 | |
| 132 | - | } | |
| 133 | - | ||
| 134 | - | // Sessions_SignOutEverywhere_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SignOutEverywhere' | |
| 135 | - | type Sessions_SignOutEverywhere_Call struct { | |
| 136 | - | *mock.Call | |
| 137 | - | } | |
| 138 | - | ||
| 139 | - | // SignOutEverywhere is a helper method to define mock.On call | |
| 140 | - | // - ctx context.Context | |
| 141 | - | // - p domain.Principal | |
| 142 | - | func (_e *Sessions_Expecter) SignOutEverywhere(ctx any, p any) *Sessions_SignOutEverywhere_Call { | |
| 143 | - | return &Sessions_SignOutEverywhere_Call{Call: _e.mock.On("SignOutEverywhere", ctx, p)} | |
| 144 | - | } | |
| 145 | - | ||
| 146 | - | func (_c *Sessions_SignOutEverywhere_Call) Run(run func(ctx context.Context, p domain.Principal)) *Sessions_SignOutEverywhere_Call { | |
| 147 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 148 | - | var arg0 context.Context | |
| 149 | - | if args[0] != nil { | |
| 150 | - | arg0 = args[0].(context.Context) | |
| 151 | - | } | |
| 152 | - | var arg1 domain.Principal | |
| 153 | - | if args[1] != nil { | |
| 154 | - | arg1 = args[1].(domain.Principal) | |
| 155 | - | } | |
| 156 | - | run( | |
| 157 | - | arg0, | |
| 158 | - | arg1, | |
| 159 | - | ) | |
| 160 | - | }) | |
| 161 | - | return _c | |
| 162 | - | } | |
| 163 | - | ||
| 164 | - | func (_c *Sessions_SignOutEverywhere_Call) Return(err error) *Sessions_SignOutEverywhere_Call { | |
| 165 | - | _c.Call.Return(err) | |
| 166 | - | return _c | |
| 167 | - | } | |
| 168 | - | ||
| 169 | - | func (_c *Sessions_SignOutEverywhere_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal) error) *Sessions_SignOutEverywhere_Call { | |
| 170 | - | _c.Call.Return(run) | |
| 171 | - | return _c | |
| 172 | - | } | |
D internal/adapters/rpc/mocks/SigningKey.go +0 -90
| @@ -1,90 +0,0 @@ | |||
| 1 | - | // Code generated by mockery; DO NOT EDIT. | |
| 2 | - | // github.com/vektra/mockery | |
| 3 | - | // template: testify | |
| 4 | - | ||
| 5 | - | package mocks | |
| 6 | - | ||
| 7 | - | import ( | |
| 8 | - | "bnema.dev/ermite/internal/domain" | |
| 9 | - | mock "github.com/stretchr/testify/mock" | |
| 10 | - | ) | |
| 11 | - | ||
| 12 | - | // NewSigningKey creates a new instance of SigningKey. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 13 | - | // The first argument is typically a *testing.T value. | |
| 14 | - | func NewSigningKey(t interface { | |
| 15 | - | mock.TestingT | |
| 16 | - | Cleanup(func()) | |
| 17 | - | }) *SigningKey { | |
| 18 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 19 | - | helper.Helper() | |
| 20 | - | } | |
| 21 | - | ||
| 22 | - | mock := &SigningKey{} | |
| 23 | - | mock.Mock.Test(t) | |
| 24 | - | ||
| 25 | - | t.Cleanup(func() { | |
| 26 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 27 | - | helper.Helper() | |
| 28 | - | } | |
| 29 | - | mock.AssertExpectations(t) | |
| 30 | - | }) | |
| 31 | - | ||
| 32 | - | return mock | |
| 33 | - | } | |
| 34 | - | ||
| 35 | - | // SigningKey is an autogenerated mock type for the SigningKey type | |
| 36 | - | type SigningKey struct { | |
| 37 | - | mock.Mock | |
| 38 | - | } | |
| 39 | - | ||
| 40 | - | type SigningKey_Expecter struct { | |
| 41 | - | mock *mock.Mock | |
| 42 | - | } | |
| 43 | - | ||
| 44 | - | func (_m *SigningKey) EXPECT() *SigningKey_Expecter { | |
| 45 | - | return &SigningKey_Expecter{mock: &_m.Mock} | |
| 46 | - | } | |
| 47 | - | ||
| 48 | - | // Info provides a mock function for the type SigningKey | |
| 49 | - | func (_mock *SigningKey) Info() domain.SigningKeyInfo { | |
| 50 | - | ret := _mock.Called() | |
| 51 | - | ||
| 52 | - | if len(ret) == 0 { | |
| 53 | - | panic("no return value specified for Info") | |
| 54 | - | } | |
| 55 | - | ||
| 56 | - | var r0 domain.SigningKeyInfo | |
| 57 | - | if returnFunc, ok := ret.Get(0).(func() domain.SigningKeyInfo); ok { | |
| 58 | - | r0 = returnFunc() | |
| 59 | - | } else { | |
| 60 | - | r0 = ret.Get(0).(domain.SigningKeyInfo) | |
| 61 | - | } | |
| 62 | - | return r0 | |
| 63 | - | } | |
| 64 | - | ||
| 65 | - | // SigningKey_Info_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Info' | |
| 66 | - | type SigningKey_Info_Call struct { | |
| 67 | - | *mock.Call | |
| 68 | - | } | |
| 69 | - | ||
| 70 | - | // Info is a helper method to define mock.On call | |
| 71 | - | func (_e *SigningKey_Expecter) Info() *SigningKey_Info_Call { | |
| 72 | - | return &SigningKey_Info_Call{Call: _e.mock.On("Info")} | |
| 73 | - | } | |
| 74 | - | ||
| 75 | - | func (_c *SigningKey_Info_Call) Run(run func()) *SigningKey_Info_Call { | |
| 76 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 77 | - | run() | |
| 78 | - | }) | |
| 79 | - | return _c | |
| 80 | - | } | |
| 81 | - | ||
| 82 | - | func (_c *SigningKey_Info_Call) Return(signingKeyInfo domain.SigningKeyInfo) *SigningKey_Info_Call { | |
| 83 | - | _c.Call.Return(signingKeyInfo) | |
| 84 | - | return _c | |
| 85 | - | } | |
| 86 | - | ||
| 87 | - | func (_c *SigningKey_Info_Call) RunAndReturn(run func() domain.SigningKeyInfo) *SigningKey_Info_Call { | |
| 88 | - | _c.Call.Return(run) | |
| 89 | - | return _c | |
| 90 | - | } | |
D internal/adapters/rpc/mocks/Tokens.go +0 -262
| @@ -1,262 +0,0 @@ | |||
| 1 | - | // Code generated by mockery; DO NOT EDIT. | |
| 2 | - | // github.com/vektra/mockery | |
| 3 | - | // template: testify | |
| 4 | - | ||
| 5 | - | package mocks | |
| 6 | - | ||
| 7 | - | import ( | |
| 8 | - | "context" | |
| 9 | - | ||
| 10 | - | "bnema.dev/ermite/internal/app" | |
| 11 | - | "bnema.dev/ermite/internal/domain" | |
| 12 | - | mock "github.com/stretchr/testify/mock" | |
| 13 | - | ) | |
| 14 | - | ||
| 15 | - | // NewTokens creates a new instance of Tokens. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | - | // The first argument is typically a *testing.T value. | |
| 17 | - | func NewTokens(t interface { | |
| 18 | - | mock.TestingT | |
| 19 | - | Cleanup(func()) | |
| 20 | - | }) *Tokens { | |
| 21 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | - | helper.Helper() | |
| 23 | - | } | |
| 24 | - | ||
| 25 | - | mock := &Tokens{} | |
| 26 | - | mock.Mock.Test(t) | |
| 27 | - | ||
| 28 | - | t.Cleanup(func() { | |
| 29 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 30 | - | helper.Helper() | |
| 31 | - | } | |
| 32 | - | mock.AssertExpectations(t) | |
| 33 | - | }) | |
| 34 | - | ||
| 35 | - | return mock | |
| 36 | - | } | |
| 37 | - | ||
| 38 | - | // Tokens is an autogenerated mock type for the Tokens type | |
| 39 | - | type Tokens struct { | |
| 40 | - | mock.Mock | |
| 41 | - | } | |
| 42 | - | ||
| 43 | - | type Tokens_Expecter struct { | |
| 44 | - | mock *mock.Mock | |
| 45 | - | } | |
| 46 | - | ||
| 47 | - | func (_m *Tokens) EXPECT() *Tokens_Expecter { | |
| 48 | - | return &Tokens_Expecter{mock: &_m.Mock} | |
| 49 | - | } | |
| 50 | - | ||
| 51 | - | // Create provides a mock function for the type Tokens | |
| 52 | - | func (_mock *Tokens) Create(ctx context.Context, p domain.Principal, params app.CreateTokenParams) (app.CreatedToken, error) { | |
| 53 | - | ret := _mock.Called(ctx, p, params) | |
| 54 | - | ||
| 55 | - | if len(ret) == 0 { | |
| 56 | - | panic("no return value specified for Create") | |
| 57 | - | } | |
| 58 | - | ||
| 59 | - | var r0 app.CreatedToken | |
| 60 | - | var r1 error | |
| 61 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, app.CreateTokenParams) (app.CreatedToken, error)); ok { | |
| 62 | - | return returnFunc(ctx, p, params) | |
| 63 | - | } | |
| 64 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, app.CreateTokenParams) app.CreatedToken); ok { | |
| 65 | - | r0 = returnFunc(ctx, p, params) | |
| 66 | - | } else { | |
| 67 | - | r0 = ret.Get(0).(app.CreatedToken) | |
| 68 | - | } | |
| 69 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, app.CreateTokenParams) error); ok { | |
| 70 | - | r1 = returnFunc(ctx, p, params) | |
| 71 | - | } else { | |
| 72 | - | r1 = ret.Error(1) | |
| 73 | - | } | |
| 74 | - | return r0, r1 | |
| 75 | - | } | |
| 76 | - | ||
| 77 | - | // Tokens_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' | |
| 78 | - | type Tokens_Create_Call struct { | |
| 79 | - | *mock.Call | |
| 80 | - | } | |
| 81 | - | ||
| 82 | - | // Create is a helper method to define mock.On call | |
| 83 | - | // - ctx context.Context | |
| 84 | - | // - p domain.Principal | |
| 85 | - | // - params app.CreateTokenParams | |
| 86 | - | func (_e *Tokens_Expecter) Create(ctx any, p any, params any) *Tokens_Create_Call { | |
| 87 | - | return &Tokens_Create_Call{Call: _e.mock.On("Create", ctx, p, params)} | |
| 88 | - | } | |
| 89 | - | ||
| 90 | - | func (_c *Tokens_Create_Call) Run(run func(ctx context.Context, p domain.Principal, params app.CreateTokenParams)) *Tokens_Create_Call { | |
| 91 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 92 | - | var arg0 context.Context | |
| 93 | - | if args[0] != nil { | |
| 94 | - | arg0 = args[0].(context.Context) | |
| 95 | - | } | |
| 96 | - | var arg1 domain.Principal | |
| 97 | - | if args[1] != nil { | |
| 98 | - | arg1 = args[1].(domain.Principal) | |
| 99 | - | } | |
| 100 | - | var arg2 app.CreateTokenParams | |
| 101 | - | if args[2] != nil { | |
| 102 | - | arg2 = args[2].(app.CreateTokenParams) | |
| 103 | - | } | |
| 104 | - | run( | |
| 105 | - | arg0, | |
| 106 | - | arg1, | |
| 107 | - | arg2, | |
| 108 | - | ) | |
| 109 | - | }) | |
| 110 | - | return _c | |
| 111 | - | } | |
| 112 | - | ||
| 113 | - | func (_c *Tokens_Create_Call) Return(createdToken app.CreatedToken, err error) *Tokens_Create_Call { | |
| 114 | - | _c.Call.Return(createdToken, err) | |
| 115 | - | return _c | |
| 116 | - | } | |
| 117 | - | ||
| 118 | - | func (_c *Tokens_Create_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, params app.CreateTokenParams) (app.CreatedToken, error)) *Tokens_Create_Call { | |
| 119 | - | _c.Call.Return(run) | |
| 120 | - | return _c | |
| 121 | - | } | |
| 122 | - | ||
| 123 | - | // ListPage provides a mock function for the type Tokens | |
| 124 | - | func (_mock *Tokens) ListPage(ctx context.Context, p domain.Principal, size int, token string) (app.TokenPage, error) { | |
| 125 | - | ret := _mock.Called(ctx, p, size, token) | |
| 126 | - | ||
| 127 | - | if len(ret) == 0 { | |
| 128 | - | panic("no return value specified for ListPage") | |
| 129 | - | } | |
| 130 | - | ||
| 131 | - | var r0 app.TokenPage | |
| 132 | - | var r1 error | |
| 133 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) (app.TokenPage, error)); ok { | |
| 134 | - | return returnFunc(ctx, p, size, token) | |
| 135 | - | } | |
| 136 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) app.TokenPage); ok { | |
| 137 | - | r0 = returnFunc(ctx, p, size, token) | |
| 138 | - | } else { | |
| 139 | - | r0 = ret.Get(0).(app.TokenPage) | |
| 140 | - | } | |
| 141 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, int, string) error); ok { | |
| 142 | - | r1 = returnFunc(ctx, p, size, token) | |
| 143 | - | } else { | |
| 144 | - | r1 = ret.Error(1) | |
| 145 | - | } | |
| 146 | - | return r0, r1 | |
| 147 | - | } | |
| 148 | - | ||
| 149 | - | // Tokens_ListPage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListPage' | |
| 150 | - | type Tokens_ListPage_Call struct { | |
| 151 | - | *mock.Call | |
| 152 | - | } | |
| 153 | - | ||
| 154 | - | // ListPage is a helper method to define mock.On call | |
| 155 | - | // - ctx context.Context | |
| 156 | - | // - p domain.Principal | |
| 157 | - | // - size int | |
| 158 | - | // - token string | |
| 159 | - | func (_e *Tokens_Expecter) ListPage(ctx any, p any, size any, token any) *Tokens_ListPage_Call { | |
| 160 | - | return &Tokens_ListPage_Call{Call: _e.mock.On("ListPage", ctx, p, size, token)} | |
| 161 | - | } | |
| 162 | - | ||
| 163 | - | func (_c *Tokens_ListPage_Call) Run(run func(ctx context.Context, p domain.Principal, size int, token string)) *Tokens_ListPage_Call { | |
| 164 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 165 | - | var arg0 context.Context | |
| 166 | - | if args[0] != nil { | |
| 167 | - | arg0 = args[0].(context.Context) | |
| 168 | - | } | |
| 169 | - | var arg1 domain.Principal | |
| 170 | - | if args[1] != nil { | |
| 171 | - | arg1 = args[1].(domain.Principal) | |
| 172 | - | } | |
| 173 | - | var arg2 int | |
| 174 | - | if args[2] != nil { | |
| 175 | - | arg2 = args[2].(int) | |
| 176 | - | } | |
| 177 | - | var arg3 string | |
| 178 | - | if args[3] != nil { | |
| 179 | - | arg3 = args[3].(string) | |
| 180 | - | } | |
| 181 | - | run( | |
| 182 | - | arg0, | |
| 183 | - | arg1, | |
| 184 | - | arg2, | |
| 185 | - | arg3, | |
| 186 | - | ) | |
| 187 | - | }) | |
| 188 | - | return _c | |
| 189 | - | } | |
| 190 | - | ||
| 191 | - | func (_c *Tokens_ListPage_Call) Return(tokenPage app.TokenPage, err error) *Tokens_ListPage_Call { | |
| 192 | - | _c.Call.Return(tokenPage, err) | |
| 193 | - | return _c | |
| 194 | - | } | |
| 195 | - | ||
| 196 | - | func (_c *Tokens_ListPage_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, size int, token string) (app.TokenPage, error)) *Tokens_ListPage_Call { | |
| 197 | - | _c.Call.Return(run) | |
| 198 | - | return _c | |
| 199 | - | } | |
| 200 | - | ||
| 201 | - | // Revoke provides a mock function for the type Tokens | |
| 202 | - | func (_mock *Tokens) Revoke(ctx context.Context, p domain.Principal, id string) error { | |
| 203 | - | ret := _mock.Called(ctx, p, id) | |
| 204 | - | ||
| 205 | - | if len(ret) == 0 { | |
| 206 | - | panic("no return value specified for Revoke") | |
| 207 | - | } | |
| 208 | - | ||
| 209 | - | var r0 error | |
| 210 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, string) error); ok { | |
| 211 | - | r0 = returnFunc(ctx, p, id) | |
| 212 | - | } else { | |
| 213 | - | r0 = ret.Error(0) | |
| 214 | - | } | |
| 215 | - | return r0 | |
| 216 | - | } | |
| 217 | - | ||
| 218 | - | // Tokens_Revoke_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Revoke' | |
| 219 | - | type Tokens_Revoke_Call struct { | |
| 220 | - | *mock.Call | |
| 221 | - | } | |
| 222 | - | ||
| 223 | - | // Revoke is a helper method to define mock.On call | |
| 224 | - | // - ctx context.Context | |
| 225 | - | // - p domain.Principal | |
| 226 | - | // - id string | |
| 227 | - | func (_e *Tokens_Expecter) Revoke(ctx any, p any, id any) *Tokens_Revoke_Call { | |
| 228 | - | return &Tokens_Revoke_Call{Call: _e.mock.On("Revoke", ctx, p, id)} | |
| 229 | - | } | |
| 230 | - | ||
| 231 | - | func (_c *Tokens_Revoke_Call) Run(run func(ctx context.Context, p domain.Principal, id string)) *Tokens_Revoke_Call { | |
| 232 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 233 | - | var arg0 context.Context | |
| 234 | - | if args[0] != nil { | |
| 235 | - | arg0 = args[0].(context.Context) | |
| 236 | - | } | |
| 237 | - | var arg1 domain.Principal | |
| 238 | - | if args[1] != nil { | |
| 239 | - | arg1 = args[1].(domain.Principal) | |
| 240 | - | } | |
| 241 | - | var arg2 string | |
| 242 | - | if args[2] != nil { | |
| 243 | - | arg2 = args[2].(string) | |
| 244 | - | } | |
| 245 | - | run( | |
| 246 | - | arg0, | |
| 247 | - | arg1, | |
| 248 | - | arg2, | |
| 249 | - | ) | |
| 250 | - | }) | |
| 251 | - | return _c | |
| 252 | - | } | |
| 253 | - | ||
| 254 | - | func (_c *Tokens_Revoke_Call) Return(err error) *Tokens_Revoke_Call { | |
| 255 | - | _c.Call.Return(err) | |
| 256 | - | return _c | |
| 257 | - | } | |
| 258 | - | ||
| 259 | - | func (_c *Tokens_Revoke_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, id string) error) *Tokens_Revoke_Call { | |
| 260 | - | _c.Call.Return(run) | |
| 261 | - | return _c | |
| 262 | - | } | |
M internal/adapters/rpc/repo.go +6 -6
| @@ -9,12 +9,12 @@ import ( | |||
| 9 | 9 | "connectrpc.com/connect" | |
| 10 | 10 | ||
| 11 | 11 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 12 | - | "bnema.dev/ermite/internal/app" | |
| 13 | 12 | "bnema.dev/ermite/internal/domain" | |
| 13 | + | "bnema.dev/ermite/internal/ports" | |
| 14 | 14 | ) | |
| 15 | 15 | ||
| 16 | 16 | // repoService implements ermiteconnect.RepoServiceHandler. | |
| 17 | - | type repoService struct{ repos Repos } | |
| 17 | + | type repoService struct{ repos ports.RepoService } | |
| 18 | 18 | ||
| 19 | 19 | func (s *repoService) ListRepos(ctx context.Context, req *connect.Request[pb.ListReposRequest]) (*connect.Response[pb.ListReposResponse], error) { | |
| 20 | 20 | page, err := s.repos.ListPage(ctx, caller(ctx), int(req.Msg.GetPageSize()), req.Msg.GetPageToken()) | |
| @@ -53,7 +53,7 @@ func (s *repoService) CreateRepo(ctx context.Context, req *connect.Request[pb.Cr | |||
| 53 | 53 | if err != nil { | |
| 54 | 54 | return nil, connectError(ctx, err) | |
| 55 | 55 | } | |
| 56 | - | repo, err := s.repos.Create(ctx, caller(ctx), app.CreateParams{ | |
| 56 | + | repo, err := s.repos.Create(ctx, caller(ctx), ports.CreateRepoParams{ | |
| 57 | 57 | Name: name, Description: req.Msg.GetDescription(), Visibility: vis, | |
| 58 | 58 | }) | |
| 59 | 59 | if err != nil { | |
| @@ -84,8 +84,8 @@ func (s *repoService) UpdateRepo(ctx context.Context, req *connect.Request[pb.Up | |||
| 84 | 84 | // nothing else. | |
| 85 | 85 | // | |
| 86 | 86 | //hexcheck:ignore suspicious-business-logic-in-adapter maps the field mask of the contract to the optional fields of the use case; no rule is decided here | |
| 87 | - | func updateParams(msg *pb.UpdateRepoRequest) (app.UpdateParams, error) { | |
| 88 | - | var params app.UpdateParams | |
| 87 | + | func updateParams(msg *pb.UpdateRepoRequest) (ports.UpdateRepoParams, error) { | |
| 88 | + | var params ports.UpdateRepoParams | |
| 89 | 89 | paths := msg.GetUpdateMask().GetPaths() | |
| 90 | 90 | if len(paths) == 0 { | |
| 91 | 91 | return params, fmt.Errorf("%w: update_mask is empty", domain.ErrInvalid) | |
| @@ -135,7 +135,7 @@ func (s *repoService) DeleteRepo(ctx context.Context, req *connect.Request[pb.De | |||
| 135 | 135 | } | |
| 136 | 136 | ||
| 137 | 137 | // respondRepo adds the default branch to repo and wraps it in a response. | |
| 138 | - | func respondRepo[T any](ctx context.Context, repos Repos, repo domain.Repo, wrap func(*pb.Repo) *T) (*connect.Response[T], error) { | |
| 138 | + | func respondRepo[T any](ctx context.Context, repos ports.RepoService, repo domain.Repo, wrap func(*pb.Repo) *T) (*connect.Response[T], error) { | |
| 139 | 139 | view, err := repos.View(ctx, repo) | |
| 140 | 140 | if err != nil { | |
| 141 | 141 | return nil, connectError(ctx, err) | |
M internal/adapters/rpc/repo_test.go +16 -16
| @@ -14,9 +14,9 @@ import ( | |||
| 14 | 14 | "google.golang.org/protobuf/types/known/fieldmaskpb" | |
| 15 | 15 | ||
| 16 | 16 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 17 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |
| 18 | - | "bnema.dev/ermite/internal/app" | |
| 19 | 17 | "bnema.dev/ermite/internal/domain" | |
| 18 | + | "bnema.dev/ermite/internal/ports" | |
| 19 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 20 | 20 | ) | |
| 21 | 21 | ||
| 22 | 22 | // ownerCtx is the context of a call made by the owner, as the interceptor | |
| @@ -60,12 +60,12 @@ func TestRepoServiceGetRepo(t *testing.T) { | |||
| 60 | 60 | for _, tt := range tests { | |
| 61 | 61 | t.Run(tt.name, func(t *testing.T) { | |
| 62 | 62 | t.Parallel() | |
| 63 | - | repos := mocks.NewRepos(t) | |
| 63 | + | repos := mocks.NewRepoService(t) | |
| 64 | 64 | if tt.wantCall { | |
| 65 | 65 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Description: "d", Visibility: domain.VisibilityPublic} | |
| 66 | 66 | repos.EXPECT().Get(mock.Anything, domain.Owner(), repo.Name).Return(repo, tt.usecase).Once() | |
| 67 | 67 | if tt.usecase == nil { | |
| 68 | - | repos.EXPECT().View(mock.Anything, repo).Return(app.RepoView{Repo: repo, DefaultBranch: "main"}, tt.viewErr).Once() | |
| 68 | + | repos.EXPECT().View(mock.Anything, repo).Return(ports.RepoView{Repo: repo, DefaultBranch: "main"}, tt.viewErr).Once() | |
| 69 | 69 | } | |
| 70 | 70 | } | |
| 71 | 71 | svc := &repoService{repos} | |
| @@ -102,14 +102,14 @@ func TestRepoServiceCreateRepo(t *testing.T) { | |||
| 102 | 102 | for _, tt := range tests { | |
| 103 | 103 | t.Run(tt.name, func(t *testing.T) { | |
| 104 | 104 | t.Parallel() | |
| 105 | - | repos := mocks.NewRepos(t) | |
| 105 | + | repos := mocks.NewRepoService(t) | |
| 106 | 106 | if tt.wantCall { | |
| 107 | 107 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Visibility: domain.VisibilityPrivate} | |
| 108 | - | repos.EXPECT().Create(mock.Anything, domain.Owner(), mock.MatchedBy(func(p app.CreateParams) bool { | |
| 108 | + | repos.EXPECT().Create(mock.Anything, domain.Owner(), mock.MatchedBy(func(p ports.CreateRepoParams) bool { | |
| 109 | 109 | return p.Name.String() == "demo" | |
| 110 | 110 | })).Return(repo, tt.usecase).Once() | |
| 111 | 111 | if tt.usecase == nil { | |
| 112 | - | repos.EXPECT().View(mock.Anything, repo).Return(app.RepoView{Repo: repo}, nil).Once() | |
| 112 | + | repos.EXPECT().View(mock.Anything, repo).Return(ports.RepoView{Repo: repo}, nil).Once() | |
| 113 | 113 | } | |
| 114 | 114 | } | |
| 115 | 115 | resp, err := (&repoService{repos}).CreateRepo(ownerCtx(), connect.NewRequest(tt.req)) | |
| @@ -170,12 +170,12 @@ func TestRepoServiceUpdateRepoValidatesMask(t *testing.T) { | |||
| 170 | 170 | for _, tt := range tests { | |
| 171 | 171 | t.Run(tt.name, func(t *testing.T) { | |
| 172 | 172 | t.Parallel() | |
| 173 | - | repos := mocks.NewRepos(t) | |
| 173 | + | repos := mocks.NewRepoService(t) | |
| 174 | 174 | if tt.wantCall { | |
| 175 | 175 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Description: "new"} | |
| 176 | 176 | repos.EXPECT().Update(mock.Anything, domain.Owner(), repo.Name, mock.Anything).Return(repo, tt.usecase).Once() | |
| 177 | 177 | if tt.usecase == nil { | |
| 178 | - | repos.EXPECT().View(mock.Anything, repo).Return(app.RepoView{Repo: repo}, nil).Once() | |
| 178 | + | repos.EXPECT().View(mock.Anything, repo).Return(ports.RepoView{Repo: repo}, nil).Once() | |
| 179 | 179 | } | |
| 180 | 180 | } | |
| 181 | 181 | resp, err := (&repoService{repos}).UpdateRepo(ownerCtx(), connect.NewRequest(tt.req)) | |
| @@ -206,7 +206,7 @@ func TestRepoServiceDeleteRepo(t *testing.T) { | |||
| 206 | 206 | for _, tt := range tests { | |
| 207 | 207 | t.Run(tt.name, func(t *testing.T) { | |
| 208 | 208 | t.Parallel() | |
| 209 | - | repos := mocks.NewRepos(t) | |
| 209 | + | repos := mocks.NewRepoService(t) | |
| 210 | 210 | if tt.wantCall { | |
| 211 | 211 | repos.EXPECT().Delete(mock.Anything, domain.Owner(), mustRepoName(t, tt.repo)).Return(tt.usecase).Once() | |
| 212 | 212 | } | |
| @@ -224,12 +224,12 @@ func TestRepoServiceListRepos(t *testing.T) { | |||
| 224 | 224 | t.Parallel() | |
| 225 | 225 | t.Run("pages and views every repo", func(t *testing.T) { | |
| 226 | 226 | t.Parallel() | |
| 227 | - | repos := mocks.NewRepos(t) | |
| 227 | + | repos := mocks.NewRepoService(t) | |
| 228 | 228 | a := domain.Repo{Name: mustRepoName(t, "a")} | |
| 229 | 229 | b := domain.Repo{Name: mustRepoName(t, "b")} | |
| 230 | - | repos.EXPECT().ListPage(mock.Anything, domain.Owner(), 2, "tok").Return(app.RepoPage{Repos: []domain.Repo{a, b}, NextPageToken: "next"}, nil).Once() | |
| 231 | - | repos.EXPECT().View(mock.Anything, a).Return(app.RepoView{Repo: a}, nil).Once() | |
| 232 | - | repos.EXPECT().View(mock.Anything, b).Return(app.RepoView{Repo: b}, nil).Once() | |
| 230 | + | repos.EXPECT().ListPage(mock.Anything, domain.Owner(), 2, "tok").Return(ports.RepoPage{Repos: []domain.Repo{a, b}, NextPageToken: "next"}, nil).Once() | |
| 231 | + | repos.EXPECT().View(mock.Anything, a).Return(ports.RepoView{Repo: a}, nil).Once() | |
| 232 | + | repos.EXPECT().View(mock.Anything, b).Return(ports.RepoView{Repo: b}, nil).Once() | |
| 233 | 233 | resp, err := (&repoService{repos}).ListRepos(ownerCtx(), connect.NewRequest(&pb.ListReposRequest{PageSize: 2, PageToken: "tok"})) | |
| 234 | 234 | require.NoError(t, err) | |
| 235 | 235 | require.Len(t, resp.Msg.GetRepos(), 2) | |
| @@ -245,8 +245,8 @@ func TestRepoServiceListRepos(t *testing.T) { | |||
| 245 | 245 | } { | |
| 246 | 246 | t.Run(name, func(t *testing.T) { | |
| 247 | 247 | t.Parallel() | |
| 248 | - | repos := mocks.NewRepos(t) | |
| 249 | - | repos.EXPECT().ListPage(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(app.RepoPage{}, tc.err).Once() | |
| 248 | + | repos := mocks.NewRepoService(t) | |
| 249 | + | repos.EXPECT().ListPage(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ports.RepoPage{}, tc.err).Once() | |
| 250 | 250 | _, err := (&repoService{repos}).ListRepos(ownerCtx(), connect.NewRequest(&pb.ListReposRequest{})) | |
| 251 | 251 | requireCode(t, tc.code, err) | |
| 252 | 252 | }) | |
M internal/adapters/rpc/server.go +2 -1
| @@ -9,12 +9,13 @@ import ( | |||
| 9 | 9 | "connectrpc.com/connect" | |
| 10 | 10 | ||
| 11 | 11 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 12 | + | "bnema.dev/ermite/internal/ports" | |
| 12 | 13 | ) | |
| 13 | 14 | ||
| 14 | 15 | // serverService implements ermiteconnect.ServerServiceHandler. | |
| 15 | 16 | type serverService struct { | |
| 16 | 17 | version string | |
| 17 | - | key SigningKey | |
| 18 | + | key ports.SigningKeyService | |
| 18 | 19 | } | |
| 19 | 20 | ||
| 20 | 21 | func (s *serverService) GetVersion(context.Context, *connect.Request[pb.GetVersionRequest]) (*connect.Response[pb.GetVersionResponse], error) { | |
M internal/adapters/rpc/server_test.go +3 -3
| @@ -11,13 +11,13 @@ import ( | |||
| 11 | 11 | "github.com/stretchr/testify/require" | |
| 12 | 12 | ||
| 13 | 13 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |
| 15 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 16 | 16 | ) | |
| 17 | 17 | ||
| 18 | 18 | func TestServerServiceGetVersion(t *testing.T) { | |
| 19 | 19 | t.Parallel() | |
| 20 | - | svc := &serverService{version: "v1.2.3", key: mocks.NewSigningKey(t)} | |
| 20 | + | svc := &serverService{version: "v1.2.3", key: mocks.NewSigningKeyService(t)} | |
| 21 | 21 | resp, err := svc.GetVersion(context.Background(), connect.NewRequest(&pb.GetVersionRequest{})) | |
| 22 | 22 | require.NoError(t, err) | |
| 23 | 23 | assert.Equal(t, "v1.2.3", resp.Msg.GetVersion()) | |
| @@ -30,7 +30,7 @@ func TestServerServiceGetVersion(t *testing.T) { | |||
| 30 | 30 | ||
| 31 | 31 | func TestServerServiceGetSigningKey(t *testing.T) { | |
| 32 | 32 | t.Parallel() | |
| 33 | - | key := mocks.NewSigningKey(t) | |
| 33 | + | key := mocks.NewSigningKeyService(t) | |
| 34 | 34 | key.EXPECT().Info().Return(domain.SigningKeyInfo{ | |
| 35 | 35 | Key: domain.SigningPublicKey{AuthorizedKey: "ssh-ed25519 AAAA", Fingerprint: "SHA256:xyz"}, | |
| 36 | 36 | Committer: domain.Identity{Name: "ermite", Email: "ermite@example.com"}, | |
D internal/adapters/rpc/services.go +0 -81
| @@ -1,81 +0,0 @@ | |||
| 1 | - | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | - | ||
| 3 | - | package rpc | |
| 4 | - | ||
| 5 | - | import ( | |
| 6 | - | "context" | |
| 7 | - | "io" | |
| 8 | - | "time" | |
| 9 | - | ||
| 10 | - | "bnema.dev/ermite/internal/app" | |
| 11 | - | "bnema.dev/ermite/internal/domain" | |
| 12 | - | ) | |
| 13 | - | ||
| 14 | - | // The interfaces below are what the handlers need of the use cases, declared | |
| 15 | - | // where they are used. The types of app fit them; the mocks in rpc/mocks | |
| 16 | - | // stand in for them in tests. | |
| 17 | - | ||
| 18 | - | // Repos is the repository use cases the API serves. *app.Repos fits. | |
| 19 | - | type Repos interface { | |
| 20 | - | ListPage(ctx context.Context, p domain.Principal, size int, token string) (app.RepoPage, error) | |
| 21 | - | View(ctx context.Context, repo domain.Repo) (app.RepoView, error) | |
| 22 | - | Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) | |
| 23 | - | Create(ctx context.Context, p domain.Principal, params app.CreateParams) (domain.Repo, error) | |
| 24 | - | Update(ctx context.Context, p domain.Principal, name domain.RepoName, params app.UpdateParams) (domain.Repo, error) | |
| 25 | - | Delete(ctx context.Context, p domain.Principal, name domain.RepoName) error | |
| 26 | - | } | |
| 27 | - | ||
| 28 | - | // Tokens is the access token use cases the API serves. *app.Tokens fits. | |
| 29 | - | type Tokens interface { | |
| 30 | - | Create(ctx context.Context, p domain.Principal, params app.CreateTokenParams) (app.CreatedToken, error) | |
| 31 | - | ListPage(ctx context.Context, p domain.Principal, size int, token string) (app.TokenPage, error) | |
| 32 | - | Revoke(ctx context.Context, p domain.Principal, id string) error | |
| 33 | - | } | |
| 34 | - | ||
| 35 | - | // Browse is the read side of a repository's content. *app.Browse fits. | |
| 36 | - | type Browse interface { | |
| 37 | - | ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListRefsParams) (app.RefPage, error) | |
| 38 | - | ResolveRevision(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) | |
| 39 | - | GetTree(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool) (domain.Tree, error) | |
| 40 | - | OpenBlob(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath) (domain.BlobInfo, io.ReadCloser, error) | |
| 41 | - | ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListCommitsParams) (app.CommitPage, error) | |
| 42 | - | GetCommit(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error) | |
| 43 | - | } | |
| 44 | - | ||
| 45 | - | // Events streams the events of the forge. *app.Events fits. | |
| 46 | - | type Events interface { | |
| 47 | - | Watch(ctx context.Context, p domain.Principal, params app.WatchParams, send func(app.WatchEvent) error) error | |
| 48 | - | } | |
| 49 | - | ||
| 50 | - | // MergeRequests is the merge request use cases. *app.MergeRequests fits. | |
| 51 | - | type MergeRequests interface { | |
| 52 | - | Create(ctx context.Context, p domain.Principal, name domain.RepoName, params app.CreateMergeRequestParams) (domain.MergeRequest, error) | |
| 53 | - | List(ctx context.Context, p domain.Principal, name domain.RepoName, params app.ListMergeRequestsParams) (app.MergeRequestPage, error) | |
| 54 | - | Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (app.MergeRequestDetail, error) | |
| 55 | - | AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.AddCommentParams) (domain.Comment, error) | |
| 56 | - | ResolveComment(ctx context.Context, p domain.Principal, name domain.RepoName, number, commentID int64, resolved bool) (domain.Comment, error) | |
| 57 | - | Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) | |
| 58 | - | MarkRead(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error) | |
| 59 | - | Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.MergeParams) (app.MergeResult, error) | |
| 60 | - | } | |
| 61 | - | ||
| 62 | - | // SigningKey tells which key signs the commits of the forge. *app.SigningKey | |
| 63 | - | // fits. | |
| 64 | - | type SigningKey interface { | |
| 65 | - | Info() domain.SigningKeyInfo | |
| 66 | - | } | |
| 67 | - | ||
| 68 | - | // Sessions is the owner's web session use cases the API serves. | |
| 69 | - | // *app.Sessions fits. | |
| 70 | - | type Sessions interface { | |
| 71 | - | CreateLoginLink(ctx context.Context, p domain.Principal) (app.LoginLink, error) | |
| 72 | - | SignOutEverywhere(ctx context.Context, p domain.Principal) error | |
| 73 | - | } | |
| 74 | - | ||
| 75 | - | // FailureLimiter counts the failed authentications per client. It is shared | |
| 76 | - | // with the other adapters that authenticate, so that a client has one budget | |
| 77 | - | // of failures. *clientlimit.Limiter fits. | |
| 78 | - | type FailureLimiter interface { | |
| 79 | - | Blocked(ctx context.Context, addr string) (bool, time.Duration) | |
| 80 | - | Fail(ctx context.Context, addr string) | |
| 81 | - | } | |
M internal/adapters/rpc/session.go +2 -1
| @@ -8,11 +8,12 @@ import ( | |||
| 8 | 8 | "connectrpc.com/connect" | |
| 9 | 9 | ||
| 10 | 10 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 11 | + | "bnema.dev/ermite/internal/ports" | |
| 11 | 12 | ) | |
| 12 | 13 | ||
| 13 | 14 | // sessionService implements ermiteconnect.SessionServiceHandler. The browser | |
| 14 | 15 | // never calls it: sessions come from the link, and the API ignores cookies. | |
| 15 | - | type sessionService struct{ sessions Sessions } | |
| 16 | + | type sessionService struct{ sessions ports.SessionService } | |
| 16 | 17 | ||
| 17 | 18 | func (s *sessionService) CreateLoginLink(ctx context.Context, _ *connect.Request[pb.CreateLoginLinkRequest]) (*connect.Response[pb.CreateLoginLinkResponse], error) { | |
| 18 | 19 | link, err := s.sessions.CreateLoginLink(ctx, caller(ctx)) | |
M internal/adapters/rpc/session_test.go +5 -5
| @@ -12,9 +12,9 @@ import ( | |||
| 12 | 12 | "github.com/stretchr/testify/require" | |
| 13 | 13 | ||
| 14 | 14 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 15 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |
| 16 | - | "bnema.dev/ermite/internal/app" | |
| 17 | 15 | "bnema.dev/ermite/internal/domain" | |
| 16 | + | "bnema.dev/ermite/internal/ports" | |
| 17 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 18 | 18 | ) | |
| 19 | 19 | ||
| 20 | 20 | func TestSessionServiceCreateLoginLink(t *testing.T) { | |
| @@ -32,9 +32,9 @@ func TestSessionServiceCreateLoginLink(t *testing.T) { | |||
| 32 | 32 | for _, tt := range tests { | |
| 33 | 33 | t.Run(tt.name, func(t *testing.T) { | |
| 34 | 34 | t.Parallel() | |
| 35 | - | sessions := mocks.NewSessions(t) | |
| 35 | + | sessions := mocks.NewSessionService(t) | |
| 36 | 36 | sessions.EXPECT().CreateLoginLink(mock.Anything, domain.Owner()). | |
| 37 | - | Return(app.LoginLink{URL: "https://x/-/login/n", ExpiresAt: exp}, tt.usecase).Once() | |
| 37 | + | Return(ports.LoginLink{URL: "https://x/-/login/n", ExpiresAt: exp}, tt.usecase).Once() | |
| 38 | 38 | resp, err := (&sessionService{sessions}).CreateLoginLink(ownerCtx(), connect.NewRequest(&pb.CreateLoginLinkRequest{})) | |
| 39 | 39 | if tt.wantCode != 0 { | |
| 40 | 40 | requireCode(t, tt.wantCode, err) | |
| @@ -60,7 +60,7 @@ func TestSessionServiceSignOutEverywhere(t *testing.T) { | |||
| 60 | 60 | for _, tt := range tests { | |
| 61 | 61 | t.Run(tt.name, func(t *testing.T) { | |
| 62 | 62 | t.Parallel() | |
| 63 | - | sessions := mocks.NewSessions(t) | |
| 63 | + | sessions := mocks.NewSessionService(t) | |
| 64 | 64 | sessions.EXPECT().SignOutEverywhere(mock.Anything, domain.Owner()).Return(tt.usecase).Once() | |
| 65 | 65 | _, err := (&sessionService{sessions}).SignOutEverywhere(ownerCtx(), connect.NewRequest(&pb.SignOutEverywhereRequest{})) | |
| 66 | 66 | if tt.wantCode != 0 { | |
M internal/adapters/rpc/token.go +3 -3
| @@ -8,15 +8,15 @@ import ( | |||
| 8 | 8 | "connectrpc.com/connect" | |
| 9 | 9 | ||
| 10 | 10 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 11 | - | "bnema.dev/ermite/internal/app" | |
| 12 | 11 | "bnema.dev/ermite/internal/domain" | |
| 12 | + | "bnema.dev/ermite/internal/ports" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | 15 | // tokenService implements ermiteconnect.TokenServiceHandler. | |
| 16 | - | type tokenService struct{ tokens Tokens } | |
| 16 | + | type tokenService struct{ tokens ports.TokenService } | |
| 17 | 17 | ||
| 18 | 18 | func (s *tokenService) CreateToken(ctx context.Context, req *connect.Request[pb.CreateTokenRequest]) (*connect.Response[pb.CreateTokenResponse], error) { | |
| 19 | - | params := app.CreateTokenParams{ | |
| 19 | + | params := ports.CreateTokenParams{ | |
| 20 | 20 | Label: req.Msg.GetLabel(), | |
| 21 | 21 | ExpiresAt: goTime(req.Msg.GetExpiresAt()), | |
| 22 | 22 | } | |
M internal/adapters/rpc/token_test.go +11 -11
| @@ -11,9 +11,9 @@ import ( | |||
| 11 | 11 | "github.com/stretchr/testify/require" | |
| 12 | 12 | ||
| 13 | 13 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |
| 15 | - | "bnema.dev/ermite/internal/app" | |
| 16 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 16 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 17 | 17 | ) | |
| 18 | 18 | ||
| 19 | 19 | func TestTokenServiceCreateToken(t *testing.T) { | |
| @@ -35,10 +35,10 @@ func TestTokenServiceCreateToken(t *testing.T) { | |||
| 35 | 35 | for _, tt := range tests { | |
| 36 | 36 | t.Run(tt.name, func(t *testing.T) { | |
| 37 | 37 | t.Parallel() | |
| 38 | - | tokens := mocks.NewTokens(t) | |
| 38 | + | tokens := mocks.NewTokenService(t) | |
| 39 | 39 | if tt.wantCall { | |
| 40 | 40 | tokens.EXPECT().Create(mock.Anything, domain.Owner(), mock.Anything). | |
| 41 | - | Return(app.CreatedToken{Token: domain.Token{ID: "t1", Label: "ci"}, Secret: "s3cret"}, tt.usecase).Once() | |
| 41 | + | Return(ports.CreatedToken{Token: domain.Token{ID: "t1", Label: "ci"}, Secret: "s3cret"}, tt.usecase).Once() | |
| 42 | 42 | } | |
| 43 | 43 | resp, err := (&tokenService{tokens}).CreateToken(ownerCtx(), connect.NewRequest(tt.req)) | |
| 44 | 44 | if tt.wantCode != 0 { | |
| @@ -54,10 +54,10 @@ func TestTokenServiceCreateToken(t *testing.T) { | |||
| 54 | 54 | ||
| 55 | 55 | func TestTokenServiceCreateTokenPassesParams(t *testing.T) { | |
| 56 | 56 | t.Parallel() | |
| 57 | - | tokens := mocks.NewTokens(t) | |
| 58 | - | tokens.EXPECT().Create(mock.Anything, domain.Owner(), mock.MatchedBy(func(p app.CreateTokenParams) bool { | |
| 57 | + | tokens := mocks.NewTokenService(t) | |
| 58 | + | tokens.EXPECT().Create(mock.Anything, domain.Owner(), mock.MatchedBy(func(p ports.CreateTokenParams) bool { | |
| 59 | 59 | return p.Label == "ci" && len(p.Scopes) == 1 && len(p.Repos) == 1 && p.Repos[0].String() == "demo" | |
| 60 | - | })).Return(app.CreatedToken{}, nil).Once() | |
| 60 | + | })).Return(ports.CreatedToken{}, nil).Once() | |
| 61 | 61 | _, err := (&tokenService{tokens}).CreateToken(ownerCtx(), connect.NewRequest(&pb.CreateTokenRequest{ | |
| 62 | 62 | Label: "ci", Scopes: []pb.Scope{pb.Scope_SCOPE_REPO_READ}, Repos: []string{"demo"}, | |
| 63 | 63 | })) | |
| @@ -78,7 +78,7 @@ func TestTokenServiceRevokeToken(t *testing.T) { | |||
| 78 | 78 | for _, tt := range tests { | |
| 79 | 79 | t.Run(tt.name, func(t *testing.T) { | |
| 80 | 80 | t.Parallel() | |
| 81 | - | tokens := mocks.NewTokens(t) | |
| 81 | + | tokens := mocks.NewTokenService(t) | |
| 82 | 82 | tokens.EXPECT().Revoke(mock.Anything, domain.Owner(), "t1").Return(tt.usecase).Once() | |
| 83 | 83 | _, err := (&tokenService{tokens}).RevokeToken(ownerCtx(), connect.NewRequest(&pb.RevokeTokenRequest{Id: "t1"})) | |
| 84 | 84 | if tt.wantCode != 0 { | |
| @@ -92,15 +92,15 @@ func TestTokenServiceRevokeToken(t *testing.T) { | |||
| 92 | 92 | ||
| 93 | 93 | func TestTokenServiceListTokens(t *testing.T) { | |
| 94 | 94 | t.Parallel() | |
| 95 | - | tokens := mocks.NewTokens(t) | |
| 95 | + | tokens := mocks.NewTokenService(t) | |
| 96 | 96 | tokens.EXPECT().ListPage(mock.Anything, domain.Owner(), 5, "tok"). | |
| 97 | - | Return(app.TokenPage{Tokens: []domain.Token{{ID: "a"}, {ID: "b"}}, NextPageToken: "n"}, nil).Once() | |
| 97 | + | Return(ports.TokenPage{Tokens: []domain.Token{{ID: "a"}, {ID: "b"}}, NextPageToken: "n"}, nil).Once() | |
| 98 | 98 | resp, err := (&tokenService{tokens}).ListTokens(ownerCtx(), connect.NewRequest(&pb.ListTokensRequest{PageSize: 5, PageToken: "tok"})) | |
| 99 | 99 | require.NoError(t, err) | |
| 100 | 100 | assert.Len(t, resp.Msg.GetTokens(), 2) | |
| 101 | 101 | assert.Equal(t, "n", resp.Msg.GetNextPageToken()) | |
| 102 | 102 | ||
| 103 | - | tokens.EXPECT().ListPage(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(app.TokenPage{}, domain.ErrInvalidPageToken).Once() | |
| 103 | + | tokens.EXPECT().ListPage(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ports.TokenPage{}, domain.ErrInvalidPageToken).Once() | |
| 104 | 104 | _, err = (&tokenService{tokens}).ListTokens(ownerCtx(), connect.NewRequest(&pb.ListTokensRequest{})) | |
| 105 | 105 | requireCode(t, connect.CodeInvalidArgument, err) | |
| 106 | 106 | } | |
M internal/adapters/web/events_test.go +6 -5
| @@ -20,7 +20,8 @@ import ( | |||
| 20 | 20 | ||
| 21 | 21 | pb "bnema.dev/ermite-api/gen/ermite" | |
| 22 | 22 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 23 | - | "bnema.dev/ermite/internal/adapters/web/mocks" | |
| 23 | + | "bnema.dev/ermite/internal/ports" | |
| 24 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 24 | 25 | ) | |
| 25 | 26 | ||
| 26 | 27 | func TestFormatEvent(t *testing.T) { | |
| @@ -115,7 +116,7 @@ func eventsServer(t *testing.T, f *fakeEvents, beat time.Duration, writeTimeout | |||
| 115 | 116 | } | |
| 116 | 117 | ||
| 117 | 118 | // eventsServerWith is eventsServer with sessions, when sess is not nil. | |
| 118 | - | func eventsServerWith(t *testing.T, f *fakeEvents, beat time.Duration, writeTimeout time.Duration, sess SessionAuth) *httptest.Server { | |
| 119 | + | func eventsServerWith(t *testing.T, f *fakeEvents, beat time.Duration, writeTimeout time.Duration, sess ports.WebSessionService) *httptest.Server { | |
| 119 | 120 | t.Helper() | |
| 120 | 121 | api := http.NewServeMux() | |
| 121 | 122 | api.Handle(ermiteconnect.NewEventServiceHandler(f)) | |
| @@ -287,16 +288,16 @@ func TestRepoUpdatedReloadsSummaryAndRefs(t *testing.T) { | |||
| 287 | 288 | } | |
| 288 | 289 | } | |
| 289 | 290 | ||
| 290 | - | func limiterFor(sess SessionAuth) FailureLimiter { | |
| 291 | + | func limiterFor(sess ports.WebSessionService) ports.FailureLimiter { | |
| 291 | 292 | if sess == nil { | |
| 292 | 293 | return nil | |
| 293 | 294 | } | |
| 294 | 295 | return &countingLimiter{} | |
| 295 | 296 | } | |
| 296 | 297 | ||
| 297 | - | // newRevocable is a SessionAuth whose one session ends when the test sets | |
| 298 | + | // newRevocable is a ports.WebSessionService whose one session ends when the test sets | |
| 298 | 299 | // ended, like SignOutEverywhere does. | |
| 299 | - | func newRevocable(t *testing.T, valid string) (*mocks.SessionAuth, *atomic.Bool) { | |
| 300 | + | func newRevocable(t *testing.T, valid string) (*mocks.WebSessionService, *atomic.Bool) { | |
| 300 | 301 | t.Helper() | |
| 301 | 302 | var ended atomic.Bool | |
| 302 | 303 | return newVerifier(t, valid, func(tok string) (bool, error) { return tok == valid && !ended.Load(), nil }), &ended | |
D internal/adapters/web/mocks/FailureLimiter.go +0 -160
| @@ -1,160 +0,0 @@ | |||
| 1 | - | // Code generated by mockery; DO NOT EDIT. | |
| 2 | - | // github.com/vektra/mockery | |
| 3 | - | // template: testify | |
| 4 | - | ||
| 5 | - | package mocks | |
| 6 | - | ||
| 7 | - | import ( | |
| 8 | - | "context" | |
| 9 | - | "time" | |
| 10 | - | ||
| 11 | - | mock "github.com/stretchr/testify/mock" | |
| 12 | - | ) | |
| 13 | - | ||
| 14 | - | // NewFailureLimiter creates a new instance of FailureLimiter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | - | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewFailureLimiter(t interface { | |
| 17 | - | mock.TestingT | |
| 18 | - | Cleanup(func()) | |
| 19 | - | }) *FailureLimiter { | |
| 20 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | - | helper.Helper() | |
| 22 | - | } | |
| 23 | - | ||
| 24 | - | mock := &FailureLimiter{} | |
| 25 | - | mock.Mock.Test(t) | |
| 26 | - | ||
| 27 | - | t.Cleanup(func() { | |
| 28 | - | if helper, ok := t.(interface{ Helper() }); ok { | |
| 29 | - | helper.Helper() | |
| 30 | - | } | |
| 31 | - | mock.AssertExpectations(t) | |
| 32 | - | }) | |
| 33 | - | ||
| 34 | - | return mock | |
| 35 | - | } | |
| 36 | - | ||
| 37 | - | // FailureLimiter is an autogenerated mock type for the FailureLimiter type | |
| 38 | - | type FailureLimiter struct { | |
| 39 | - | mock.Mock | |
| 40 | - | } | |
| 41 | - | ||
| 42 | - | type FailureLimiter_Expecter struct { | |
| 43 | - | mock *mock.Mock | |
| 44 | - | } | |
| 45 | - | ||
| 46 | - | func (_m *FailureLimiter) EXPECT() *FailureLimiter_Expecter { | |
| 47 | - | return &FailureLimiter_Expecter{mock: &_m.Mock} | |
| 48 | - | } | |
| 49 | - | ||
| 50 | - | // Blocked provides a mock function for the type FailureLimiter | |
| 51 | - | func (_mock *FailureLimiter) Blocked(ctx context.Context, addr string) (bool, time.Duration) { | |
| 52 | - | ret := _mock.Called(ctx, addr) | |
| 53 | - | ||
| 54 | - | if len(ret) == 0 { | |
| 55 | - | panic("no return value specified for Blocked") | |
| 56 | - | } | |
| 57 | - | ||
| 58 | - | var r0 bool | |
| 59 | - | var r1 time.Duration | |
| 60 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, string) (bool, time.Duration)); ok { | |
| 61 | - | return returnFunc(ctx, addr) | |
| 62 | - | } | |
| 63 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, string) bool); ok { | |
| 64 | - | r0 = returnFunc(ctx, addr) | |
| 65 | - | } else { | |
| 66 | - | r0 = ret.Get(0).(bool) | |
| 67 | - | } | |
| 68 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, string) time.Duration); ok { | |
| 69 | - | r1 = returnFunc(ctx, addr) | |
| 70 | - | } else { | |
| 71 | - | r1 = ret.Get(1).(time.Duration) | |
| 72 | - | } | |
| 73 | - | return r0, r1 | |
| 74 | - | } | |
| 75 | - | ||
| 76 | - | // FailureLimiter_Blocked_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Blocked' | |
| 77 | - | type FailureLimiter_Blocked_Call struct { | |
| 78 | - | *mock.Call | |
| 79 | - | } | |
| 80 | - | ||
| 81 | - | // Blocked is a helper method to define mock.On call | |
| 82 | - | // - ctx context.Context | |
| 83 | - | // - addr string | |
| 84 | - | func (_e *FailureLimiter_Expecter) Blocked(ctx any, addr any) *FailureLimiter_Blocked_Call { | |
| 85 | - | return &FailureLimiter_Blocked_Call{Call: _e.mock.On("Blocked", ctx, addr)} | |
| 86 | - | } | |
| 87 | - | ||
| 88 | - | func (_c *FailureLimiter_Blocked_Call) Run(run func(ctx context.Context, addr string)) *FailureLimiter_Blocked_Call { | |
| 89 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 90 | - | var arg0 context.Context | |
| 91 | - | if args[0] != nil { | |
| 92 | - | arg0 = args[0].(context.Context) | |
| 93 | - | } | |
| 94 | - | var arg1 string | |
| 95 | - | if args[1] != nil { | |
| 96 | - | arg1 = args[1].(string) | |
| 97 | - | } | |
| 98 | - | run( | |
| 99 | - | arg0, | |
| 100 | - | arg1, | |
| 101 | - | ) | |
| 102 | - | }) | |
| 103 | - | return _c | |
| 104 | - | } | |
| 105 | - | ||
| 106 | - | func (_c *FailureLimiter_Blocked_Call) Return(b bool, duration time.Duration) *FailureLimiter_Blocked_Call { | |
| 107 | - | _c.Call.Return(b, duration) | |
| 108 | - | return _c | |
| 109 | - | } | |
| 110 | - | ||
| 111 | - | func (_c *FailureLimiter_Blocked_Call) RunAndReturn(run func(ctx context.Context, addr string) (bool, time.Duration)) *FailureLimiter_Blocked_Call { | |
| 112 | - | _c.Call.Return(run) | |
| 113 | - | return _c | |
| 114 | - | } | |
| 115 | - | ||
| 116 | - | // Fail provides a mock function for the type FailureLimiter | |
| 117 | - | func (_mock *FailureLimiter) Fail(ctx context.Context, addr string) { | |
| 118 | - | _mock.Called(ctx, addr) | |
| 119 | - | return | |
| 120 | - | } | |
| 121 | - | ||
| 122 | - | // FailureLimiter_Fail_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Fail' | |
| 123 | - | type FailureLimiter_Fail_Call struct { | |
| 124 | - | *mock.Call | |
| 125 | - | } | |
| 126 | - | ||
| 127 | - | // Fail is a helper method to define mock.On call | |
| 128 | - | // - ctx context.Context | |
| 129 | - | // - addr string | |
| 130 | - | func (_e *FailureLimiter_Expecter) Fail(ctx any, addr any) *FailureLimiter_Fail_Call { | |
| 131 | - | return &FailureLimiter_Fail_Call{Call: _e.mock.On("Fail", ctx, addr)} | |
| 132 | - | } | |
| 133 | - | ||
| 134 | - | func (_c *FailureLimiter_Fail_Call) Run(run func(ctx context.Context, addr string)) *FailureLimiter_Fail_Call { | |
| 135 | - | _c.Call.Run(func(args mock.Arguments) { | |
| 136 | - | var arg0 context.Context | |
| 137 | - | if args[0] != nil { | |
| 138 | - | arg0 = args[0].(context.Context) | |
| 139 | - | } | |
| 140 | - | var arg1 string | |
| 141 | - | if args[1] != nil { | |
| 142 | - | arg1 = args[1].(string) | |
| 143 | - | } | |
| 144 | - | run( | |
| 145 | - | arg0, | |
| 146 | - | arg1, | |
| 147 | - | ) | |
| 148 | - | }) | |
| 149 | - | return _c | |
| 150 | - | } | |
| 151 | - | ||
| 152 | - | func (_c *FailureLimiter_Fail_Call) Return() *FailureLimiter_Fail_Call { | |
| 153 | - | _c.Call.Return() | |
| 154 | - | return _c | |
| 155 | - | } | |
| 156 | - | ||
| 157 | - | func (_c *FailureLimiter_Fail_Call) RunAndReturn(run func(ctx context.Context, addr string)) *FailureLimiter_Fail_Call { | |
| 158 | - | _c.Run(run) | |
| 159 | - | return _c | |
| 160 | - | } | |
M internal/adapters/web/session.go +3 -27
| @@ -16,6 +16,7 @@ import ( | |||
| 16 | 16 | "github.com/bnema/zerowrap" | |
| 17 | 17 | ||
| 18 | 18 | "bnema.dev/ermite/internal/clientlimit" | |
| 19 | + | "bnema.dev/ermite/internal/ports" | |
| 19 | 20 | ) | |
| 20 | 21 | ||
| 21 | 22 | // The owner's session on the web (ADR 0018). | |
| @@ -39,31 +40,6 @@ const CookieName = "__Host-ermite" | |||
| 39 | 40 | // loginPrefix is the path of login links, up to the nonce. | |
| 40 | 41 | const loginPrefix = "/-/login/" | |
| 41 | 42 | ||
| 42 | - | // ErrLinkRejected is what SessionAuth.Login returns for a link that is | |
| 43 | - | // unknown, expired or already used. | |
| 44 | - | var ErrLinkRejected = errors.New("login link rejected") | |
| 45 | - | ||
| 46 | - | // SessionAuth is the session side of the use cases, as the web needs it. | |
| 47 | - | type SessionAuth interface { | |
| 48 | - | // LoginLinkValid reports whether the link is pending, without using it. | |
| 49 | - | LoginLinkValid(nonce string) bool | |
| 50 | - | // Login uses the link and returns the session token and how long it | |
| 51 | - | // lasts, or ErrLinkRejected. | |
| 52 | - | Login(ctx context.Context, nonce string) (token string, lifetime time.Duration, err error) | |
| 53 | - | // Verify checks a session token. When it is valid it returns the context | |
| 54 | - | // to serve the request with, which carries the owner as the caller of the | |
| 55 | - | // API; when it is not, ok is false and err nil. An error means the check | |
| 56 | - | // could not be made (the request then runs as anonymous). | |
| 57 | - | Verify(ctx context.Context, token string) (owner context.Context, ok bool, err error) | |
| 58 | - | } | |
| 59 | - | ||
| 60 | - | // FailureLimiter counts failed logins per client, with the failed | |
| 61 | - | // authentications of the other routes. *clientlimit.Limiter fits. | |
| 62 | - | type FailureLimiter interface { | |
| 63 | - | Blocked(ctx context.Context, addr string) (bool, time.Duration) | |
| 64 | - | Fail(ctx context.Context, addr string) | |
| 65 | - | } | |
| 66 | - | ||
| 67 | 43 | type signedInKey struct{} | |
| 68 | 44 | ||
| 69 | 45 | // SignedIn reports whether the request carries a valid owner session. The | |
| @@ -275,12 +251,12 @@ func (s *Server) loginPost(w http.ResponseWriter, r *http.Request) { | |||
| 275 | 251 | nonce := r.PathValue("nonce") | |
| 276 | 252 | var token string | |
| 277 | 253 | var lifetime time.Duration | |
| 278 | - | err := ErrLinkRejected | |
| 254 | + | err := ports.ErrLinkRejected | |
| 279 | 255 | if validNonce(nonce) { | |
| 280 | 256 | token, lifetime, err = s.cfg.Sessions.Login(ctx, nonce) | |
| 281 | 257 | } | |
| 282 | 258 | switch { | |
| 283 | - | case errors.Is(err, ErrLinkRejected): | |
| 259 | + | case errors.Is(err, ports.ErrLinkRejected): | |
| 284 | 260 | s.cfg.Limiter.Fail(ctx, addr) | |
| 285 | 261 | s.secretPage(w, r, http.StatusNotFound, s.loginRejectedPage()) | |
| 286 | 262 | return | |
M internal/adapters/web/session_test.go +13 -12
| @@ -17,21 +17,22 @@ import ( | |||
| 17 | 17 | "github.com/stretchr/testify/require" | |
| 18 | 18 | ||
| 19 | 19 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 20 | - | "bnema.dev/ermite/internal/adapters/web/mocks" | |
| 20 | + | "bnema.dev/ermite/internal/ports" | |
| 21 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 21 | 22 | ) | |
| 22 | 23 | ||
| 23 | 24 | // nonceA is the one valid login link of the mocks. | |
| 24 | 25 | var nonceA = strings.Repeat("a", 43) | |
| 25 | 26 | ||
| 26 | - | // newVerifier is a SessionAuth that accepts the session token valid, checked | |
| 27 | + | // newVerifier is a WebSessionService that accepts the session token valid, checked | |
| 27 | 28 | // by verify when it is not nil, and that does not know any login link. A | |
| 28 | 29 | // call that is not expected fails the test. | |
| 29 | - | func newVerifier(t *testing.T, valid string, verify func(token string) (bool, error)) *mocks.SessionAuth { | |
| 30 | + | func newVerifier(t *testing.T, valid string, verify func(token string) (bool, error)) *mocks.WebSessionService { | |
| 30 | 31 | t.Helper() | |
| 31 | 32 | if verify == nil { | |
| 32 | 33 | verify = func(token string) (bool, error) { return token == valid, nil } | |
| 33 | 34 | } | |
| 34 | - | m := mocks.NewSessionAuth(t) | |
| 35 | + | m := mocks.NewWebSessionService(t) | |
| 35 | 36 | m.EXPECT().Verify(mock.Anything, mock.Anything).RunAndReturn( | |
| 36 | 37 | func(ctx context.Context, token string) (context.Context, bool, error) { | |
| 37 | 38 | ok, err := verify(token) | |
| @@ -41,22 +42,22 @@ func newVerifier(t *testing.T, valid string, verify func(token string) (bool, er | |||
| 41 | 42 | } | |
| 42 | 43 | ||
| 43 | 44 | // expectLogin makes nonceA the one link of m, answering with the token valid. | |
| 44 | - | func expectLogin(m *mocks.SessionAuth, valid string) { | |
| 45 | + | func expectLogin(m *mocks.WebSessionService, valid string) { | |
| 45 | 46 | m.EXPECT().LoginLinkValid(mock.Anything).RunAndReturn(func(n string) bool { return n == nonceA }).Maybe() | |
| 46 | 47 | m.EXPECT().Login(mock.Anything, nonceA).Return(valid, time.Hour, nil).Maybe() | |
| 47 | - | m.EXPECT().Login(mock.Anything, mock.Anything).Return("", time.Duration(0), ErrLinkRejected).Maybe() | |
| 48 | + | m.EXPECT().Login(mock.Anything, mock.Anything).Return("", time.Duration(0), ports.ErrLinkRejected).Maybe() | |
| 48 | 49 | } | |
| 49 | 50 | ||
| 50 | - | // newSessions is a SessionAuth with one session token and one login link. | |
| 51 | - | func newSessions(t *testing.T, valid string) *mocks.SessionAuth { | |
| 51 | + | // newSessions is a WebSessionService with one session token and one login link. | |
| 52 | + | func newSessions(t *testing.T, valid string) *mocks.WebSessionService { | |
| 52 | 53 | t.Helper() | |
| 53 | 54 | m := newVerifier(t, valid, nil) | |
| 54 | 55 | expectLogin(m, valid) | |
| 55 | 56 | return m | |
| 56 | 57 | } | |
| 57 | 58 | ||
| 58 | - | // newBrokenSessions is a SessionAuth whose check cannot be made. | |
| 59 | - | func newBrokenSessions(t *testing.T, valid string) *mocks.SessionAuth { | |
| 59 | + | // newBrokenSessions is a WebSessionService whose check cannot be made. | |
| 60 | + | func newBrokenSessions(t *testing.T, valid string) *mocks.WebSessionService { | |
| 60 | 61 | t.Helper() | |
| 61 | 62 | m := newVerifier(t, valid, func(string) (bool, error) { return false, errors.New("kv down") }) | |
| 62 | 63 | expectLogin(m, valid) | |
| @@ -68,7 +69,7 @@ type countingLimiter struct{ fails int } | |||
| 68 | 69 | func (*countingLimiter) Blocked(context.Context, string) (bool, time.Duration) { return false, 0 } | |
| 69 | 70 | func (l *countingLimiter) Fail(context.Context, string) { l.fails++ } | |
| 70 | 71 | ||
| 71 | - | func newSessionServer(t *testing.T, sess SessionAuth, publicURL string) (*Server, *countingLimiter) { | |
| 72 | + | func newSessionServer(t *testing.T, sess ports.WebSessionService, publicURL string) (*Server, *countingLimiter) { | |
| 72 | 73 | t.Helper() | |
| 73 | 74 | lim := &countingLimiter{} | |
| 74 | 75 | srv, err := New(Config{ | |
| @@ -294,7 +295,7 @@ func TestNoSessionsNoRoutes(t *testing.T) { | |||
| 294 | 295 | ||
| 295 | 296 | _, err = New(Config{ | |
| 296 | 297 | Repos: failing{}, Git: ermiteconnect.NewGitServiceClient(http.DefaultClient, "http://unused.invalid"), | |
| 297 | - | PublicURL: "https://forge.example", Sessions: mocks.NewSessionAuth(t), | |
| 298 | + | PublicURL: "https://forge.example", Sessions: mocks.NewWebSessionService(t), | |
| 298 | 299 | }) | |
| 299 | 300 | assert.Error(t, err, "sessions need a limiter") | |
| 300 | 301 | } | |
M internal/adapters/web/web.go +3 -2
| @@ -33,6 +33,7 @@ import ( | |||
| 33 | 33 | "github.com/bnema/zerowrap" | |
| 34 | 34 | ||
| 35 | 35 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | |
| 36 | + | "bnema.dev/ermite/internal/ports" | |
| 36 | 37 | ) | |
| 37 | 38 | ||
| 38 | 39 | // Patterns are the ServeMux patterns the handler serves: everything. The | |
| @@ -69,10 +70,10 @@ type Config struct { | |||
| 69 | 70 | Now func() time.Time | |
| 70 | 71 | // Sessions signs the owner in (ADR 0018). Without it there are no login | |
| 71 | 72 | // routes and every visitor is anonymous. | |
| 72 | - | Sessions SessionAuth | |
| 73 | + | Sessions ports.WebSessionService | |
| 73 | 74 | // Limiter counts the failed logins; required with Sessions. Share it with | |
| 74 | 75 | // the API and Git, so that a client has one budget of failures. | |
| 75 | - | Limiter FailureLimiter | |
| 76 | + | Limiter ports.FailureLimiter | |
| 76 | 77 | // TrustedProxies are the networks allowed to set X-Forwarded-For, to find | |
| 77 | 78 | // the address of the client that fails a login. | |
| 78 | 79 | TrustedProxies []netip.Prefix | |
M internal/app/browse.go +15 -52
| @@ -31,6 +31,8 @@ type Browse struct { | |||
| 31 | 31 | history *historyCache | |
| 32 | 32 | } | |
| 33 | 33 | ||
| 34 | + | var _ ports.BrowseService = (*Browse)(nil) | |
| 35 | + | ||
| 34 | 36 | // NewBrowse builds the read use cases over their ports, with a history cache | |
| 35 | 37 | // of the default bounds. | |
| 36 | 38 | func NewBrowse(meta ports.RepoMetaStore, reader ports.RepoReader) *Browse { | |
| @@ -71,23 +73,6 @@ func repoEpoch(r domain.Repo) int64 { | |||
| 71 | 73 | return r.CreatedAt.UnixNano() | |
| 72 | 74 | } | |
| 73 | 75 | ||
| 74 | - | // ListRefsParams selects the refs to list. | |
| 75 | - | type ListRefsParams struct { | |
| 76 | - | // Kinds restricts the result; empty means every kind. | |
| 77 | - | Kinds []domain.RefKind | |
| 78 | - | // PageSize is 0 for the default, and lowered to MaxRefPageSize. | |
| 79 | - | PageSize int | |
| 80 | - | // PageToken is the NextPageToken of the previous page, or empty. | |
| 81 | - | PageToken string | |
| 82 | - | } | |
| 83 | - | ||
| 84 | - | // RefPage is a page of refs. | |
| 85 | - | type RefPage struct { | |
| 86 | - | Refs []domain.Ref | |
| 87 | - | // NextPageToken is empty on the last page. | |
| 88 | - | NextPageToken string | |
| 89 | - | } | |
| 90 | - | ||
| 91 | 76 | func kindRank(k domain.RefKind) int { | |
| 92 | 77 | switch k { | |
| 93 | 78 | case domain.RefKindHead: | |
| @@ -101,26 +86,26 @@ func kindRank(k domain.RefKind) int { | |||
| 101 | 86 | // ListRefs lists HEAD, the branches and the tags, in that order, then by | |
| 102 | 87 | // name. The page token names the last ref of the previous page, so refs that | |
| 103 | 88 | // appear or disappear between two pages never shift the others. | |
| 104 | - | func (b *Browse) ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params ListRefsParams) (RefPage, error) { | |
| 89 | + | func (b *Browse) ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListRefsParams) (ports.RefPage, error) { | |
| 105 | 90 | size, err := pageSizeUpTo(params.PageSize, MaxRefPageSize) | |
| 106 | 91 | if err != nil { | |
| 107 | - | return RefPage{}, err | |
| 92 | + | return ports.RefPage{}, err | |
| 108 | 93 | } | |
| 109 | 94 | for _, k := range params.Kinds { | |
| 110 | 95 | if k != domain.RefKindHead && k != domain.RefKindBranch && k != domain.RefKindTag { | |
| 111 | - | return RefPage{}, fmt.Errorf("%w: %q", domain.ErrInvalidRefKind, k) | |
| 96 | + | return ports.RefPage{}, fmt.Errorf("%w: %q", domain.ErrInvalidRefKind, k) | |
| 112 | 97 | } | |
| 113 | 98 | } | |
| 114 | 99 | after, err := decodeRefToken(params.PageToken) | |
| 115 | 100 | if err != nil { | |
| 116 | - | return RefPage{}, err | |
| 101 | + | return ports.RefPage{}, err | |
| 117 | 102 | } | |
| 118 | 103 | if _, err := b.authorize(ctx, p, repo); err != nil { | |
| 119 | - | return RefPage{}, err | |
| 104 | + | return ports.RefPage{}, err | |
| 120 | 105 | } | |
| 121 | 106 | all, err := b.reader.ListRefs(ctx, repo) | |
| 122 | 107 | if err != nil { | |
| 123 | - | return RefPage{}, err | |
| 108 | + | return ports.RefPage{}, err | |
| 124 | 109 | } | |
| 125 | 110 | ||
| 126 | 111 | var wanted []domain.Ref | |
| @@ -129,7 +114,7 @@ func (b *Browse) ListRefs(ctx context.Context, p domain.Principal, repo domain.R | |||
| 129 | 114 | wanted = append(wanted, r) | |
| 130 | 115 | } | |
| 131 | 116 | } | |
| 132 | - | var page RefPage | |
| 117 | + | var page ports.RefPage | |
| 133 | 118 | page.Refs, page.NextPageToken = pageAfter(wanted, size, | |
| 134 | 119 | func(r domain.Ref) bool { return after == nil || refAfter(r, *after) }, | |
| 135 | 120 | encodeRefToken) | |
| @@ -227,53 +212,31 @@ func (b *Browse) OpenBlob(ctx context.Context, p domain.Principal, repo domain.R | |||
| 227 | 212 | return b.reader.OpenBlob(ctx, repo, rev, path) | |
| 228 | 213 | } | |
| 229 | 214 | ||
| 230 | - | // ListCommitsParams selects a page of history. | |
| 231 | - | type ListCommitsParams struct { | |
| 232 | - | // Revision is where the history starts; the zero value is HEAD. Ignored | |
| 233 | - | // when PageToken is set: the token pins the commit the first page started | |
| 234 | - | // from, so every page walks the same history even if a branch moves. | |
| 235 | - | Revision domain.Revision | |
| 236 | - | // Path limits the history to the commits that changed it. It must be the | |
| 237 | - | // same on every page of a listing. | |
| 238 | - | Path domain.TreePath | |
| 239 | - | // PageSize is 0 for the default, and lowered to MaxPageSize. | |
| 240 | - | PageSize int | |
| 241 | - | // PageToken is the NextPageToken of the previous page, or empty. | |
| 242 | - | PageToken string | |
| 243 | - | } | |
| 244 | - | ||
| 245 | - | // CommitPage is a page of history, newest first. | |
| 246 | - | type CommitPage struct { | |
| 247 | - | Commits []domain.Commit | |
| 248 | - | // NextPageToken is empty on the last page. | |
| 249 | - | NextPageToken string | |
| 250 | - | } | |
| 251 | - | ||
| 252 | 215 | // ListCommits returns a page of history. The page token holds the commit the | |
| 253 | 216 | // listing started from, how many commits were already returned and a digest | |
| 254 | 217 | // of the path; a token used with another path is invalid. | |
| 255 | - | func (b *Browse) ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params ListCommitsParams) (CommitPage, error) { | |
| 218 | + | func (b *Browse) ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListCommitsParams) (ports.HistoryPage, error) { | |
| 256 | 219 | size, err := pageSize(params.PageSize) | |
| 257 | 220 | if err != nil { | |
| 258 | - | return CommitPage{}, err | |
| 221 | + | return ports.HistoryPage{}, err | |
| 259 | 222 | } | |
| 260 | 223 | q := ports.CommitQuery{Revision: params.Revision, Path: params.Path, Limit: size} | |
| 261 | 224 | if params.PageToken != "" { | |
| 262 | 225 | head, skip, err := decodeCommitToken(params.PageToken, params.Path) | |
| 263 | 226 | if err != nil { | |
| 264 | - | return CommitPage{}, err | |
| 227 | + | return ports.HistoryPage{}, err | |
| 265 | 228 | } | |
| 266 | 229 | q.Revision, q.Skip = domain.RevisionOf(head), skip | |
| 267 | 230 | } | |
| 268 | 231 | r, err := b.authorize(ctx, p, repo) | |
| 269 | 232 | if err != nil { | |
| 270 | - | return CommitPage{}, err | |
| 233 | + | return ports.HistoryPage{}, err | |
| 271 | 234 | } | |
| 272 | 235 | res, err := b.listCommits(ctx, r, q) | |
| 273 | 236 | if err != nil { | |
| 274 | - | return CommitPage{}, err | |
| 237 | + | return ports.HistoryPage{}, err | |
| 275 | 238 | } | |
| 276 | - | out := CommitPage{Commits: res.Commits} | |
| 239 | + | out := ports.HistoryPage{Commits: res.Commits} | |
| 277 | 240 | if res.HasMore { | |
| 278 | 241 | out.NextPageToken = encodeCommitToken(res.Head, q.Skip+len(res.Commits), params.Path) | |
| 279 | 242 | } | |
M internal/app/browse_test.go +24 -24
| @@ -55,7 +55,7 @@ func browseOps() []browseOp { | |||
| 55 | 55 | root := domain.TreePath{} | |
| 56 | 56 | return []browseOp{ | |
| 57 | 57 | {"ListRefs", func(b *app.Browse, ctx context.Context, p domain.Principal, repo domain.RepoName) error { | |
| 58 | - | _, err := b.ListRefs(ctx, p, repo, app.ListRefsParams{}) | |
| 58 | + | _, err := b.ListRefs(ctx, p, repo, ports.ListRefsParams{}) | |
| 59 | 59 | return err | |
| 60 | 60 | }, func(r *mocks.RepoReader) { r.EXPECT().ListRefs(mock.Anything, mock.Anything).Return(nil, nil) }}, | |
| 61 | 61 | {"ResolveRevision", func(b *app.Browse, ctx context.Context, p domain.Principal, repo domain.RepoName) error { | |
| @@ -87,7 +87,7 @@ func browseOps() []browseOp { | |||
| 87 | 87 | Return(domain.BlobInfo{}, io.NopCloser(strings.NewReader("")), nil) | |
| 88 | 88 | }}, | |
| 89 | 89 | {"ListCommits", func(b *app.Browse, ctx context.Context, p domain.Principal, repo domain.RepoName) error { | |
| 90 | - | _, err := b.ListCommits(ctx, p, repo, app.ListCommitsParams{}) | |
| 90 | + | _, err := b.ListCommits(ctx, p, repo, ports.ListCommitsParams{}) | |
| 91 | 91 | return err | |
| 92 | 92 | }, func(r *mocks.RepoReader) { | |
| 93 | 93 | r.EXPECT().ListCommits(mock.Anything, mock.Anything, mock.Anything).Return(ports.CommitPage{}, nil) | |
| @@ -214,7 +214,7 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||
| 214 | 214 | tok := "" | |
| 215 | 215 | for pages := 0; ; pages++ { | |
| 216 | 216 | require.Less(t, pages, 10) | |
| 217 | - | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{PageSize: 2, PageToken: tok}) | |
| 217 | + | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{PageSize: 2, PageToken: tok}) | |
| 218 | 218 | require.NoError(t, err) | |
| 219 | 219 | got = append(got, names(page.Refs)...) | |
| 220 | 220 | if tok = page.NextPageToken; tok == "" { | |
| @@ -226,19 +226,19 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||
| 226 | 226 | ||
| 227 | 227 | t.Run("a ref that appears between pages does not shift the others", func(t *testing.T) { | |
| 228 | 228 | b := setup(t, all[:4]) | |
| 229 | - | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{PageSize: 2}) | |
| 229 | + | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{PageSize: 2}) | |
| 230 | 230 | require.NoError(t, err) | |
| 231 | 231 | require.Equal(t, []string{"HEAD", "refs/heads/a"}, names(page.Refs)) | |
| 232 | 232 | ||
| 233 | 233 | b2 := setup(t, append([]domain.Ref{all[0], ref(domain.RefKindBranch, "refs/heads/0new")}, all[1:4]...)) | |
| 234 | - | next, err := b2.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{PageSize: 2, PageToken: page.NextPageToken}) | |
| 234 | + | next, err := b2.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{PageSize: 2, PageToken: page.NextPageToken}) | |
| 235 | 235 | require.NoError(t, err) | |
| 236 | 236 | assert.Equal(t, []string{"refs/heads/b", "refs/heads/c"}, names(next.Refs)) | |
| 237 | 237 | }) | |
| 238 | 238 | ||
| 239 | 239 | t.Run("kinds filter", func(t *testing.T) { | |
| 240 | 240 | b := setup(t, all) | |
| 241 | - | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{Kinds: []domain.RefKind{domain.RefKindTag}}) | |
| 241 | + | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{Kinds: []domain.RefKind{domain.RefKindTag}}) | |
| 242 | 242 | require.NoError(t, err) | |
| 243 | 243 | assert.Equal(t, []string{"refs/tags/v1", "refs/tags/v2"}, names(page.Refs)) | |
| 244 | 244 | assert.Empty(t, page.NextPageToken) | |
| @@ -251,13 +251,13 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||
| 251 | 251 | many = append(many, ref(domain.RefKindTag, fmt.Sprintf("refs/tags/t%04d", i))) | |
| 252 | 252 | } | |
| 253 | 253 | b := setup(t, many) | |
| 254 | - | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{}) | |
| 254 | + | page, err := b.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{}) | |
| 255 | 255 | require.NoError(t, err) | |
| 256 | 256 | assert.Len(t, page.Refs, app.DefaultPageSize) | |
| 257 | 257 | assert.NotEmpty(t, page.NextPageToken) | |
| 258 | 258 | ||
| 259 | 259 | b = setup(t, many) | |
| 260 | - | page, err = b.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{PageSize: 100000}) | |
| 260 | + | page, err = b.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{PageSize: 100000}) | |
| 261 | 261 | require.NoError(t, err) | |
| 262 | 262 | assert.Len(t, page.Refs, app.MaxRefPageSize, "a page holds up to MaxRefPageSize refs") | |
| 263 | 263 | assert.NotEmpty(t, page.NextPageToken) | |
| @@ -266,7 +266,7 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||
| 266 | 266 | t.Run("bad input never reaches the reader", func(t *testing.T) { | |
| 267 | 267 | t.Parallel() | |
| 268 | 268 | f := newBrowseFixture(t) | |
| 269 | - | for _, params := range []app.ListRefsParams{ | |
| 269 | + | for _, params := range []ports.ListRefsParams{ | |
| 270 | 270 | {PageSize: -1}, | |
| 271 | 271 | {Kinds: []domain.RefKind{"nope"}}, | |
| 272 | 272 | {PageToken: "!!!"}, | |
| @@ -275,11 +275,11 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||
| 275 | 275 | _, err := f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, params) | |
| 276 | 276 | assert.Error(t, err, "%+v", params) | |
| 277 | 277 | } | |
| 278 | - | _, err := f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{PageSize: -1}) | |
| 278 | + | _, err := f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{PageSize: -1}) | |
| 279 | 279 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | |
| 280 | - | _, err = f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{Kinds: []domain.RefKind{"x"}}) | |
| 280 | + | _, err = f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{Kinds: []domain.RefKind{"x"}}) | |
| 281 | 281 | assert.ErrorIs(t, err, domain.ErrInvalidRefKind) | |
| 282 | - | _, err = f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, app.ListRefsParams{PageToken: "!!!"}) | |
| 282 | + | _, err = f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, ports.ListRefsParams{PageToken: "!!!"}) | |
| 283 | 283 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | |
| 284 | 284 | }) | |
| 285 | 285 | } | |
| @@ -296,7 +296,7 @@ func TestListCommitsPaging(t *testing.T) { | |||
| 296 | 296 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | |
| 297 | 297 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Path: p, Limit: 10}). | |
| 298 | 298 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil) | |
| 299 | - | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{Path: p, PageSize: 10}) | |
| 299 | + | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{Path: p, PageSize: 10}) | |
| 300 | 300 | require.NoError(t, err) | |
| 301 | 301 | require.Len(t, page.Commits, 1) | |
| 302 | 302 | require.NotEmpty(t, page.NextPageToken) | |
| @@ -308,7 +308,7 @@ func TestListCommitsPaging(t *testing.T) { | |||
| 308 | 308 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | |
| 309 | 309 | // The revision of the request is ignored once there is a token. | |
| 310 | 310 | rev, _ := domain.ParseRevision("moved") | |
| 311 | - | next, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{ | |
| 311 | + | next, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{ | |
| 312 | 312 | Revision: rev, Path: p, PageSize: 10, PageToken: page.NextPageToken, | |
| 313 | 313 | }) | |
| 314 | 314 | require.NoError(t, err) | |
| @@ -322,10 +322,10 @@ func TestListCommitsPaging(t *testing.T) { | |||
| 322 | 322 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | |
| 323 | 323 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.Anything). | |
| 324 | 324 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil) | |
| 325 | - | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{Path: p}) | |
| 325 | + | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{Path: p}) | |
| 326 | 326 | require.NoError(t, err) | |
| 327 | 327 | ||
| 328 | - | for _, params := range []app.ListCommitsParams{ | |
| 328 | + | for _, params := range []ports.ListCommitsParams{ | |
| 329 | 329 | {PageToken: page.NextPageToken}, // no path | |
| 330 | 330 | {Path: mustPath(t, "other"), PageToken: page.NextPageToken}, // another path | |
| 331 | 331 | {Path: p, PageToken: "garbage"}, | |
| @@ -343,7 +343,7 @@ func TestListCommitsPaging(t *testing.T) { | |||
| 343 | 343 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil).Maybe() | |
| 344 | 344 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.Anything). | |
| 345 | 345 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil).Once() | |
| 346 | - | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{Path: p}) | |
| 346 | + | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{Path: p}) | |
| 347 | 347 | require.NoError(t, err) | |
| 348 | 348 | raw, err := base64.RawURLEncoding.DecodeString(page.NextPageToken) | |
| 349 | 349 | require.NoError(t, err) | |
| @@ -356,9 +356,9 @@ func TestListCommitsPaging(t *testing.T) { | |||
| 356 | 356 | ||
| 357 | 357 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.MatchedBy(func(q ports.CommitQuery) bool { return q.Skip == app.MaxCommitSkip })). | |
| 358 | 358 | Return(ports.CommitPage{Head: oid("a")}, nil).Once() | |
| 359 | - | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{Path: p, PageToken: withSkip(app.MaxCommitSkip)}) | |
| 359 | + | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{Path: p, PageToken: withSkip(app.MaxCommitSkip)}) | |
| 360 | 360 | require.NoError(t, err, "the cap itself is allowed") | |
| 361 | - | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{Path: p, PageToken: withSkip(app.MaxCommitSkip + 1)}) | |
| 361 | + | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{Path: p, PageToken: withSkip(app.MaxCommitSkip + 1)}) | |
| 362 | 362 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | |
| 363 | 363 | }) | |
| 364 | 364 | ||
| @@ -368,11 +368,11 @@ func TestListCommitsPaging(t *testing.T) { | |||
| 368 | 368 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil).Times(2) | |
| 369 | 369 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Limit: app.DefaultPageSize}).Return(ports.CommitPage{}, nil) | |
| 370 | 370 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Limit: 100}).Return(ports.CommitPage{}, nil) | |
| 371 | - | _, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{}) | |
| 371 | + | _, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{}) | |
| 372 | 372 | require.NoError(t, err) | |
| 373 | - | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{PageSize: 5000}) | |
| 373 | + | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{PageSize: 5000}) | |
| 374 | 374 | require.NoError(t, err) | |
| 375 | - | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{PageSize: -3}) | |
| 375 | + | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{PageSize: -3}) | |
| 376 | 376 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | |
| 377 | 377 | }) | |
| 378 | 378 | ||
| @@ -382,10 +382,10 @@ func TestListCommitsPaging(t *testing.T) { | |||
| 382 | 382 | f.meta.EXPECT().Get(ctx, priv.Name).Return(priv, nil) | |
| 383 | 383 | f.reader.EXPECT().ListCommits(ctx, priv.Name, mock.Anything). | |
| 384 | 384 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil) | |
| 385 | - | page, err := f.browse.ListCommits(ctx, domain.Root(), priv.Name, app.ListCommitsParams{}) | |
| 385 | + | page, err := f.browse.ListCommits(ctx, domain.Root(), priv.Name, ports.ListCommitsParams{}) | |
| 386 | 386 | require.NoError(t, err) | |
| 387 | 387 | f.meta.EXPECT().Get(ctx, priv.Name).Return(priv, nil) | |
| 388 | - | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), priv.Name, app.ListCommitsParams{PageToken: page.NextPageToken}) | |
| 388 | + | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), priv.Name, ports.ListCommitsParams{PageToken: page.NextPageToken}) | |
| 389 | 389 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| 390 | 390 | }) | |
| 391 | 391 | } | |
M internal/app/browsecache_test.go +4 -4
| @@ -131,7 +131,7 @@ func TestHistoryCacheNotServedAcrossRecreate(t *testing.T) { | |||
| 131 | 131 | r.EXPECT().GetTree(mock.Anything, n, rev, dir, true).Return(domain.Tree{}, domain.ErrNotFound).Once() | |
| 132 | 132 | }}, | |
| 133 | 133 | {"last change of a path", func(b *app.Browse) error { | |
| 134 | - | _, err := b.ListCommits(ctx, domain.Anonymous(), n, app.ListCommitsParams{Revision: rev, Path: dir, PageSize: 1}) | |
| 134 | + | _, err := b.ListCommits(ctx, domain.Anonymous(), n, ports.ListCommitsParams{Revision: rev, Path: dir, PageSize: 1}) | |
| 135 | 135 | return err | |
| 136 | 136 | }, func(r *mocks.RepoReader) { | |
| 137 | 137 | q := ports.CommitQuery{Revision: rev, Path: dir, Limit: 1} | |
| @@ -305,7 +305,7 @@ func TestListCommitsLastChangeCache(t *testing.T) { | |||
| 305 | 305 | }, nil).Times(tc.calls) | |
| 306 | 306 | for range 2 { | |
| 307 | 307 | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, | |
| 308 | - | app.ListCommitsParams{Revision: tc.rev, Path: tc.path, PageSize: tc.size}) | |
| 308 | + | ports.ListCommitsParams{Revision: tc.rev, Path: tc.path, PageSize: tc.size}) | |
| 309 | 309 | require.NoError(t, err) | |
| 310 | 310 | require.Len(t, page.Commits, 1) | |
| 311 | 311 | page.Commits[0].Parents[0] = oid("f") // must not leak into the cache | |
| @@ -319,13 +319,13 @@ func TestListCommitsLastChangeCache(t *testing.T) { | |||
| 319 | 319 | f.meta.EXPECT().Get(mock.Anything, pub.Name).Return(pub, nil) | |
| 320 | 320 | f.reader.EXPECT().ListCommits(mock.Anything, pub.Name, ports.CommitQuery{Revision: full, Path: file, Limit: 1}). | |
| 321 | 321 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("c")}}, HasMore: true}, nil).Once() | |
| 322 | - | first, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{Revision: full, Path: file, PageSize: 1}) | |
| 322 | + | first, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{Revision: full, Path: file, PageSize: 1}) | |
| 323 | 323 | require.NoError(t, err) | |
| 324 | 324 | require.NotEmpty(t, first.NextPageToken) | |
| 325 | 325 | f.reader.EXPECT().ListCommits(mock.Anything, pub.Name, ports.CommitQuery{Revision: domain.RevisionOf(oid("a")), Path: file, Skip: 1, Limit: 1}). | |
| 326 | 326 | Return(ports.CommitPage{Head: oid("a")}, nil).Twice() | |
| 327 | 327 | for range 2 { | |
| 328 | - | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, app.ListCommitsParams{Path: file, PageSize: 1, PageToken: first.NextPageToken}) | |
| 328 | + | _, err = f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, ports.ListCommitsParams{Path: file, PageSize: 1, PageToken: first.NextPageToken}) | |
| 329 | 329 | require.NoError(t, err) | |
| 330 | 330 | } | |
| 331 | 331 | }) | |
M internal/app/events.go +13 -45
| @@ -27,7 +27,7 @@ const ( | |||
| 27 | 27 | // MaxWatchers is the most watches in progress at once. | |
| 28 | 28 | MaxWatchers = 256 | |
| 29 | 29 | // MaxWatchersPerClient is the most watches in progress for one client | |
| 30 | - | // address (see WatchParams.Client). | |
| 30 | + | // address (see ports.WatchParams.Client). | |
| 31 | 31 | MaxWatchersPerClient = 16 | |
| 32 | 32 | // DefaultRevalidateEvery is how long a watcher with a stored token goes | |
| 33 | 33 | // without asking the token store whether the token still exists. | |
| @@ -74,7 +74,7 @@ type bufferedEvent struct { | |||
| 74 | 74 | // NewEvents and lives until Close. | |
| 75 | 75 | type Events struct { | |
| 76 | 76 | repos *Repos | |
| 77 | - | auth Revalidator | |
| 77 | + | auth ports.Revalidator | |
| 78 | 78 | clock ports.Clock | |
| 79 | 79 | boot string | |
| 80 | 80 | size int | |
| @@ -92,13 +92,15 @@ type Events struct { | |||
| 92 | 92 | clients map[string]int // watches in progress by client | |
| 93 | 93 | } | |
| 94 | 94 | ||
| 95 | + | var _ ports.EventService = (*Events)(nil) | |
| 96 | + | ||
| 95 | 97 | // EventsConfig configures Events. | |
| 96 | 98 | type EventsConfig struct { | |
| 97 | 99 | // Size is the number of events remembered; DefaultEventBuffer when not | |
| 98 | 100 | // positive. | |
| 99 | 101 | Size int | |
| 100 | 102 | // Auth confirms that the token of a watcher still exists. Required. | |
| 101 | - | Auth Revalidator | |
| 103 | + | Auth ports.Revalidator | |
| 102 | 104 | // RevalidateEvery is how long the answer of Auth is kept for a watcher; | |
| 103 | 105 | // DefaultRevalidateEvery when zero, and negative to ask for every event. | |
| 104 | 106 | RevalidateEvery time.Duration | |
| @@ -246,40 +248,6 @@ func (e *Events) parseID(id string) (uint64, bool) { | |||
| 246 | 248 | return n, err == nil && n > 0 | |
| 247 | 249 | } | |
| 248 | 250 | ||
| 249 | - | // WatchParams select the events of a watch. | |
| 250 | - | type WatchParams struct { | |
| 251 | - | // Topics are TopicHome or "repo:<name>"; empty means TopicHome. | |
| 252 | - | Topics []string | |
| 253 | - | // ResumeAfter is the id of the last event the caller saw; empty to | |
| 254 | - | // receive only new events. | |
| 255 | - | ResumeAfter string | |
| 256 | - | // Client identifies where the watch comes from, for the limit per client | |
| 257 | - | // (MaxWatchersPerClient): an opaque key such as a normalized address; the | |
| 258 | - | // web passes its visitor's. Empty only for callers with no client, which | |
| 259 | - | // count against MaxWatchers alone. | |
| 260 | - | Client string | |
| 261 | - | // Ready, when not nil, is called once the topics are valid and the watch | |
| 262 | - | // is registered: events published from then on are not missed. Nothing is | |
| 263 | - | // sent before it returns. | |
| 264 | - | Ready func() | |
| 265 | - | } | |
| 266 | - | ||
| 267 | - | // WatchEvent is one item of a watch. | |
| 268 | - | type WatchEvent struct { | |
| 269 | - | // ID identifies the event, for resuming. Empty on a gap. | |
| 270 | - | ID string | |
| 271 | - | // Gap tells that events were lost: the caller must reload what it shows. | |
| 272 | - | // Event is nil then. | |
| 273 | - | Gap bool | |
| 274 | - | // Event is a domain.RepoCreated, RepoUpdated, RepoDeleted, PushEvent, | |
| 275 | - | // MergeRequestOpened, MergeRequestMerged, MergeRequestClosed or | |
| 276 | - | // CommentAdded. | |
| 277 | - | Event domain.Event | |
| 278 | - | // Repo is the state of the repository at delivery, for RepoCreated and | |
| 279 | - | // RepoUpdated. | |
| 280 | - | Repo *RepoView | |
| 281 | - | } | |
| 282 | - | ||
| 283 | 251 | // watch is the state of one Watch call. | |
| 284 | 252 | type watch struct { | |
| 285 | 253 | p domain.Principal | |
| @@ -337,7 +305,7 @@ func (e *Events) parseTopics(ctx context.Context, p domain.Principal, topics []s | |||
| 337 | 305 | // buffered, or was not issued by this run, a gap comes first and the oldest | |
| 338 | 306 | // buffered event follows. A watcher that falls more than the buffer behind | |
| 339 | 307 | // gets a gap too, and carries on with the oldest buffered event. | |
| 340 | - | func (e *Events) Watch(ctx context.Context, p domain.Principal, params WatchParams, send func(WatchEvent) error) error { | |
| 308 | + | func (e *Events) Watch(ctx context.Context, p domain.Principal, params ports.WatchParams, send func(ports.WatchEvent) error) error { | |
| 341 | 309 | w, err := e.parseTopics(ctx, p, params.Topics) | |
| 342 | 310 | if err != nil { | |
| 343 | 311 | return err | |
| @@ -382,7 +350,7 @@ func (e *Events) Watch(ctx context.Context, p domain.Principal, params WatchPara | |||
| 382 | 350 | log := zerowrap.FromCtx(ctx) | |
| 383 | 351 | log.Debug().Strs("topics", params.Topics).Bool("resume", params.ResumeAfter != "").Bool("gap", gap).Msg("watch started") | |
| 384 | 352 | if gap { | |
| 385 | - | if err := send(WatchEvent{Gap: true}); err != nil { | |
| 353 | + | if err := send(ports.WatchEvent{Gap: true}); err != nil { | |
| 386 | 354 | return err | |
| 387 | 355 | } | |
| 388 | 356 | } | |
| @@ -392,7 +360,7 @@ func (e *Events) Watch(ctx context.Context, p domain.Principal, params WatchPara | |||
| 392 | 360 | } | |
| 393 | 361 | batch, changed, oldest, lost, closed := e.since(next) | |
| 394 | 362 | if lost { | |
| 395 | - | if err := send(WatchEvent{Gap: true}); err != nil { | |
| 363 | + | if err := send(ports.WatchEvent{Gap: true}); err != nil { | |
| 396 | 364 | return err | |
| 397 | 365 | } | |
| 398 | 366 | next = oldest | |
| @@ -482,15 +450,15 @@ func (e *Events) since(next uint64) (batch []bufferedEvent, changed <-chan struc | |||
| 482 | 450 | } | |
| 483 | 451 | ||
| 484 | 452 | // deliver sends the event if the watcher follows its topic and may see it. | |
| 485 | - | func (e *Events) deliver(ctx context.Context, w *watch, be bufferedEvent, send func(WatchEvent) error) error { | |
| 453 | + | func (e *Events) deliver(ctx context.Context, w *watch, be bufferedEvent, send func(ports.WatchEvent) error) error { | |
| 486 | 454 | if err := e.stillAllowed(ctx, w); err != nil { | |
| 487 | 455 | return err | |
| 488 | 456 | } | |
| 489 | - | out := WatchEvent{ID: e.id(be.seq), Event: be.ev} | |
| 457 | + | out := ports.WatchEvent{ID: e.id(be.seq), Event: be.ev} | |
| 490 | 458 | switch ev := be.ev.(type) { | |
| 491 | 459 | case domain.EventGap: | |
| 492 | 460 | // The feeder lost events: tell every watcher. | |
| 493 | - | return send(WatchEvent{Gap: true}) | |
| 461 | + | return send(ports.WatchEvent{Gap: true}) | |
| 494 | 462 | case domain.RepoDeleted: | |
| 495 | 463 | // The repository is gone: use the visibility it had. | |
| 496 | 464 | if !w.wants(ev.Repo) || !canReadAs(w.p, ev.Repo, ev.Visibility) { | |
| @@ -523,7 +491,7 @@ func (e *Events) deliver(ctx context.Context, w *watch, be bufferedEvent, send f | |||
| 523 | 491 | // The exception is a repository that became private: the watchers who could | |
| 524 | 492 | // read it before are told once, with its name and its new visibility only, | |
| 525 | 493 | // so that what they show can be removed. | |
| 526 | - | func (e *Events) deliverRepo(ctx context.Context, w *watch, name domain.RepoName, withRepo bool, be bufferedEvent, out WatchEvent, send func(WatchEvent) error) error { | |
| 494 | + | func (e *Events) deliverRepo(ctx context.Context, w *watch, name domain.RepoName, withRepo bool, be bufferedEvent, out ports.WatchEvent, send func(ports.WatchEvent) error) error { | |
| 527 | 495 | if !w.wants(name) || !be.known { | |
| 528 | 496 | return nil | |
| 529 | 497 | } | |
| @@ -541,7 +509,7 @@ func (e *Events) deliverRepo(ctx context.Context, w *watch, name domain.RepoName | |||
| 541 | 509 | } | |
| 542 | 510 | if !canReadAs(w.p, name, be.vis) { | |
| 543 | 511 | if up, ok := be.ev.(domain.RepoUpdated); ok && canReadAs(w.p, name, up.Previous) { | |
| 544 | - | out.Repo = &RepoView{Repo: domain.Repo{Name: name, Visibility: up.Visibility}} | |
| 512 | + | out.Repo = &ports.RepoView{Repo: domain.Repo{Name: name, Visibility: up.Visibility}} | |
| 545 | 513 | return send(out) | |
| 546 | 514 | } | |
| 547 | 515 | return nil | |
M internal/app/events_test.go +60 -60
| @@ -17,8 +17,8 @@ import ( | |||
| 17 | 17 | "github.com/stretchr/testify/require" | |
| 18 | 18 | ||
| 19 | 19 | "bnema.dev/ermite/internal/app" | |
| 20 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |
| 21 | 20 | "bnema.dev/ermite/internal/domain" | |
| 21 | + | "bnema.dev/ermite/internal/ports" | |
| 22 | 22 | "bnema.dev/ermite/internal/ports/mocks" | |
| 23 | 23 | ) | |
| 24 | 24 | ||
| @@ -28,7 +28,7 @@ type eventRig struct { | |||
| 28 | 28 | meta *mocks.RepoMetaStore | |
| 29 | 29 | git *mocks.GitRepos | |
| 30 | 30 | feed chan domain.Event | |
| 31 | - | auth *appmocks.Revalidator | |
| 31 | + | auth *mocks.Revalidator | |
| 32 | 32 | revoked sync.Map // token IDs revoked by the test | |
| 33 | 33 | revalidations atomic.Int32 // calls to auth.Revalidate | |
| 34 | 34 | events *app.Events | |
| @@ -46,7 +46,7 @@ func newEventRigConfig(t *testing.T, cfg app.EventsConfig) *eventRig { | |||
| 46 | 46 | meta: mocks.NewRepoMetaStore(t), | |
| 47 | 47 | git: mocks.NewGitRepos(t), | |
| 48 | 48 | feed: make(chan domain.Event, 4096), | |
| 49 | - | auth: appmocks.NewRevalidator(t), | |
| 49 | + | auth: mocks.NewRevalidator(t), | |
| 50 | 50 | } | |
| 51 | 51 | // Tokens are valid until the test revokes them. | |
| 52 | 52 | r.auth.EXPECT().Revalidate(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, p domain.Principal) error { | |
| @@ -95,14 +95,14 @@ func (r *eventRig) push(n domain.RepoName, i int) { | |||
| 95 | 95 | ||
| 96 | 96 | // watcher is a running Watch. | |
| 97 | 97 | type watcher struct { | |
| 98 | - | got chan app.WatchEvent | |
| 98 | + | got chan ports.WatchEvent | |
| 99 | 99 | done chan error | |
| 100 | 100 | } | |
| 101 | 101 | ||
| 102 | - | func (r *eventRig) watch(ctx context.Context, p domain.Principal, params app.WatchParams) *watcher { | |
| 103 | - | w := &watcher{got: make(chan app.WatchEvent, 4096), done: make(chan error, 1)} | |
| 102 | + | func (r *eventRig) watch(ctx context.Context, p domain.Principal, params ports.WatchParams) *watcher { | |
| 103 | + | w := &watcher{got: make(chan ports.WatchEvent, 4096), done: make(chan error, 1)} | |
| 104 | 104 | go func() { | |
| 105 | - | w.done <- r.events.Watch(ctx, p, params, func(e app.WatchEvent) error { | |
| 105 | + | w.done <- r.events.Watch(ctx, p, params, func(e ports.WatchEvent) error { | |
| 106 | 106 | w.got <- e | |
| 107 | 107 | return nil | |
| 108 | 108 | }) | |
| @@ -110,7 +110,7 @@ func (r *eventRig) watch(ctx context.Context, p domain.Principal, params app.Wat | |||
| 110 | 110 | return w | |
| 111 | 111 | } | |
| 112 | 112 | ||
| 113 | - | func (w *watcher) next(t *testing.T) app.WatchEvent { | |
| 113 | + | func (w *watcher) next(t *testing.T) ports.WatchEvent { | |
| 114 | 114 | t.Helper() | |
| 115 | 115 | synctest.Wait() // everything the event can reach has run | |
| 116 | 116 | select { | |
| @@ -121,7 +121,7 @@ func (w *watcher) next(t *testing.T) app.WatchEvent { | |||
| 121 | 121 | default: | |
| 122 | 122 | t.Fatal("no event") | |
| 123 | 123 | } | |
| 124 | - | return app.WatchEvent{} | |
| 124 | + | return ports.WatchEvent{} | |
| 125 | 125 | } | |
| 126 | 126 | ||
| 127 | 127 | // sentinelOID marks the push events that only prove the ones before them were | |
| @@ -150,10 +150,10 @@ func TestWatchLiveAndFiltered(t *testing.T) { | |||
| 150 | 150 | ctx, cancel := context.WithCancel(context.Background()) | |
| 151 | 151 | defer cancel() | |
| 152 | 152 | ||
| 153 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | |
| 154 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{Topics: []string{"home"}}) | |
| 155 | - | scoped := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "other"), app.WatchParams{}) | |
| 156 | - | onlyPriv := r.watch(ctx, domain.Root(), app.WatchParams{Topics: []string{"repo:priv"}}) | |
| 153 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) | |
| 154 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{Topics: []string{"home"}}) | |
| 155 | + | scoped := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "other"), ports.WatchParams{}) | |
| 156 | + | onlyPriv := r.watch(ctx, domain.Root(), ports.WatchParams{Topics: []string{"repo:priv"}}) | |
| 157 | 157 | synctest.Wait() | |
| 158 | 158 | require.Equal(t, 4, r.events.Watchers()) | |
| 159 | 159 | ||
| @@ -191,7 +191,7 @@ func TestWatchRechecksAccessPerEvent(t *testing.T) { | |||
| 191 | 191 | }) | |
| 192 | 192 | ctx, cancel := context.WithCancel(context.Background()) | |
| 193 | 193 | defer cancel() | |
| 194 | - | w := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | |
| 194 | + | w := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) | |
| 195 | 195 | synctest.Wait() | |
| 196 | 196 | require.Equal(t, 1, r.events.Watchers()) | |
| 197 | 197 | ||
| @@ -217,7 +217,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||
| 217 | 217 | ctx, cancel := context.WithCancel(context.Background()) | |
| 218 | 218 | t.Cleanup(cancel) | |
| 219 | 219 | ||
| 220 | - | first := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 220 | + | first := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 221 | 221 | synctest.Wait() | |
| 222 | 222 | require.Equal(t, 1, r.events.Watchers()) | |
| 223 | 223 | // One at a time: this watcher must not fall behind the small ring. | |
| @@ -235,7 +235,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||
| 235 | 235 | r, _, ctx, ids := setup(t) | |
| 236 | 236 | // 20 events were taken, the buffer holds the last 8: ids[12] is the | |
| 237 | 237 | // oldest still present; ids[0] is long gone. | |
| 238 | - | w := r.watch(ctx, domain.Root(), app.WatchParams{ResumeAfter: ids[0]}) | |
| 238 | + | w := r.watch(ctx, domain.Root(), ports.WatchParams{ResumeAfter: ids[0]}) | |
| 239 | 239 | gap := w.next(t) | |
| 240 | 240 | assert.True(t, gap.Gap) | |
| 241 | 241 | assert.Empty(t, gap.ID) | |
| @@ -250,7 +250,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||
| 250 | 250 | synctest.Test(t, func(t *testing.T) { | |
| 251 | 251 | r, _, ctx, _ := setup(t) | |
| 252 | 252 | for _, id := range []string{"nonsense", "zz-1", "-", "0-0"} { | |
| 253 | - | w := r.watch(ctx, domain.Root(), app.WatchParams{ResumeAfter: id}) | |
| 253 | + | w := r.watch(ctx, domain.Root(), ports.WatchParams{ResumeAfter: id}) | |
| 254 | 254 | assert.True(t, w.next(t).Gap, id) | |
| 255 | 255 | } | |
| 256 | 256 | }) | |
| @@ -260,7 +260,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||
| 260 | 260 | t.Parallel() | |
| 261 | 261 | synctest.Test(t, func(t *testing.T) { | |
| 262 | 262 | r, _, ctx, _ := setup(t) | |
| 263 | - | w := r.watch(ctx, domain.Root(), app.WatchParams{ResumeAfter: "otherboot-999"}) | |
| 263 | + | w := r.watch(ctx, domain.Root(), ports.WatchParams{ResumeAfter: "otherboot-999"}) | |
| 264 | 264 | assert.True(t, w.next(t).Gap) | |
| 265 | 265 | }) | |
| 266 | 266 | }) | |
| @@ -269,7 +269,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||
| 269 | 269 | t.Parallel() | |
| 270 | 270 | synctest.Test(t, func(t *testing.T) { | |
| 271 | 271 | r, n, ctx, ids := setup(t) | |
| 272 | - | w := r.watch(ctx, domain.Root(), app.WatchParams{ResumeAfter: ids[16]}) | |
| 272 | + | w := r.watch(ctx, domain.Root(), ports.WatchParams{ResumeAfter: ids[16]}) | |
| 273 | 273 | for _, want := range ids[17:] { | |
| 274 | 274 | e := w.next(t) | |
| 275 | 275 | assert.False(t, e.Gap) | |
| @@ -287,7 +287,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||
| 287 | 287 | t.Parallel() | |
| 288 | 288 | synctest.Test(t, func(t *testing.T) { | |
| 289 | 289 | r, n, ctx, ids := setup(t) | |
| 290 | - | w := r.watch(ctx, domain.Root(), app.WatchParams{ResumeAfter: ids[len(ids)-1]}) | |
| 290 | + | w := r.watch(ctx, domain.Root(), ports.WatchParams{ResumeAfter: ids[len(ids)-1]}) | |
| 291 | 291 | r.push(n, 99) | |
| 292 | 292 | e := w.next(t) | |
| 293 | 293 | assert.False(t, e.Gap) | |
| @@ -302,7 +302,7 @@ func TestWatchTopicErrors(t *testing.T) { | |||
| 302 | 302 | r.repo("pub", domain.VisibilityPublic) | |
| 303 | 303 | r.repo("priv", domain.VisibilityPrivate) | |
| 304 | 304 | r.meta.EXPECT().Get(mock.Anything, name(t, "gone")).Return(domain.Repo{}, domain.ErrNotFound).Maybe() | |
| 305 | - | noop := func(app.WatchEvent) error { return nil } | |
| 305 | + | noop := func(ports.WatchEvent) error { return nil } | |
| 306 | 306 | ctx := context.Background() | |
| 307 | 307 | ||
| 308 | 308 | for topic, want := range map[string]error{ | |
| @@ -313,7 +313,7 @@ func TestWatchTopicErrors(t *testing.T) { | |||
| 313 | 313 | "repo:priv": domain.ErrNotFound, // hidden from anonymous | |
| 314 | 314 | "repo:pub:foo": domain.ErrInvalidName, | |
| 315 | 315 | } { | |
| 316 | - | err := r.events.Watch(ctx, domain.Anonymous(), app.WatchParams{Topics: []string{topic}}, noop) | |
| 316 | + | err := r.events.Watch(ctx, domain.Anonymous(), ports.WatchParams{Topics: []string{topic}}, noop) | |
| 317 | 317 | assert.ErrorIs(t, err, want, topic) | |
| 318 | 318 | } | |
| 319 | 319 | } | |
| @@ -325,7 +325,7 @@ func TestWatchEndsCleanly(t *testing.T) { | |||
| 325 | 325 | synctest.Test(t, func(t *testing.T) { | |
| 326 | 326 | r := newEventRig(t, 0) | |
| 327 | 327 | ctx, cancel := context.WithCancel(context.Background()) | |
| 328 | - | w := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 328 | + | w := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 329 | 329 | synctest.Wait() | |
| 330 | 330 | require.Equal(t, 1, r.events.Watchers()) | |
| 331 | 331 | cancel() | |
| @@ -344,7 +344,7 @@ func TestWatchEndsCleanly(t *testing.T) { | |||
| 344 | 344 | t.Parallel() | |
| 345 | 345 | synctest.Test(t, func(t *testing.T) { | |
| 346 | 346 | r := newEventRig(t, 0) | |
| 347 | - | w := r.watch(context.Background(), domain.Root(), app.WatchParams{}) | |
| 347 | + | w := r.watch(context.Background(), domain.Root(), ports.WatchParams{}) | |
| 348 | 348 | synctest.Wait() | |
| 349 | 349 | require.Equal(t, 1, r.events.Watchers()) | |
| 350 | 350 | r.events.Close(context.Background()) | |
| @@ -367,7 +367,7 @@ func TestWatchEndsCleanly(t *testing.T) { | |||
| 367 | 367 | boom := errors.New("client went away") | |
| 368 | 368 | done := make(chan error, 1) | |
| 369 | 369 | go func() { | |
| 370 | - | done <- r.events.Watch(context.Background(), domain.Root(), app.WatchParams{}, func(app.WatchEvent) error { return boom }) | |
| 370 | + | done <- r.events.Watch(context.Background(), domain.Root(), ports.WatchParams{}, func(ports.WatchEvent) error { return boom }) | |
| 371 | 371 | }() | |
| 372 | 372 | synctest.Wait() | |
| 373 | 373 | require.Equal(t, 1, r.events.Watchers()) | |
| @@ -386,12 +386,12 @@ func TestWatchSlowWatcherGetsAGap(t *testing.T) { | |||
| 386 | 386 | ||
| 387 | 387 | release := make(chan struct{}) | |
| 388 | 388 | var mu sync.Mutex | |
| 389 | - | var got []app.WatchEvent | |
| 389 | + | var got []ports.WatchEvent | |
| 390 | 390 | done := make(chan error, 1) | |
| 391 | 391 | blocked := make(chan struct{}) | |
| 392 | 392 | first := true | |
| 393 | 393 | go func() { | |
| 394 | - | done <- r.events.Watch(context.Background(), domain.Root(), app.WatchParams{}, func(e app.WatchEvent) error { | |
| 394 | + | done <- r.events.Watch(context.Background(), domain.Root(), ports.WatchParams{}, func(e ports.WatchEvent) error { | |
| 395 | 395 | if first { // block on the first event while the ring turns over | |
| 396 | 396 | first = false | |
| 397 | 397 | close(blocked) | |
| @@ -405,7 +405,7 @@ func TestWatchSlowWatcherGetsAGap(t *testing.T) { | |||
| 405 | 405 | }() | |
| 406 | 406 | // A second, fast watcher tells when the use case has taken every event: | |
| 407 | 407 | // it receives them in order. | |
| 408 | - | fast := r.watch(context.Background(), domain.Root(), app.WatchParams{}) | |
| 408 | + | fast := r.watch(context.Background(), domain.Root(), ports.WatchParams{}) | |
| 409 | 409 | synctest.Wait() | |
| 410 | 410 | require.Equal(t, 2, r.events.Watchers()) | |
| 411 | 411 | r.push(n, 0) | |
| @@ -444,8 +444,8 @@ func TestEventsRepoPayloads(t *testing.T) { | |||
| 444 | 444 | priv := r.repo("priv", domain.VisibilityPrivate) | |
| 445 | 445 | ctx, cancel := context.WithCancel(context.Background()) | |
| 446 | 446 | defer cancel() | |
| 447 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | |
| 448 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 447 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) | |
| 448 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 449 | 449 | synctest.Wait() | |
| 450 | 450 | require.Equal(t, 2, r.events.Watchers()) | |
| 451 | 451 | ||
| @@ -493,7 +493,7 @@ func TestWatchEndsWhenTheTokenIsRevoked(t *testing.T) { | |||
| 493 | 493 | ctx, cancel := context.WithCancel(context.Background()) | |
| 494 | 494 | defer cancel() | |
| 495 | 495 | ||
| 496 | - | w := r.watch(ctx, p, app.WatchParams{}) | |
| 496 | + | w := r.watch(ctx, p, ports.WatchParams{}) | |
| 497 | 497 | synctest.Wait() | |
| 498 | 498 | require.Equal(t, 1, r.events.Watchers()) | |
| 499 | 499 | r.push(pub, 1) | |
| @@ -523,7 +523,7 @@ func TestWatchEndsWhenTheTokenExpires(t *testing.T) { | |||
| 523 | 523 | pub := r.repo("pub", domain.VisibilityPublic) | |
| 524 | 524 | // The rig's clock stands at now: this token expired at now. | |
| 525 | 525 | p := tokenWith("tok", now) | |
| 526 | - | w := r.watch(context.Background(), p, app.WatchParams{}) | |
| 526 | + | w := r.watch(context.Background(), p, ports.WatchParams{}) | |
| 527 | 527 | r.push(pub, 1) // whether or not the watch had started, it ends unauthenticated | |
| 528 | 528 | synctest.Wait() | |
| 529 | 529 | select { | |
| @@ -542,7 +542,7 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||
| 542 | 542 | t.Parallel() | |
| 543 | 543 | synctest.Test(t, func(t *testing.T) { | |
| 544 | 544 | r := newEventRigConfig(t, app.EventsConfig{}) // the production default interval | |
| 545 | - | w := r.watch(context.Background(), tokenWith("tok", time.Time{}), app.WatchParams{}) | |
| 545 | + | w := r.watch(context.Background(), tokenWith("tok", time.Time{}), ports.WatchParams{}) | |
| 546 | 546 | synctest.Wait() | |
| 547 | 547 | require.Equal(t, 1, r.events.Watchers()) | |
| 548 | 548 | r.revoked.Store("tok", true) | |
| @@ -569,7 +569,7 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||
| 569 | 569 | synctest.Test(t, func(t *testing.T) { | |
| 570 | 570 | r := newEventRigConfig(t, app.EventsConfig{RevalidateEvery: time.Hour}) | |
| 571 | 571 | pub := r.repo("pub", domain.VisibilityPublic) | |
| 572 | - | w := r.watch(context.Background(), tokenWith("tok", time.Time{}), app.WatchParams{}) | |
| 572 | + | w := r.watch(context.Background(), tokenWith("tok", time.Time{}), ports.WatchParams{}) | |
| 573 | 573 | synctest.Wait() | |
| 574 | 574 | require.Equal(t, 1, r.events.Watchers()) | |
| 575 | 575 | for i := range 20 { | |
| @@ -592,8 +592,8 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||
| 592 | 592 | synctest.Test(t, func(t *testing.T) { | |
| 593 | 593 | r := newEventRigConfig(t, app.EventsConfig{RevalidateEvery: -1}) | |
| 594 | 594 | pub := r.repo("pub", domain.VisibilityPublic) | |
| 595 | - | a := r.watch(context.Background(), domain.Anonymous(), app.WatchParams{}) | |
| 596 | - | b := r.watch(context.Background(), domain.Root(), app.WatchParams{}) | |
| 595 | + | a := r.watch(context.Background(), domain.Anonymous(), ports.WatchParams{}) | |
| 596 | + | b := r.watch(context.Background(), domain.Root(), ports.WatchParams{}) | |
| 597 | 597 | synctest.Wait() | |
| 598 | 598 | require.Equal(t, 2, r.events.Watchers()) | |
| 599 | 599 | r.push(pub, 1) | |
| @@ -606,7 +606,7 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||
| 606 | 606 | ||
| 607 | 607 | func TestWatchLimits(t *testing.T) { | |
| 608 | 608 | t.Parallel() | |
| 609 | - | noop := func(app.WatchEvent) error { return nil } | |
| 609 | + | noop := func(ports.WatchEvent) error { return nil } | |
| 610 | 610 | ||
| 611 | 611 | t.Run("too many topics", func(t *testing.T) { | |
| 612 | 612 | t.Parallel() | |
| @@ -619,8 +619,8 @@ func TestWatchLimits(t *testing.T) { | |||
| 619 | 619 | } | |
| 620 | 620 | ctx, cancel := context.WithCancel(context.Background()) | |
| 621 | 621 | cancel() // returns at once once the topics are accepted | |
| 622 | - | assert.NoError(t, r.events.Watch(ctx, domain.Root(), app.WatchParams{Topics: ok}, noop)) | |
| 623 | - | err := r.events.Watch(context.Background(), domain.Root(), app.WatchParams{Topics: append(ok, "home")}, noop) | |
| 622 | + | assert.NoError(t, r.events.Watch(ctx, domain.Root(), ports.WatchParams{Topics: ok}, noop)) | |
| 623 | + | err := r.events.Watch(context.Background(), domain.Root(), ports.WatchParams{Topics: append(ok, "home")}, noop) | |
| 624 | 624 | assert.ErrorIs(t, err, domain.ErrInvalid) | |
| 625 | 625 | }) | |
| 626 | 626 | }) | |
| @@ -632,11 +632,11 @@ func TestWatchLimits(t *testing.T) { | |||
| 632 | 632 | ctx, cancel := context.WithCancel(context.Background()) | |
| 633 | 633 | defer cancel() | |
| 634 | 634 | for range app.MaxWatchers { | |
| 635 | - | r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 635 | + | r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 636 | 636 | } | |
| 637 | 637 | synctest.Wait() | |
| 638 | 638 | require.Equal(t, app.MaxWatchers, r.events.Watchers()) | |
| 639 | - | err := r.events.Watch(ctx, domain.Root(), app.WatchParams{}, noop) | |
| 639 | + | err := r.events.Watch(ctx, domain.Root(), ports.WatchParams{}, noop) | |
| 640 | 640 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | |
| 641 | 641 | assert.Equal(t, app.MaxWatchers, r.events.Watchers(), "a refused watch is not counted") | |
| 642 | 642 | ||
| @@ -645,7 +645,7 @@ func TestWatchLimits(t *testing.T) { | |||
| 645 | 645 | require.Equal(t, 0, r.events.Watchers()) | |
| 646 | 646 | again, stop := context.WithCancel(context.Background()) | |
| 647 | 647 | stop() | |
| 648 | - | assert.NoError(t, r.events.Watch(again, domain.Root(), app.WatchParams{}, noop)) | |
| 648 | + | assert.NoError(t, r.events.Watch(again, domain.Root(), ports.WatchParams{}, noop)) | |
| 649 | 649 | }) | |
| 650 | 650 | }) | |
| 651 | 651 | ||
| @@ -656,17 +656,17 @@ func TestWatchLimits(t *testing.T) { | |||
| 656 | 656 | ctx, cancel := context.WithCancel(context.Background()) | |
| 657 | 657 | defer cancel() | |
| 658 | 658 | for range app.MaxWatchersPerClient { | |
| 659 | - | r.watch(ctx, domain.Root(), app.WatchParams{Client: "198.51.100.1"}) | |
| 659 | + | r.watch(ctx, domain.Root(), ports.WatchParams{Client: "198.51.100.1"}) | |
| 660 | 660 | } | |
| 661 | 661 | synctest.Wait() | |
| 662 | 662 | require.Equal(t, app.MaxWatchersPerClient, r.events.Watchers()) | |
| 663 | 663 | ||
| 664 | - | err := r.events.Watch(ctx, domain.Root(), app.WatchParams{Client: "198.51.100.1"}, noop) | |
| 664 | + | err := r.events.Watch(ctx, domain.Root(), ports.WatchParams{Client: "198.51.100.1"}, noop) | |
| 665 | 665 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | |
| 666 | 666 | ||
| 667 | 667 | // Another client, and callers in process, are not affected. | |
| 668 | - | r.watch(ctx, domain.Root(), app.WatchParams{Client: "198.51.100.2"}) | |
| 669 | - | r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 668 | + | r.watch(ctx, domain.Root(), ports.WatchParams{Client: "198.51.100.2"}) | |
| 669 | + | r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 670 | 670 | synctest.Wait() | |
| 671 | 671 | require.Equal(t, app.MaxWatchersPerClient+2, r.events.Watchers()) | |
| 672 | 672 | ||
| @@ -675,7 +675,7 @@ func TestWatchLimits(t *testing.T) { | |||
| 675 | 675 | require.Equal(t, 0, r.events.Watchers()) | |
| 676 | 676 | again, stop := context.WithCancel(context.Background()) | |
| 677 | 677 | stop() | |
| 678 | - | assert.NoError(t, r.events.Watch(again, domain.Root(), app.WatchParams{Client: "198.51.100.1"}, noop), "the slots were released") | |
| 678 | + | assert.NoError(t, r.events.Watch(again, domain.Root(), ports.WatchParams{Client: "198.51.100.1"}, noop), "the slots were released") | |
| 679 | 679 | }) | |
| 680 | 680 | }) | |
| 681 | 681 | } | |
| @@ -712,7 +712,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||
| 712 | 712 | defer cancel() | |
| 713 | 713 | r := newEventRig(t, 0) | |
| 714 | 714 | l, n := r.liveRepo("secret", domain.VisibilityPrivate, now) | |
| 715 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 715 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 716 | 716 | synctest.Wait() | |
| 717 | 717 | require.Equal(t, 1, r.events.Watchers()) | |
| 718 | 718 | r.push(n, 1) | |
| @@ -728,7 +728,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||
| 728 | 728 | // An anonymous caller that resumes with an id nobody issued gets what | |
| 729 | 729 | // is buffered, filtered: the public update and the public push, not the | |
| 730 | 730 | // pushes of the private era. | |
| 731 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{ResumeAfter: "bogus"}) | |
| 731 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{ResumeAfter: "bogus"}) | |
| 732 | 732 | assert.True(t, anon.next(t).Gap) | |
| 733 | 733 | upd := anon.next(t) | |
| 734 | 734 | require.IsType(t, domain.RepoUpdated{}, upd.Event) | |
| @@ -747,7 +747,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||
| 747 | 747 | r := newEventRig(t, 0) | |
| 748 | 748 | first := now.Add(-time.Hour) | |
| 749 | 749 | l, n := r.liveRepo("again", domain.VisibilityPublic, first) | |
| 750 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 750 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 751 | 751 | synctest.Wait() | |
| 752 | 752 | require.Equal(t, 1, r.events.Watchers()) | |
| 753 | 753 | r.push(n, 1) | |
| @@ -757,7 +757,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||
| 757 | 757 | r.push(n, 2) | |
| 758 | 758 | root.next(t) | |
| 759 | 759 | ||
| 760 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{ResumeAfter: "bogus"}) | |
| 760 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{ResumeAfter: "bogus"}) | |
| 761 | 761 | assert.True(t, anon.next(t).Gap) | |
| 762 | 762 | e := anon.next(t) | |
| 763 | 763 | require.IsType(t, domain.PushEvent{}, e.Event) | |
| @@ -773,10 +773,10 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||
| 773 | 773 | defer cancel() | |
| 774 | 774 | r := newEventRig(t, 0) | |
| 775 | 775 | l, n := r.liveRepo("hide", domain.VisibilityPublic, now) | |
| 776 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | |
| 777 | - | reader := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "hide"), app.WatchParams{}) | |
| 778 | - | other := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "elsewhere"), app.WatchParams{}) | |
| 779 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 776 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) | |
| 777 | + | reader := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "hide"), ports.WatchParams{}) | |
| 778 | + | other := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "elsewhere"), ports.WatchParams{}) | |
| 779 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 780 | 780 | synctest.Wait() | |
| 781 | 781 | require.Equal(t, 4, r.events.Watchers()) | |
| 782 | 782 | ||
| @@ -809,7 +809,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||
| 809 | 809 | defer cancel() | |
| 810 | 810 | r := newEventRig(t, 0) | |
| 811 | 811 | _, n := r.liveRepo("closed", domain.VisibilityPrivate, now) | |
| 812 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | |
| 812 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) | |
| 813 | 813 | synctest.Wait() | |
| 814 | 814 | require.Equal(t, 1, r.events.Watchers()) | |
| 815 | 815 | r.feed <- domain.RepoUpdated{Repo: n, At: now, Visibility: domain.VisibilityPrivate, Previous: domain.VisibilityPrivate, CreatedAt: now} | |
| @@ -842,8 +842,8 @@ func TestPushEventsKeepTheirSnapshot(t *testing.T) { | |||
| 842 | 842 | defer cancel() | |
| 843 | 843 | r := newEventRig(t, 0) | |
| 844 | 844 | l, n := r.liveRepo("secret", domain.VisibilityPrivate, now) | |
| 845 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | |
| 846 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 845 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) | |
| 846 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 847 | 847 | synctest.Wait() | |
| 848 | 848 | require.Equal(t, 2, r.events.Watchers()) | |
| 849 | 849 | ||
| @@ -859,7 +859,7 @@ func TestPushEventsKeepTheirSnapshot(t *testing.T) { | |||
| 859 | 859 | ||
| 860 | 860 | anon.quiet(t, r, r.repo("open", domain.VisibilityPublic)) | |
| 861 | 861 | ||
| 862 | - | late := r.watch(ctx, domain.Anonymous(), app.WatchParams{ResumeAfter: "bogus"}) | |
| 862 | + | late := r.watch(ctx, domain.Anonymous(), ports.WatchParams{ResumeAfter: "bogus"}) | |
| 863 | 863 | assert.True(t, late.next(t).Gap) | |
| 864 | 864 | late.quiet(t, r, r.repo("open2", domain.VisibilityPublic)) | |
| 865 | 865 | }) | |
| @@ -873,7 +873,7 @@ func TestPushEventsKeepTheirSnapshot(t *testing.T) { | |||
| 873 | 873 | defer cancel() | |
| 874 | 874 | r := newEventRig(t, 0) | |
| 875 | 875 | n := r.repo("ghost", domain.VisibilityPublic) | |
| 876 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | |
| 876 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) | |
| 877 | 877 | synctest.Wait() | |
| 878 | 878 | require.Equal(t, 1, r.events.Watchers()) | |
| 879 | 879 | r.feed <- domain.PushEvent{Repo: n, Visibility: domain.VisibilityPublic, At: now} | |
M internal/app/maintenance.go +2 -0
| @@ -38,6 +38,8 @@ type Maintainer struct { | |||
| 38 | 38 | wg sync.WaitGroup | |
| 39 | 39 | } | |
| 40 | 40 | ||
| 41 | + | var _ ports.MaintenanceScheduler = (*Maintainer)(nil) | |
| 42 | + | ||
| 41 | 43 | type maintEntry struct { | |
| 42 | 44 | timer *time.Timer // pending run, nil while running or idle | |
| 43 | 45 | running bool | |
M internal/app/mergerequests.go +29 -102
| @@ -47,12 +47,14 @@ type MergeRequests struct { | |||
| 47 | 47 | committer domain.Identity | |
| 48 | 48 | bus ports.EventBus | |
| 49 | 49 | clock ports.Clock | |
| 50 | - | maint MaintenanceScheduler | |
| 50 | + | maint ports.MaintenanceScheduler | |
| 51 | 51 | ||
| 52 | 52 | mu sync.Mutex | |
| 53 | 53 | locks map[domain.RepoName]chan struct{} | |
| 54 | 54 | } | |
| 55 | 55 | ||
| 56 | + | var _ ports.MergeRequestService = (*MergeRequests)(nil) | |
| 57 | + | ||
| 56 | 58 | // MergeRequestsConfig holds what the merge request use cases need. Every field | |
| 57 | 59 | // is required. | |
| 58 | 60 | type MergeRequestsConfig struct { | |
| @@ -68,7 +70,7 @@ type MergeRequestsConfig struct { | |||
| 68 | 70 | Bus ports.EventBus | |
| 69 | 71 | Clock ports.Clock | |
| 70 | 72 | // Maint queues the maintenance that follows a merge, as it does a push. | |
| 71 | - | Maint MaintenanceScheduler | |
| 73 | + | Maint ports.MaintenanceScheduler | |
| 72 | 74 | } | |
| 73 | 75 | ||
| 74 | 76 | // NewMergeRequests builds the merge request use cases. | |
| @@ -161,20 +163,12 @@ func (m *MergeRequests) branchOrZero(ctx context.Context, repo domain.RepoName, | |||
| 161 | 163 | return id, err | |
| 162 | 164 | } | |
| 163 | 165 | ||
| 164 | - | // CreateMergeRequestParams describes the merge request to open. | |
| 165 | - | type CreateMergeRequestParams struct { | |
| 166 | - | Title string | |
| 167 | - | Description string | |
| 168 | - | // Source is required; Target defaults to the default branch. | |
| 169 | - | Source, Target string | |
| 170 | - | } | |
| 171 | - | ||
| 172 | 166 | // Create opens a merge request and publishes MergeRequestOpened. The principal | |
| 173 | 167 | // needs mr:write. A request that breaks a rule of ADR 0017 (the texts, a | |
| 174 | 168 | // branch that does not exist, source and target the same) is rejected whole | |
| 175 | 169 | // with an *domain.InvalidFieldsError naming the fields. An open request with | |
| 176 | 170 | // the same source and target gives domain.ErrAlreadyExists. | |
| 177 | - | func (m *MergeRequests) Create(ctx context.Context, p domain.Principal, name domain.RepoName, params CreateMergeRequestParams) (domain.MergeRequest, error) { | |
| 171 | + | func (m *MergeRequests) Create(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.CreateMergeRequestParams) (domain.MergeRequest, error) { | |
| 178 | 172 | repo, err := m.writable(ctx, p, name, domain.ScopeMRWrite) | |
| 179 | 173 | if err != nil { | |
| 180 | 174 | return domain.MergeRequest{}, err | |
| @@ -239,7 +233,7 @@ func (m *MergeRequests) Create(ctx context.Context, p domain.Principal, name dom | |||
| 239 | 233 | // Only a branch that does not exist is a violation. Any other failure to read | |
| 240 | 234 | // Git is returned as an error, so that it is logged and masked, not shown in | |
| 241 | 235 | // the field violations. | |
| 242 | - | func (m *MergeRequests) checkBranches(ctx context.Context, name domain.RepoName, params CreateMergeRequestParams, v *domain.Violations) (source, target string, err error) { | |
| 236 | + | func (m *MergeRequests) checkBranches(ctx context.Context, name domain.RepoName, params ports.CreateMergeRequestParams, v *domain.Violations) (source, target string, err error) { | |
| 243 | 237 | source, target = params.Source, params.Target | |
| 244 | 238 | if source == "" { | |
| 245 | 239 | v.Add("source_branch", "is required") | |
| @@ -279,44 +273,27 @@ func (m *MergeRequests) checkBranches(ctx context.Context, name domain.RepoName, | |||
| 279 | 273 | return source, target, nil | |
| 280 | 274 | } | |
| 281 | 275 | ||
| 282 | - | // ListMergeRequestsParams selects a page of merge requests. | |
| 283 | - | type ListMergeRequestsParams struct { | |
| 284 | - | // State restricts the result; empty means every state. | |
| 285 | - | State domain.MRState | |
| 286 | - | // PageSize is 0 for the default, and lowered to MaxPageSize. | |
| 287 | - | PageSize int | |
| 288 | - | // PageToken is the NextPageToken of the previous page, or empty. | |
| 289 | - | PageToken string | |
| 290 | - | } | |
| 291 | - | ||
| 292 | - | // MergeRequestPage is a page of merge requests, highest number first. | |
| 293 | - | type MergeRequestPage struct { | |
| 294 | - | MergeRequests []domain.MergeRequest | |
| 295 | - | // NextPageToken is empty on the last page. | |
| 296 | - | NextPageToken string | |
| 297 | - | } | |
| 298 | - | ||
| 299 | 276 | // List returns a page of the merge requests of a repository, highest number | |
| 300 | 277 | // first. The open ones carry the head of their source branch. The page token | |
| 301 | 278 | // names the last number of the previous page, so requests created between two | |
| 302 | 279 | // pages never shift the others. | |
| 303 | - | func (m *MergeRequests) List(ctx context.Context, p domain.Principal, name domain.RepoName, params ListMergeRequestsParams) (MergeRequestPage, error) { | |
| 280 | + | func (m *MergeRequests) List(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.ListMergeRequestsParams) (ports.MergeRequestPage, error) { | |
| 304 | 281 | size, err := pageSize(params.PageSize) | |
| 305 | 282 | if err != nil { | |
| 306 | - | return MergeRequestPage{}, err | |
| 283 | + | return ports.MergeRequestPage{}, err | |
| 307 | 284 | } | |
| 308 | 285 | after, err := decodeMRToken(params.PageToken) | |
| 309 | 286 | if err != nil { | |
| 310 | - | return MergeRequestPage{}, err | |
| 287 | + | return ports.MergeRequestPage{}, err | |
| 311 | 288 | } | |
| 312 | 289 | if _, err := m.readable(ctx, p, name); err != nil { | |
| 313 | - | return MergeRequestPage{}, err | |
| 290 | + | return ports.MergeRequestPage{}, err | |
| 314 | 291 | } | |
| 315 | 292 | all, err := m.store.List(ctx, name) | |
| 316 | 293 | if err != nil { | |
| 317 | - | return MergeRequestPage{}, fmt.Errorf("list merge requests of %q: %w", name, err) | |
| 294 | + | return ports.MergeRequestPage{}, fmt.Errorf("list merge requests of %q: %w", name, err) | |
| 318 | 295 | } | |
| 319 | - | var page MergeRequestPage | |
| 296 | + | var page ports.MergeRequestPage | |
| 320 | 297 | page.MergeRequests, page.NextPageToken = pageAfter(all, size, | |
| 321 | 298 | func(mr domain.MergeRequest) bool { | |
| 322 | 299 | return (params.State == "" || mr.State == params.State) && (after == 0 || mr.Number < after) | |
| @@ -324,7 +301,7 @@ func (m *MergeRequests) List(ctx context.Context, p domain.Principal, name domai | |||
| 324 | 301 | encodeMRToken) | |
| 325 | 302 | for i, mr := range page.MergeRequests { | |
| 326 | 303 | if page.MergeRequests[i], err = m.withHead(ctx, mr); err != nil { | |
| 327 | - | return MergeRequestPage{}, err | |
| 304 | + | return ports.MergeRequestPage{}, err | |
| 328 | 305 | } | |
| 329 | 306 | } | |
| 330 | 307 | return page, nil | |
| @@ -361,27 +338,6 @@ func (m *MergeRequests) get(ctx context.Context, p domain.Principal, name domain | |||
| 361 | 338 | return repo, mr, nil | |
| 362 | 339 | } | |
| 363 | 340 | ||
| 364 | - | // MergeRequestDetail is a merge request with its review data. | |
| 365 | - | type MergeRequestDetail struct { | |
| 366 | - | MergeRequest domain.MergeRequest | |
| 367 | - | // Commits are the commits of the head that the target lacks, newest | |
| 368 | - | // first, at most MaxMergeRequestCommits. | |
| 369 | - | Commits []domain.Commit | |
| 370 | - | CommitsTruncated bool | |
| 371 | - | // DiffBaseID is the commit the diff compares from; zero when the source | |
| 372 | - | // branch is gone, then the diff is empty. | |
| 373 | - | DiffBaseID domain.ObjectID | |
| 374 | - | Stats domain.DiffStats | |
| 375 | - | Diff domain.Diff | |
| 376 | - | // Comments are the comments, oldest first. | |
| 377 | - | Comments []domain.Comment | |
| 378 | - | // LastReadID is the head recorded by MarkRead; zero when none. | |
| 379 | - | LastReadID domain.ObjectID | |
| 380 | - | // LastReadLost tells that since-last-read was asked for, a head was | |
| 381 | - | // recorded, but that commit is gone: the diff is against the target. | |
| 382 | - | LastReadLost bool | |
| 383 | - | } | |
| 384 | - | ||
| 385 | 341 | // Get returns a merge request with its commits, its diff, its comments and the | |
| 386 | 342 | // read position. The diff compares the merge base of the target and the head | |
| 387 | 343 | // with the head ("target...head"), within domain.DefaultDiffLimits. With | |
| @@ -390,25 +346,25 @@ type MergeRequestDetail struct { | |||
| 390 | 346 | // still exists; when none was recorded the diff is the default one, and when | |
| 391 | 347 | // the recorded commit is gone too, with LastReadLost set. A merged or closed | |
| 392 | 348 | // request keeps the head and the base it had. | |
| 393 | - | func (m *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (MergeRequestDetail, error) { | |
| 349 | + | func (m *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (ports.MergeRequestDetail, error) { | |
| 394 | 350 | _, mr, err := m.get(ctx, p, name, number) | |
| 395 | 351 | if err != nil { | |
| 396 | - | return MergeRequestDetail{}, err | |
| 352 | + | return ports.MergeRequestDetail{}, err | |
| 397 | 353 | } | |
| 398 | 354 | if mr, err = m.withHead(ctx, mr); err != nil { | |
| 399 | - | return MergeRequestDetail{}, err | |
| 355 | + | return ports.MergeRequestDetail{}, err | |
| 400 | 356 | } | |
| 401 | - | d := MergeRequestDetail{MergeRequest: mr} | |
| 357 | + | d := ports.MergeRequestDetail{MergeRequest: mr} | |
| 402 | 358 | if d.Comments, err = m.store.ListComments(ctx, name, number); err != nil { | |
| 403 | - | return MergeRequestDetail{}, fmt.Errorf("list comments of !%d in %q: %w", number, name, err) | |
| 359 | + | return ports.MergeRequestDetail{}, fmt.Errorf("list comments of !%d in %q: %w", number, name, err) | |
| 404 | 360 | } | |
| 405 | 361 | if d.LastReadID, err = m.store.GetRead(ctx, name, number); err != nil { | |
| 406 | - | return MergeRequestDetail{}, err | |
| 362 | + | return ports.MergeRequestDetail{}, err | |
| 407 | 363 | } | |
| 408 | 364 | ||
| 409 | 365 | exclude, base, err := m.rangeOf(ctx, mr) | |
| 410 | 366 | if err != nil { | |
| 411 | - | return MergeRequestDetail{}, err | |
| 367 | + | return ports.MergeRequestDetail{}, err | |
| 412 | 368 | } | |
| 413 | 369 | head := mr.HeadID | |
| 414 | 370 | if head.IsZero() { | |
| @@ -419,18 +375,18 @@ func (m *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain | |||
| 419 | 375 | // source branch; once it is deleted, gc may prune them. | |
| 420 | 376 | switch ok, err := m.git.HasCommit(ctx, name, head); { | |
| 421 | 377 | case err != nil: | |
| 422 | - | return MergeRequestDetail{}, err | |
| 378 | + | return ports.MergeRequestDetail{}, err | |
| 423 | 379 | case !ok: | |
| 424 | 380 | return d, nil // the reviewed commits are gone: no commits, no diff | |
| 425 | 381 | } | |
| 426 | 382 | } | |
| 427 | 383 | if d.Commits, d.CommitsTruncated, err = m.git.ListRange(ctx, name, exclude, head, MaxMergeRequestCommits); err != nil { | |
| 428 | - | return MergeRequestDetail{}, err | |
| 384 | + | return ports.MergeRequestDetail{}, err | |
| 429 | 385 | } | |
| 430 | 386 | if sinceLastRead && !d.LastReadID.IsZero() { | |
| 431 | 387 | switch ok, err := m.git.HasCommit(ctx, name, d.LastReadID); { | |
| 432 | 388 | case err != nil: | |
| 433 | - | return MergeRequestDetail{}, err | |
| 389 | + | return ports.MergeRequestDetail{}, err | |
| 434 | 390 | case ok: | |
| 435 | 391 | base = d.LastReadID | |
| 436 | 392 | default: | |
| @@ -442,7 +398,7 @@ func (m *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain | |||
| 442 | 398 | } | |
| 443 | 399 | d.DiffBaseID = base | |
| 444 | 400 | if d.Stats, d.Diff, err = m.git.DiffCommits(ctx, name, base, head, domain.DefaultDiffLimits()); err != nil { | |
| 445 | - | return MergeRequestDetail{}, err | |
| 401 | + | return ports.MergeRequestDetail{}, err | |
| 446 | 402 | } | |
| 447 | 403 | return d, nil | |
| 448 | 404 | } | |
| @@ -470,23 +426,13 @@ func (m *MergeRequests) rangeOf(ctx context.Context, mr domain.MergeRequest) (ex | |||
| 470 | 426 | return tip, base, err | |
| 471 | 427 | } | |
| 472 | 428 | ||
| 473 | - | // AddCommentParams describes the comment to add. | |
| 474 | - | type AddCommentParams struct { | |
| 475 | - | // Path, Line and Side designate a line of the diff; all empty for a | |
| 476 | - | // general comment. | |
| 477 | - | Path string | |
| 478 | - | Line int | |
| 479 | - | Side domain.DiffSide | |
| 480 | - | Text string | |
| 481 | - | } | |
| 482 | - | ||
| 483 | 429 | // AddComment adds a comment and publishes CommentAdded. The principal needs | |
| 484 | 430 | // mr:write. The text must follow the rules of ADR 0017 and not be blank; a | |
| 485 | 431 | // comment on a line must name a line of the current diff of the request (see | |
| 486 | 432 | // domain.Diff.HasLine), else the call fails with domain.ErrInvalid. A request | |
| 487 | 433 | // that is not open gives domain.ErrPreconditionFailed, and one that already | |
| 488 | 434 | // holds MaxCommentsPerMergeRequest comments domain.ErrResourceExhausted. | |
| 489 | - | func (m *MergeRequests) AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params AddCommentParams) (domain.Comment, error) { | |
| 435 | + | func (m *MergeRequests) AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.AddCommentParams) (domain.Comment, error) { | |
| 490 | 436 | repo, err := m.writable(ctx, p, name, domain.ScopeMRWrite) | |
| 491 | 437 | if err != nil { | |
| 492 | 438 | return domain.Comment{}, err | |
| @@ -567,7 +513,7 @@ func (m *MergeRequests) AddComment(ctx context.Context, p domain.Principal, name | |||
| 567 | 513 | ||
| 568 | 514 | // checkLine verifies that a comment designates a line of the current diff of | |
| 569 | 515 | // the request. | |
| 570 | - | func (m *MergeRequests) checkLine(ctx context.Context, mr domain.MergeRequest, params AddCommentParams) error { | |
| 516 | + | func (m *MergeRequests) checkLine(ctx context.Context, mr domain.MergeRequest, params ports.AddCommentParams) error { | |
| 571 | 517 | var v domain.Violations | |
| 572 | 518 | _, base, err := m.rangeOf(ctx, mr) | |
| 573 | 519 | if err != nil { | |
| @@ -706,25 +652,6 @@ func (m *MergeRequests) MarkRead(ctx context.Context, p domain.Principal, name d | |||
| 706 | 652 | return head, nil | |
| 707 | 653 | } | |
| 708 | 654 | ||
| 709 | - | // MergeParams describes the merge to perform. | |
| 710 | - | type MergeParams struct { | |
| 711 | - | // Mode defaults to fast-forward. | |
| 712 | - | Mode domain.MergeMode | |
| 713 | - | // HeadID is the commit the caller reviewed; the source branch must still | |
| 714 | - | // point to it. | |
| 715 | - | HeadID domain.ObjectID | |
| 716 | - | // DeleteSource deletes the source branch after the merge. | |
| 717 | - | DeleteSource bool | |
| 718 | - | } | |
| 719 | - | ||
| 720 | - | // MergeResult is a merged request and what happened to its source branch. | |
| 721 | - | type MergeResult struct { | |
| 722 | - | domain.MergeRequest | |
| 723 | - | // SourceDeleted is true when DeleteSource was asked and the branch is | |
| 724 | - | // gone. | |
| 725 | - | SourceDeleted bool | |
| 726 | - | } | |
| 727 | - | ||
| 728 | 655 | // Merge merges an open merge request, publishes MergeRequestMerged then a | |
| 729 | 656 | // PushEvent for the target branch, and returns the merged request. The | |
| 730 | 657 | // principal needs mr:merge. Merges of one repository run one at a time. | |
| @@ -748,12 +675,12 @@ type MergeResult struct { | |||
| 748 | 675 | // request. After the merge the source is deleted if it still points to the | |
| 749 | 676 | // head; the PushEvent then carries the deletion too. A failed deletion is | |
| 750 | 677 | // logged and leaves the branch: the merge stands and SourceDeleted is false. | |
| 751 | - | func (m *MergeRequests) Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params MergeParams) (MergeResult, error) { | |
| 678 | + | func (m *MergeRequests) Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.MergeParams) (ports.MergeResult, error) { | |
| 752 | 679 | mr, deleted, err := m.merge(ctx, p, name, number, params) | |
| 753 | - | return MergeResult{MergeRequest: mr, SourceDeleted: deleted}, err | |
| 680 | + | return ports.MergeResult{MergeRequest: mr, SourceDeleted: deleted}, err | |
| 754 | 681 | } | |
| 755 | 682 | ||
| 756 | - | func (m *MergeRequests) merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params MergeParams) (domain.MergeRequest, bool, error) { | |
| 683 | + | func (m *MergeRequests) merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.MergeParams) (domain.MergeRequest, bool, error) { | |
| 757 | 684 | repo, err := m.writable(ctx, p, name, domain.ScopeMRMerge) | |
| 758 | 685 | if err != nil { | |
| 759 | 686 | return domain.MergeRequest{}, false, err | |
M internal/app/mergerequests_delete_test.go +13 -12
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | "bnema.dev/ermite/internal/adapters/gitcli" | |
| 13 | 13 | "bnema.dev/ermite/internal/app" | |
| 14 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 15 | 16 | ) | |
| 16 | 17 | ||
| 17 | 18 | // A merge can delete its source branch; the push event carries both refs. | |
| @@ -26,7 +27,7 @@ func TestMergeDeletesTheSourceBranch(t *testing.T) { | |||
| 26 | 27 | mr := r.open("feat") | |
| 27 | 28 | r.drain() | |
| 28 | 29 | ||
| 29 | - | res, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{Mode: mode, HeadID: head, DeleteSource: true}) | |
| 30 | + | res, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{Mode: mode, HeadID: head, DeleteSource: true}) | |
| 30 | 31 | require.NoError(t, err) | |
| 31 | 32 | assert.True(t, res.SourceDeleted) | |
| 32 | 33 | assert.Equal(t, domain.MRStateMerged, res.State) | |
| @@ -54,7 +55,7 @@ func TestMergeDeletesTheSourceBranch(t *testing.T) { | |||
| 54 | 55 | r.seed() | |
| 55 | 56 | head := r.feature("feat") | |
| 56 | 57 | mr := r.open("feat") | |
| 57 | - | res, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 58 | + | res, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 58 | 59 | require.NoError(t, err) | |
| 59 | 60 | assert.False(t, res.SourceDeleted) | |
| 60 | 61 | assert.Equal(t, head, r.branchHead("feat")) | |
| @@ -73,10 +74,10 @@ func TestMergeRefusesToDeleteANeededBranch(t *testing.T) { | |||
| 73 | 74 | r.sh("checkout", "-q", "-B", "release", "main") | |
| 74 | 75 | r.push("release") | |
| 75 | 76 | mr := r.open("feat") | |
| 76 | - | _, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "to release", Source: "feat", Target: "release"}) | |
| 77 | + | _, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "to release", Source: "feat", Target: "release"}) | |
| 77 | 78 | require.NoError(t, err) | |
| 78 | 79 | ||
| 79 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, DeleteSource: true}) | |
| 80 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, DeleteSource: true}) | |
| 80 | 81 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 81 | 82 | assert.Contains(t, err.Error(), "!2 still uses") | |
| 82 | 83 | assert.Equal(t, main, r.branchHead("main"), "not merged") | |
| @@ -95,9 +96,9 @@ func TestMergeRefusesToDeleteANeededBranch(t *testing.T) { | |||
| 95 | 96 | r.sh("checkout", "-q", "-B", "sub", "feat") | |
| 96 | 97 | r.commit(author, "d.txt", "dee\n", "add d") | |
| 97 | 98 | r.push("sub") | |
| 98 | - | _, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "stacked", Source: "sub", Target: "feat"}) | |
| 99 | + | _, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "stacked", Source: "sub", Target: "feat"}) | |
| 99 | 100 | require.NoError(t, err) | |
| 100 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, DeleteSource: true}) | |
| 101 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, DeleteSource: true}) | |
| 101 | 102 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 102 | 103 | assert.Equal(t, head, r.branchHead("feat")) | |
| 103 | 104 | }) | |
| @@ -109,9 +110,9 @@ func TestMergeRefusesToDeleteANeededBranch(t *testing.T) { | |||
| 109 | 110 | r.sh("checkout", "-q", "-B", "old", "main~1") | |
| 110 | 111 | r.push("old") | |
| 111 | 112 | old := r.branchHead("old") | |
| 112 | - | mr, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "back", Source: "main", Target: "old"}) | |
| 113 | + | mr, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "back", Source: "main", Target: "old"}) | |
| 113 | 114 | require.NoError(t, err) | |
| 114 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: main, DeleteSource: true}) | |
| 115 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: main, DeleteSource: true}) | |
| 115 | 116 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 116 | 117 | assert.Contains(t, err.Error(), "default branch") | |
| 117 | 118 | assert.Equal(t, old, r.branchHead("old"), "not merged") | |
| @@ -127,7 +128,7 @@ func TestSquashMergedRequestReadsAfterItsCommitsArePruned(t *testing.T) { | |||
| 127 | 128 | r.seed() | |
| 128 | 129 | head := r.feature("feat") | |
| 129 | 130 | mr := r.open("feat") | |
| 130 | - | res, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{Mode: domain.MergeModeSquash, HeadID: head, DeleteSource: true}) | |
| 131 | + | res, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{Mode: domain.MergeModeSquash, HeadID: head, DeleteSource: true}) | |
| 131 | 132 | require.NoError(t, err) | |
| 132 | 133 | require.True(t, res.SourceDeleted) | |
| 133 | 134 | ||
| @@ -154,9 +155,9 @@ func TestCreateAfterAMergeDeletedTheBranch(t *testing.T) { | |||
| 154 | 155 | r.seed() | |
| 155 | 156 | head := r.feature("feat") | |
| 156 | 157 | mr := r.open("feat") | |
| 157 | - | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, DeleteSource: true}) | |
| 158 | + | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, DeleteSource: true}) | |
| 158 | 159 | require.NoError(t, err) | |
| 159 | - | _, err = r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "late", Source: "feat"}) | |
| 160 | + | _, err = r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "late", Source: "feat"}) | |
| 160 | 161 | require.ErrorIs(t, err, domain.ErrInvalid) | |
| 161 | 162 | assert.Contains(t, fieldsOf(t, err), "source_branch") | |
| 162 | 163 | } | |
| @@ -189,7 +190,7 @@ func TestMergeKeepsASourceThatMovedAfterTheMerge(t *testing.T) { | |||
| 189 | 190 | }) | |
| 190 | 191 | r.drain() | |
| 191 | 192 | ||
| 192 | - | res, err := mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, DeleteSource: true}) | |
| 193 | + | res, err := mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, DeleteSource: true}) | |
| 193 | 194 | require.NoError(t, err, "the merge stands") | |
| 194 | 195 | assert.False(t, res.SourceDeleted) | |
| 195 | 196 | assert.Equal(t, domain.MRStateMerged, res.State) | |
M internal/app/mergerequests_integration_test.go +116 -115
| @@ -23,8 +23,9 @@ import ( | |||
| 23 | 23 | "bnema.dev/ermite/internal/adapters/kvstore" | |
| 24 | 24 | "bnema.dev/ermite/internal/adapters/sshsig" | |
| 25 | 25 | "bnema.dev/ermite/internal/app" | |
| 26 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |
| 27 | 26 | "bnema.dev/ermite/internal/domain" | |
| 27 | + | "bnema.dev/ermite/internal/ports" | |
| 28 | + | "bnema.dev/ermite/internal/ports/mocks" | |
| 28 | 29 | ) | |
| 29 | 30 | ||
| 30 | 31 | // queuedRepos records the repositories whose maintenance was queued. | |
| @@ -58,7 +59,7 @@ type mrRig struct { | |||
| 58 | 59 | store *kvstore.Store | |
| 59 | 60 | git *gitcli.Git | |
| 60 | 61 | bus *eventbus.Bus | |
| 61 | - | sched *appmocks.MaintenanceScheduler | |
| 62 | + | sched *mocks.MaintenanceScheduler | |
| 62 | 63 | queued *queuedRepos | |
| 63 | 64 | events <-chan domain.Event | |
| 64 | 65 | work string | |
| @@ -94,7 +95,7 @@ func newMRRig(t *testing.T) *mrRig { | |||
| 94 | 95 | require.NoError(t, err) | |
| 95 | 96 | bus := eventbus.NewWithBuffer(1024) | |
| 96 | 97 | committer := domain.Identity{Name: "ermite", Email: "ermite@git.example.org"} | |
| 97 | - | sched := appmocks.NewMaintenanceScheduler(t) | |
| 98 | + | sched := mocks.NewMaintenanceScheduler(t) | |
| 98 | 99 | queued := &queuedRepos{} | |
| 99 | 100 | sched.EXPECT().Schedule(mock.Anything, mock.Anything).Run(queued.add).Return().Maybe() | |
| 100 | 101 | r := &mrRig{ | |
| @@ -109,7 +110,7 @@ func newMRRig(t *testing.T) *mrRig { | |||
| 109 | 110 | Meta: store, Store: store.MergeRequests(), Repos: git, Git: git, Signer: signer, | |
| 110 | 111 | Committer: committer, Bus: bus, Clock: fixedClock{}, Maint: r.sched, | |
| 111 | 112 | }) | |
| 112 | - | _, err = r.repos.Create(ctx, root, app.CreateParams{Name: r.repo, Visibility: domain.VisibilityPrivate}) | |
| 113 | + | _, err = r.repos.Create(ctx, root, ports.CreateRepoParams{Name: r.repo, Visibility: domain.VisibilityPrivate}) | |
| 113 | 114 | require.NoError(t, err) | |
| 114 | 115 | r.sh("init", "-q", "--initial-branch=main") | |
| 115 | 116 | return r | |
| @@ -196,7 +197,7 @@ func (r *mrRig) feature(branch string) domain.ObjectID { | |||
| 196 | 197 | ||
| 197 | 198 | func (r *mrRig) open(branch string) domain.MergeRequest { | |
| 198 | 199 | r.t.Helper() | |
| 199 | - | mr, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "Add " + branch, Source: branch}) | |
| 200 | + | mr, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "Add " + branch, Source: branch}) | |
| 200 | 201 | require.NoError(r.t, err) | |
| 201 | 202 | return mr | |
| 202 | 203 | } | |
| @@ -252,26 +253,26 @@ func TestCreateMergeRequestInputRules(t *testing.T) { | |||
| 252 | 253 | ||
| 253 | 254 | tests := []struct { | |
| 254 | 255 | name string | |
| 255 | - | params app.CreateMergeRequestParams | |
| 256 | + | params ports.CreateMergeRequestParams | |
| 256 | 257 | field string // "" for valid | |
| 257 | 258 | }{ | |
| 258 | - | {"valid, default target", app.CreateMergeRequestParams{Title: "t", Source: "feat"}, ""}, | |
| 259 | - | {"valid, explicit target and description", app.CreateMergeRequestParams{Title: "t", Description: "a\nb", Source: "other", Target: "main"}, ""}, | |
| 260 | - | {"empty title", app.CreateMergeRequestParams{Title: "", Source: "feat", Target: "other"}, "title"}, | |
| 261 | - | {"two-line title", app.CreateMergeRequestParams{Title: "a\nb", Source: "feat", Target: "other"}, "title"}, | |
| 262 | - | {"title too long", app.CreateMergeRequestParams{Title: strings.Repeat("x", 121), Source: "feat", Target: "other"}, "title"}, | |
| 263 | - | {"title with a bidi override", app.CreateMergeRequestParams{Title: "a\u202eb", Source: "feat", Target: "other"}, "title"}, | |
| 264 | - | {"title with an escape", app.CreateMergeRequestParams{Title: "\x1b[31m", Source: "feat", Target: "other"}, "title"}, | |
| 265 | - | {"description with a control character", app.CreateMergeRequestParams{Title: "t", Description: "a\x07", Source: "feat", Target: "other"}, "description"}, | |
| 266 | - | {"description with a bidi isolate", app.CreateMergeRequestParams{Title: "t", Description: "a\u2066b", Source: "feat", Target: "other"}, "description"}, | |
| 267 | - | {"description too long", app.CreateMergeRequestParams{Title: "t", Description: strings.Repeat("x", 8001), Source: "feat", Target: "other"}, "description"}, | |
| 268 | - | {"description not utf-8", app.CreateMergeRequestParams{Title: "t", Description: "\xff", Source: "feat", Target: "other"}, "description"}, | |
| 269 | - | {"source missing", app.CreateMergeRequestParams{Title: "t", Source: ""}, "source_branch"}, | |
| 270 | - | {"source does not exist", app.CreateMergeRequestParams{Title: "t", Source: "nope", Target: "main"}, "source_branch"}, | |
| 271 | - | {"source is not a branch name", app.CreateMergeRequestParams{Title: "t", Source: "a..b", Target: "main"}, "source_branch"}, | |
| 272 | - | {"source is a full ref", app.CreateMergeRequestParams{Title: "t", Source: "refs/heads/feat", Target: "main"}, "source_branch"}, | |
| 273 | - | {"target does not exist", app.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "nope"}, "target_branch"}, | |
| 274 | - | {"same branch", app.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "feat"}, "target_branch"}, | |
| 259 | + | {"valid, default target", ports.CreateMergeRequestParams{Title: "t", Source: "feat"}, ""}, | |
| 260 | + | {"valid, explicit target and description", ports.CreateMergeRequestParams{Title: "t", Description: "a\nb", Source: "other", Target: "main"}, ""}, | |
| 261 | + | {"empty title", ports.CreateMergeRequestParams{Title: "", Source: "feat", Target: "other"}, "title"}, | |
| 262 | + | {"two-line title", ports.CreateMergeRequestParams{Title: "a\nb", Source: "feat", Target: "other"}, "title"}, | |
| 263 | + | {"title too long", ports.CreateMergeRequestParams{Title: strings.Repeat("x", 121), Source: "feat", Target: "other"}, "title"}, | |
| 264 | + | {"title with a bidi override", ports.CreateMergeRequestParams{Title: "a\u202eb", Source: "feat", Target: "other"}, "title"}, | |
| 265 | + | {"title with an escape", ports.CreateMergeRequestParams{Title: "\x1b[31m", Source: "feat", Target: "other"}, "title"}, | |
| 266 | + | {"description with a control character", ports.CreateMergeRequestParams{Title: "t", Description: "a\x07", Source: "feat", Target: "other"}, "description"}, | |
| 267 | + | {"description with a bidi isolate", ports.CreateMergeRequestParams{Title: "t", Description: "a\u2066b", Source: "feat", Target: "other"}, "description"}, | |
| 268 | + | {"description too long", ports.CreateMergeRequestParams{Title: "t", Description: strings.Repeat("x", 8001), Source: "feat", Target: "other"}, "description"}, | |
| 269 | + | {"description not utf-8", ports.CreateMergeRequestParams{Title: "t", Description: "\xff", Source: "feat", Target: "other"}, "description"}, | |
| 270 | + | {"source missing", ports.CreateMergeRequestParams{Title: "t", Source: ""}, "source_branch"}, | |
| 271 | + | {"source does not exist", ports.CreateMergeRequestParams{Title: "t", Source: "nope", Target: "main"}, "source_branch"}, | |
| 272 | + | {"source is not a branch name", ports.CreateMergeRequestParams{Title: "t", Source: "a..b", Target: "main"}, "source_branch"}, | |
| 273 | + | {"source is a full ref", ports.CreateMergeRequestParams{Title: "t", Source: "refs/heads/feat", Target: "main"}, "source_branch"}, | |
| 274 | + | {"target does not exist", ports.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "nope"}, "target_branch"}, | |
| 275 | + | {"same branch", ports.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "feat"}, "target_branch"}, | |
| 275 | 276 | } | |
| 276 | 277 | for _, tc := range tests { | |
| 277 | 278 | t.Run(tc.name, func(t *testing.T) { | |
| @@ -290,7 +291,7 @@ func TestCreateMergeRequestInputRules(t *testing.T) { | |||
| 290 | 291 | } | |
| 291 | 292 | ||
| 292 | 293 | t.Run("a request is rejected whole with every field named", func(t *testing.T) { | |
| 293 | - | _, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "a\nb", Description: "\x07", Source: "nope", Target: "feat"}) | |
| 294 | + | _, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "a\nb", Description: "\x07", Source: "nope", Target: "feat"}) | |
| 294 | 295 | got := fieldsOf(t, err) | |
| 295 | 296 | assert.Contains(t, got, "title") | |
| 296 | 297 | assert.Contains(t, got, "description") | |
| @@ -309,22 +310,22 @@ func TestCreateMergeRequestNumbersAndDuplicates(t *testing.T) { | |||
| 309 | 310 | second := r.open("two") | |
| 310 | 311 | assert.Equal(t, int64(2), second.Number) | |
| 311 | 312 | ||
| 312 | - | _, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "again", Source: "one", Target: "main"}) | |
| 313 | + | _, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "again", Source: "one", Target: "main"}) | |
| 313 | 314 | require.ErrorIs(t, err, domain.ErrAlreadyExists, "same open source and target") | |
| 314 | - | _, err = r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "again", Source: "one"}) | |
| 315 | + | _, err = r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "again", Source: "one"}) | |
| 315 | 316 | require.ErrorIs(t, err, domain.ErrAlreadyExists, "the default target is the same target") | |
| 316 | 317 | ||
| 317 | 318 | // Another target is another request. | |
| 318 | 319 | r.sh("checkout", "-q", "-B", "stage", "main") | |
| 319 | 320 | r.push("stage") | |
| 320 | - | third, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "to stage", Source: "one", Target: "stage"}) | |
| 321 | + | third, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "to stage", Source: "one", Target: "stage"}) | |
| 321 | 322 | require.NoError(t, err) | |
| 322 | 323 | assert.Equal(t, int64(3), third.Number) | |
| 323 | 324 | ||
| 324 | 325 | // Once the first is closed, the pair is free again, with a new number. | |
| 325 | 326 | _, err = r.mrs.Close(r.ctx, root, r.repo, first.Number) | |
| 326 | 327 | require.NoError(t, err) | |
| 327 | - | fourth, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "retry", Source: "one"}) | |
| 328 | + | fourth, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "retry", Source: "one"}) | |
| 328 | 329 | require.NoError(t, err) | |
| 329 | 330 | assert.Equal(t, int64(4), fourth.Number, "numbers are never reused") | |
| 330 | 331 | } | |
| @@ -340,7 +341,7 @@ func TestMergeRequestAccess(t *testing.T) { | |||
| 340 | 341 | ||
| 341 | 342 | reads := map[string]func(p domain.Principal) error{ | |
| 342 | 343 | "List": func(p domain.Principal) error { | |
| 343 | - | _, err := r.mrs.List(r.ctx, p, r.repo, app.ListMergeRequestsParams{}) | |
| 344 | + | _, err := r.mrs.List(r.ctx, p, r.repo, ports.ListMergeRequestsParams{}) | |
| 344 | 345 | return err | |
| 345 | 346 | }, | |
| 346 | 347 | "Get": func(p domain.Principal) error { | |
| @@ -357,16 +358,16 @@ func TestMergeRequestAccess(t *testing.T) { | |||
| 357 | 358 | } | |
| 358 | 359 | _, err := r.mrs.Get(r.ctx, reader, r.repo, n+1, false) | |
| 359 | 360 | assert.ErrorIs(t, err, domain.ErrNotFound, "unknown number") | |
| 360 | - | _, err = r.mrs.List(r.ctx, root, name(t, "ghost"), app.ListMergeRequestsParams{}) | |
| 361 | + | _, err = r.mrs.List(r.ctx, root, name(t, "ghost"), ports.ListMergeRequestsParams{}) | |
| 361 | 362 | assert.ErrorIs(t, err, domain.ErrNotFound, "unknown repository") | |
| 362 | 363 | ||
| 363 | 364 | writes := map[string]func(p domain.Principal) error{ | |
| 364 | 365 | "Create": func(p domain.Principal) error { | |
| 365 | - | _, err := r.mrs.Create(r.ctx, p, r.repo, app.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "feat"}) | |
| 366 | + | _, err := r.mrs.Create(r.ctx, p, r.repo, ports.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "feat"}) | |
| 366 | 367 | return err | |
| 367 | 368 | }, | |
| 368 | 369 | "AddComment": func(p domain.Principal) error { | |
| 369 | - | _, err := r.mrs.AddComment(r.ctx, p, r.repo, n, app.AddCommentParams{Text: "x"}) | |
| 370 | + | _, err := r.mrs.AddComment(r.ctx, p, r.repo, n, ports.AddCommentParams{Text: "x"}) | |
| 370 | 371 | return err | |
| 371 | 372 | }, | |
| 372 | 373 | "ResolveComment": func(p domain.Principal) error { | |
| @@ -382,7 +383,7 @@ func TestMergeRequestAccess(t *testing.T) { | |||
| 382 | 383 | return err | |
| 383 | 384 | }, | |
| 384 | 385 | "Merge": func(p domain.Principal) error { | |
| 385 | - | _, err := r.mrs.Merge(r.ctx, p, r.repo, n+100, app.MergeParams{HeadID: mr.HeadID}) | |
| 386 | + | _, err := r.mrs.Merge(r.ctx, p, r.repo, n+100, ports.MergeParams{HeadID: mr.HeadID}) | |
| 386 | 387 | return err | |
| 387 | 388 | }, | |
| 388 | 389 | } | |
| @@ -413,11 +414,11 @@ func TestMergeRequestAccess(t *testing.T) { | |||
| 413 | 414 | // On a public repository an anonymous caller reads, but writing is | |
| 414 | 415 | // unauthenticated rather than not found. | |
| 415 | 416 | pubName := name(t, "pub") | |
| 416 | - | _, err = r.repos.Create(r.ctx, root, app.CreateParams{Name: pubName, Visibility: domain.VisibilityPublic}) | |
| 417 | + | _, err = r.repos.Create(r.ctx, root, ports.CreateRepoParams{Name: pubName, Visibility: domain.VisibilityPublic}) | |
| 417 | 418 | require.NoError(t, err) | |
| 418 | - | _, err = r.mrs.List(r.ctx, domain.Anonymous(), pubName, app.ListMergeRequestsParams{}) | |
| 419 | + | _, err = r.mrs.List(r.ctx, domain.Anonymous(), pubName, ports.ListMergeRequestsParams{}) | |
| 419 | 420 | assert.NoError(t, err) | |
| 420 | - | _, err = r.mrs.Create(r.ctx, domain.Anonymous(), pubName, app.CreateMergeRequestParams{Title: "t", Source: "a", Target: "b"}) | |
| 421 | + | _, err = r.mrs.Create(r.ctx, domain.Anonymous(), pubName, ports.CreateMergeRequestParams{Title: "t", Source: "a", Target: "b"}) | |
| 421 | 422 | assert.ErrorIs(t, err, domain.ErrUnauthenticated) | |
| 422 | 423 | } | |
| 423 | 424 | ||
| @@ -434,24 +435,24 @@ func TestListMergeRequests(t *testing.T) { | |||
| 434 | 435 | require.NoError(t, err) | |
| 435 | 436 | r.sh("checkout", "-q", "main") | |
| 436 | 437 | merged := r.feature("f0") | |
| 437 | - | _, err = r.mrs.Merge(r.ctx, root, r.repo, 1, app.MergeParams{HeadID: merged}) | |
| 438 | + | _, err = r.mrs.Merge(r.ctx, root, r.repo, 1, ports.MergeParams{HeadID: merged}) | |
| 438 | 439 | require.NoError(t, err) | |
| 439 | 440 | r.sh("branch", "-D", "f4") | |
| 440 | 441 | r.run(r.bare(), r.env(author), "branch", "-D", "f4") | |
| 441 | 442 | ||
| 442 | - | numbers := func(p app.MergeRequestPage) []int64 { | |
| 443 | + | numbers := func(p ports.MergeRequestPage) []int64 { | |
| 443 | 444 | var out []int64 | |
| 444 | 445 | for _, m := range p.MergeRequests { | |
| 445 | 446 | out = append(out, m.Number) | |
| 446 | 447 | } | |
| 447 | 448 | return out | |
| 448 | 449 | } | |
| 449 | - | all, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{}) | |
| 450 | + | all, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{}) | |
| 450 | 451 | require.NoError(t, err) | |
| 451 | 452 | assert.Equal(t, []int64{5, 4, 3, 2, 1}, numbers(all), "highest number first") | |
| 452 | 453 | assert.Empty(t, all.NextPageToken) | |
| 453 | 454 | ||
| 454 | - | open, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{State: domain.MRStateOpen}) | |
| 455 | + | open, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{State: domain.MRStateOpen}) | |
| 455 | 456 | require.NoError(t, err) | |
| 456 | 457 | assert.Equal(t, []int64{5, 4, 3}, numbers(open)) | |
| 457 | 458 | for _, m := range open.MergeRequests { | |
| @@ -461,35 +462,35 @@ func TestListMergeRequests(t *testing.T) { | |||
| 461 | 462 | assert.False(t, m.HeadID.IsZero(), "an open request carries its head") | |
| 462 | 463 | } | |
| 463 | 464 | } | |
| 464 | - | closed, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{State: domain.MRStateClosed}) | |
| 465 | + | closed, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{State: domain.MRStateClosed}) | |
| 465 | 466 | require.NoError(t, err) | |
| 466 | 467 | assert.Equal(t, []int64{2}, numbers(closed)) | |
| 467 | - | mergedPage, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{State: domain.MRStateMerged}) | |
| 468 | + | mergedPage, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{State: domain.MRStateMerged}) | |
| 468 | 469 | require.NoError(t, err) | |
| 469 | 470 | assert.Equal(t, []int64{1}, numbers(mergedPage)) | |
| 470 | 471 | assert.Equal(t, merged, mergedPage.MergeRequests[0].HeadID, "a merged request keeps the head it had") | |
| 471 | 472 | ||
| 472 | 473 | // Paging: the token names the last number. | |
| 473 | - | p1, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{PageSize: 2}) | |
| 474 | + | p1, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{PageSize: 2}) | |
| 474 | 475 | require.NoError(t, err) | |
| 475 | 476 | assert.Equal(t, []int64{5, 4}, numbers(p1)) | |
| 476 | 477 | require.NotEmpty(t, p1.NextPageToken) | |
| 477 | 478 | // A request created between the pages does not shift them. | |
| 478 | 479 | r.feature("late") | |
| 479 | 480 | r.open("late") | |
| 480 | - | p2, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{PageSize: 2, PageToken: p1.NextPageToken}) | |
| 481 | + | p2, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{PageSize: 2, PageToken: p1.NextPageToken}) | |
| 481 | 482 | require.NoError(t, err) | |
| 482 | 483 | assert.Equal(t, []int64{3, 2}, numbers(p2)) | |
| 483 | - | p3, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{PageSize: 2, PageToken: p2.NextPageToken}) | |
| 484 | + | p3, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{PageSize: 2, PageToken: p2.NextPageToken}) | |
| 484 | 485 | require.NoError(t, err) | |
| 485 | 486 | assert.Equal(t, []int64{1}, numbers(p3)) | |
| 486 | 487 | assert.Empty(t, p3.NextPageToken) | |
| 487 | 488 | ||
| 488 | 489 | for _, tok := range []string{"garbage", "bW9yZQ"} { | |
| 489 | - | _, err = r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{PageToken: tok}) | |
| 490 | + | _, err = r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{PageToken: tok}) | |
| 490 | 491 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | |
| 491 | 492 | } | |
| 492 | - | _, err = r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{PageSize: -1}) | |
| 493 | + | _, err = r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{PageSize: -1}) | |
| 493 | 494 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | |
| 494 | 495 | _ = nums | |
| 495 | 496 | } | |
| @@ -499,9 +500,9 @@ func TestGetMergeRequest(t *testing.T) { | |||
| 499 | 500 | main := r.seed() | |
| 500 | 501 | head := r.feature("feat") | |
| 501 | 502 | mr := r.open("feat") | |
| 502 | - | _, err := r.mrs.AddComment(r.ctx, root, r.repo, mr.Number, app.AddCommentParams{Text: "first"}) | |
| 503 | + | _, err := r.mrs.AddComment(r.ctx, root, r.repo, mr.Number, ports.AddCommentParams{Text: "first"}) | |
| 503 | 504 | require.NoError(t, err) | |
| 504 | - | _, err = r.mrs.AddComment(r.ctx, root, r.repo, mr.Number, app.AddCommentParams{Text: "second"}) | |
| 505 | + | _, err = r.mrs.AddComment(r.ctx, root, r.repo, mr.Number, ports.AddCommentParams{Text: "second"}) | |
| 505 | 506 | require.NoError(t, err) | |
| 506 | 507 | ||
| 507 | 508 | d, err := r.mrs.Get(r.ctx, reader, r.repo, mr.Number, false) | |
| @@ -565,30 +566,30 @@ func TestAddComment(t *testing.T) { | |||
| 565 | 566 | ||
| 566 | 567 | tests := []struct { | |
| 567 | 568 | name string | |
| 568 | - | params app.AddCommentParams | |
| 569 | + | params ports.AddCommentParams | |
| 569 | 570 | field string // "" for valid | |
| 570 | 571 | }{ | |
| 571 | - | {"general", app.AddCommentParams{Text: "looks good"}, ""}, | |
| 572 | - | {"multi-line general", app.AddCommentParams{Text: "a\n\nb"}, ""}, | |
| 573 | - | {"new side of a changed line", app.AddCommentParams{Path: "a.txt", Line: 2, Side: domain.SideNew, Text: "x"}, ""}, | |
| 574 | - | {"old side of a changed line", app.AddCommentParams{Path: "a.txt", Line: 2, Side: domain.SideOld, Text: "x"}, ""}, | |
| 575 | - | {"context line", app.AddCommentParams{Path: "a.txt", Line: 3, Side: domain.SideNew, Text: "x"}, ""}, | |
| 576 | - | {"added file", app.AddCommentParams{Path: "c.txt", Line: 1, Side: domain.SideNew, Text: "x"}, ""}, | |
| 577 | - | {"empty text", app.AddCommentParams{Text: ""}, "text"}, | |
| 578 | - | {"blank text", app.AddCommentParams{Text: " \n "}, "text"}, | |
| 579 | - | {"text too long", app.AddCommentParams{Text: strings.Repeat("x", 8001)}, "text"}, | |
| 580 | - | {"text with a control character", app.AddCommentParams{Text: "a\x1b[0m"}, "text"}, | |
| 581 | - | {"text with a tab", app.AddCommentParams{Text: "a\tb"}, "text"}, | |
| 582 | - | {"text with a bidi override", app.AddCommentParams{Text: "a\u202eb"}, "text"}, | |
| 583 | - | {"line outside the diff", app.AddCommentParams{Path: "a.txt", Line: 40, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 584 | - | {"unchanged file", app.AddCommentParams{Path: "b.txt", Line: 1, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 585 | - | {"unknown path", app.AddCommentParams{Path: "nope.txt", Line: 1, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 586 | - | {"deleted line on the wrong side", app.AddCommentParams{Path: "c.txt", Line: 1, Side: domain.SideOld, Text: "x"}, "path"}, | |
| 587 | - | {"path without a line", app.AddCommentParams{Path: "a.txt", Side: domain.SideNew, Text: "x"}, "line"}, | |
| 588 | - | {"path without a side", app.AddCommentParams{Path: "a.txt", Line: 2, Text: "x"}, "side"}, | |
| 589 | - | {"line without a path", app.AddCommentParams{Line: 2, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 590 | - | {"side without a path", app.AddCommentParams{Side: domain.SideOld, Text: "x"}, "path"}, | |
| 591 | - | {"negative line", app.AddCommentParams{Path: "a.txt", Line: -2, Side: domain.SideNew, Text: "x"}, "line"}, | |
| 572 | + | {"general", ports.AddCommentParams{Text: "looks good"}, ""}, | |
| 573 | + | {"multi-line general", ports.AddCommentParams{Text: "a\n\nb"}, ""}, | |
| 574 | + | {"new side of a changed line", ports.AddCommentParams{Path: "a.txt", Line: 2, Side: domain.SideNew, Text: "x"}, ""}, | |
| 575 | + | {"old side of a changed line", ports.AddCommentParams{Path: "a.txt", Line: 2, Side: domain.SideOld, Text: "x"}, ""}, | |
| 576 | + | {"context line", ports.AddCommentParams{Path: "a.txt", Line: 3, Side: domain.SideNew, Text: "x"}, ""}, | |
| 577 | + | {"added file", ports.AddCommentParams{Path: "c.txt", Line: 1, Side: domain.SideNew, Text: "x"}, ""}, | |
| 578 | + | {"empty text", ports.AddCommentParams{Text: ""}, "text"}, | |
| 579 | + | {"blank text", ports.AddCommentParams{Text: " \n "}, "text"}, | |
| 580 | + | {"text too long", ports.AddCommentParams{Text: strings.Repeat("x", 8001)}, "text"}, | |
| 581 | + | {"text with a control character", ports.AddCommentParams{Text: "a\x1b[0m"}, "text"}, | |
| 582 | + | {"text with a tab", ports.AddCommentParams{Text: "a\tb"}, "text"}, | |
| 583 | + | {"text with a bidi override", ports.AddCommentParams{Text: "a\u202eb"}, "text"}, | |
| 584 | + | {"line outside the diff", ports.AddCommentParams{Path: "a.txt", Line: 40, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 585 | + | {"unchanged file", ports.AddCommentParams{Path: "b.txt", Line: 1, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 586 | + | {"unknown path", ports.AddCommentParams{Path: "nope.txt", Line: 1, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 587 | + | {"deleted line on the wrong side", ports.AddCommentParams{Path: "c.txt", Line: 1, Side: domain.SideOld, Text: "x"}, "path"}, | |
| 588 | + | {"path without a line", ports.AddCommentParams{Path: "a.txt", Side: domain.SideNew, Text: "x"}, "line"}, | |
| 589 | + | {"path without a side", ports.AddCommentParams{Path: "a.txt", Line: 2, Text: "x"}, "side"}, | |
| 590 | + | {"line without a path", ports.AddCommentParams{Line: 2, Side: domain.SideNew, Text: "x"}, "path"}, | |
| 591 | + | {"side without a path", ports.AddCommentParams{Side: domain.SideOld, Text: "x"}, "path"}, | |
| 592 | + | {"negative line", ports.AddCommentParams{Path: "a.txt", Line: -2, Side: domain.SideNew, Text: "x"}, "line"}, | |
| 592 | 593 | } | |
| 593 | 594 | for _, tc := range tests { | |
| 594 | 595 | t.Run(tc.name, func(t *testing.T) { | |
| @@ -625,7 +626,7 @@ func TestAddComment(t *testing.T) { | |||
| 625 | 626 | t.Run("not open", func(t *testing.T) { | |
| 626 | 627 | _, err := r.mrs.Close(r.ctx, mrW, r.repo, n) | |
| 627 | 628 | require.NoError(t, err) | |
| 628 | - | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, n, app.AddCommentParams{Text: "late"}) | |
| 629 | + | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, n, ports.AddCommentParams{Text: "late"}) | |
| 629 | 630 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 630 | 631 | _, err = r.mrs.ResolveComment(r.ctx, mrW, r.repo, n, 1, true) | |
| 631 | 632 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| @@ -642,7 +643,7 @@ func TestConcurrentComments(t *testing.T) { | |||
| 642 | 643 | ids := make(chan int64, workers) | |
| 643 | 644 | for i := range workers { | |
| 644 | 645 | wg.Go(func() { | |
| 645 | - | c, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, app.AddCommentParams{Text: fmt.Sprintf("c%d", i)}) | |
| 646 | + | c, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, ports.AddCommentParams{Text: fmt.Sprintf("c%d", i)}) | |
| 646 | 647 | if assert.NoError(t, err) { | |
| 647 | 648 | ids <- c.ID | |
| 648 | 649 | } | |
| @@ -666,7 +667,7 @@ func TestResolveComment(t *testing.T) { | |||
| 666 | 667 | r.seed() | |
| 667 | 668 | r.feature("feat") | |
| 668 | 669 | mr := r.open("feat") | |
| 669 | - | c, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, app.AddCommentParams{Text: "fix this"}) | |
| 670 | + | c, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, ports.AddCommentParams{Text: "fix this"}) | |
| 670 | 671 | require.NoError(t, err) | |
| 671 | 672 | r.drain() | |
| 672 | 673 | ||
| @@ -698,9 +699,9 @@ func TestEventsOfAMergeRequest(t *testing.T) { | |||
| 698 | 699 | r.drain() | |
| 699 | 700 | ||
| 700 | 701 | mr := r.open("feat") | |
| 701 | - | c, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, app.AddCommentParams{Text: "note"}) | |
| 702 | + | c, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, ports.AddCommentParams{Text: "note"}) | |
| 702 | 703 | require.NoError(t, err) | |
| 703 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 704 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 704 | 705 | require.NoError(t, err) | |
| 705 | 706 | ||
| 706 | 707 | r.feature("other") | |
| @@ -732,7 +733,7 @@ func TestEventsOfAMergeRequest(t *testing.T) { | |||
| 732 | 733 | // Failed calls publish nothing. | |
| 733 | 734 | _, err = r.mrs.Close(r.ctx, mrW, r.repo, other.Number) | |
| 734 | 735 | require.Error(t, err) | |
| 735 | - | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, other.Number, app.AddCommentParams{Text: "x"}) | |
| 736 | + | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, other.Number, ports.AddCommentParams{Text: "x"}) | |
| 736 | 737 | require.Error(t, err) | |
| 737 | 738 | assert.Empty(t, r.drain()) | |
| 738 | 739 | } | |
| @@ -859,7 +860,7 @@ func TestMergeFastForward(t *testing.T) { | |||
| 859 | 860 | mr := r.open("feat") | |
| 860 | 861 | r.drain() | |
| 861 | 862 | ||
| 862 | - | merged, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 863 | + | merged, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 863 | 864 | require.NoError(t, err) | |
| 864 | 865 | assert.Equal(t, domain.MRStateMerged, merged.State) | |
| 865 | 866 | assert.Equal(t, domain.MergeModeFastForward, merged.MergeMode, "the default mode") | |
| @@ -880,11 +881,11 @@ func TestMergeFastForward(t *testing.T) { | |||
| 880 | 881 | assert.Len(t, d.Diff.Files, 2) | |
| 881 | 882 | ||
| 882 | 883 | // Repeating it, or touching a final request, is a failed precondition. | |
| 883 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 884 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 884 | 885 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 885 | 886 | _, err = r.mrs.Close(r.ctx, mrW, r.repo, mr.Number) | |
| 886 | 887 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 887 | - | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, app.AddCommentParams{Text: "x"}) | |
| 888 | + | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, ports.AddCommentParams{Text: "x"}) | |
| 888 | 889 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 889 | 890 | } | |
| 890 | 891 | ||
| @@ -897,14 +898,14 @@ func TestMergeRefusals(t *testing.T) { | |||
| 897 | 898 | mr := r.open("feat") | |
| 898 | 899 | r.commit(author, "more.txt", "m\n", "pushed after the review") | |
| 899 | 900 | r.push("feat") | |
| 900 | - | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 901 | + | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 901 | 902 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 902 | 903 | assert.Contains(t, err.Error(), "branch moved, read again") | |
| 903 | 904 | assert.NotEqual(t, head, r.branchHead("main"), "main did not move") | |
| 904 | 905 | // Reading again gives the new head, which merges. | |
| 905 | 906 | d, err := r.mrs.Get(r.ctx, mrM, r.repo, mr.Number, false) | |
| 906 | 907 | require.NoError(t, err) | |
| 907 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: d.MergeRequest.HeadID}) | |
| 908 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: d.MergeRequest.HeadID}) | |
| 908 | 909 | require.NoError(t, err) | |
| 909 | 910 | }) | |
| 910 | 911 | ||
| @@ -919,7 +920,7 @@ func TestMergeRefusals(t *testing.T) { | |||
| 919 | 920 | tip := r.branchHead("main") | |
| 920 | 921 | ||
| 921 | 922 | for _, mode := range []domain.MergeMode{domain.MergeModeFastForward, domain.MergeModeSquash} { | |
| 922 | - | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, Mode: mode}) | |
| 923 | + | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, Mode: mode}) | |
| 923 | 924 | require.ErrorIs(t, err, domain.ErrPreconditionFailed, mode) | |
| 924 | 925 | assert.Contains(t, err.Error(), "rebase", mode) | |
| 925 | 926 | } | |
| @@ -932,7 +933,7 @@ func TestMergeRefusals(t *testing.T) { | |||
| 932 | 933 | r.sh("checkout", "-q", "feat") | |
| 933 | 934 | r.sh("rebase", "-q", "main") | |
| 934 | 935 | r.push("feat") | |
| 935 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: r.head()}) | |
| 936 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: r.head()}) | |
| 936 | 937 | require.NoError(t, err) | |
| 937 | 938 | }) | |
| 938 | 939 | ||
| @@ -942,13 +943,13 @@ func TestMergeRefusals(t *testing.T) { | |||
| 942 | 943 | head := r.feature("feat") | |
| 943 | 944 | mr := r.open("feat") | |
| 944 | 945 | modes := []domain.MergeMode{domain.MergeModeFastForward} | |
| 945 | - | _, err := r.repos.Update(r.ctx, root, r.repo, app.UpdateParams{AllowedMergeModes: &modes}) | |
| 946 | + | _, err := r.repos.Update(r.ctx, root, r.repo, ports.UpdateRepoParams{AllowedMergeModes: &modes}) | |
| 946 | 947 | require.NoError(t, err) | |
| 947 | 948 | ||
| 948 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, Mode: domain.MergeModeSquash}) | |
| 949 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, Mode: domain.MergeModeSquash}) | |
| 949 | 950 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 950 | 951 | assert.Contains(t, err.Error(), "squash") | |
| 951 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 952 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 952 | 953 | require.NoError(t, err, "fast-forward is allowed") | |
| 953 | 954 | }) | |
| 954 | 955 | ||
| @@ -958,11 +959,11 @@ func TestMergeRefusals(t *testing.T) { | |||
| 958 | 959 | head := r.feature("feat") | |
| 959 | 960 | mr := r.open("feat") | |
| 960 | 961 | modes := []domain.MergeMode{domain.MergeModeSquash} | |
| 961 | - | _, err := r.repos.Update(r.ctx, root, r.repo, app.UpdateParams{AllowedMergeModes: &modes}) | |
| 962 | + | _, err := r.repos.Update(r.ctx, root, r.repo, ports.UpdateRepoParams{AllowedMergeModes: &modes}) | |
| 962 | 963 | require.NoError(t, err) | |
| 963 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 964 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 964 | 965 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 965 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, Mode: domain.MergeModeSquash}) | |
| 966 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, Mode: domain.MergeModeSquash}) | |
| 966 | 967 | require.NoError(t, err) | |
| 967 | 968 | }) | |
| 968 | 969 | ||
| @@ -971,13 +972,13 @@ func TestMergeRefusals(t *testing.T) { | |||
| 971 | 972 | r.seed() | |
| 972 | 973 | head := r.feature("feat") | |
| 973 | 974 | mr := r.open("feat") | |
| 974 | - | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{}) | |
| 975 | + | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{}) | |
| 975 | 976 | require.ErrorIs(t, err, domain.ErrInvalid) | |
| 976 | 977 | assert.Contains(t, fieldsOf(t, err), "head_id") | |
| 977 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, Mode: "rebase"}) | |
| 978 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, Mode: "rebase"}) | |
| 978 | 979 | require.ErrorIs(t, err, domain.ErrInvalid) | |
| 979 | 980 | assert.Contains(t, fieldsOf(t, err), "mode") | |
| 980 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, 99, app.MergeParams{HeadID: head}) | |
| 981 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, 99, ports.MergeParams{HeadID: head}) | |
| 981 | 982 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| 982 | 983 | }) | |
| 983 | 984 | ||
| @@ -987,13 +988,13 @@ func TestMergeRefusals(t *testing.T) { | |||
| 987 | 988 | head := r.feature("feat") | |
| 988 | 989 | mr := r.open("feat") | |
| 989 | 990 | r.run(r.bare(), r.env(author), "branch", "-D", "feat") | |
| 990 | - | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 991 | + | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 991 | 992 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 992 | 993 | assert.Contains(t, err.Error(), "no longer exists") | |
| 993 | 994 | ||
| 994 | 995 | r.push("feat") | |
| 995 | 996 | r.run(r.bare(), r.env(author), "update-ref", "refs/heads/main", head.String()) | |
| 996 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head}) | |
| 997 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head}) | |
| 997 | 998 | require.ErrorIs(t, err, domain.ErrPreconditionFailed, "the target already is at the head") | |
| 998 | 999 | assert.Contains(t, err.Error(), "nothing to merge") | |
| 999 | 1000 | }) | |
| @@ -1022,7 +1023,7 @@ func TestConcurrentMergesSerialize(t *testing.T) { | |||
| 1022 | 1023 | continue | |
| 1023 | 1024 | } | |
| 1024 | 1025 | wg.Go(func() { | |
| 1025 | - | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, number, app.MergeParams{HeadID: head, Mode: mode}) | |
| 1026 | + | _, err := r.mrs.Merge(r.ctx, mrM, r.repo, number, ports.MergeParams{HeadID: head, Mode: mode}) | |
| 1026 | 1027 | results <- outcome{number, err} | |
| 1027 | 1028 | }) | |
| 1028 | 1029 | } | |
| @@ -1079,11 +1080,11 @@ func TestSquashMerge(t *testing.T) { | |||
| 1079 | 1080 | r.commit(bob, "w.txt", "w\n", "bob again") | |
| 1080 | 1081 | r.push("feat") | |
| 1081 | 1082 | head := r.branchHead("feat") | |
| 1082 | - | mr, err := r.mrs.Create(r.ctx, root, r.repo, app.CreateMergeRequestParams{Title: "Add things", Source: "feat"}) | |
| 1083 | + | mr, err := r.mrs.Create(r.ctx, root, r.repo, ports.CreateMergeRequestParams{Title: "Add things", Source: "feat"}) | |
| 1083 | 1084 | require.NoError(t, err) | |
| 1084 | 1085 | r.drain() | |
| 1085 | 1086 | ||
| 1086 | - | merged, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: head, Mode: domain.MergeModeSquash}) | |
| 1087 | + | merged, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: head, Mode: domain.MergeModeSquash}) | |
| 1087 | 1088 | require.NoError(t, err) | |
| 1088 | 1089 | assert.Equal(t, domain.MergeModeSquash, merged.MergeMode) | |
| 1089 | 1090 | require.False(t, merged.MergedCommitID.IsZero()) | |
| @@ -1144,7 +1145,7 @@ func TestSquashSingleCommitHasNoTrailer(t *testing.T) { | |||
| 1144 | 1145 | r.commit(author, "m.txt", "m\n", "only") | |
| 1145 | 1146 | r.push("mine") | |
| 1146 | 1147 | mr := r.open("mine") | |
| 1147 | - | merged, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{HeadID: r.branchHead("mine"), Mode: domain.MergeModeSquash}) | |
| 1148 | + | merged, err := r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{HeadID: r.branchHead("mine"), Mode: domain.MergeModeSquash}) | |
| 1148 | 1149 | require.NoError(t, err) | |
| 1149 | 1150 | msg := r.run(r.bare(), r.env(author), "log", "-1", "--format=%B", merged.MergedCommitID.String()) | |
| 1150 | 1151 | assert.Equal(t, "Add mine (!1)\n\n- only", msg) | |
| @@ -1159,7 +1160,7 @@ func TestUpdateRepoSettings(t *testing.T) { | |||
| 1159 | 1160 | ||
| 1160 | 1161 | modes := []domain.MergeMode{domain.MergeModeSquash, domain.MergeModeSquash} | |
| 1161 | 1162 | off := false | |
| 1162 | - | got, err := r.repos.Update(r.ctx, root, r.repo, app.UpdateParams{AllowedMergeModes: &modes, FailingChecksBlock: &off}) | |
| 1163 | + | got, err := r.repos.Update(r.ctx, root, r.repo, ports.UpdateRepoParams{AllowedMergeModes: &modes, FailingChecksBlock: &off}) | |
| 1163 | 1164 | require.NoError(t, err) | |
| 1164 | 1165 | assert.Equal(t, domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}, FailingChecksBlock: false}, got.Settings) | |
| 1165 | 1166 | again, err := r.repos.Get(r.ctx, root, r.repo) | |
| @@ -1168,14 +1169,14 @@ func TestUpdateRepoSettings(t *testing.T) { | |||
| 1168 | 1169 | ||
| 1169 | 1170 | // Only the named setting changes. | |
| 1170 | 1171 | on := true | |
| 1171 | - | got, err = r.repos.Update(r.ctx, root, r.repo, app.UpdateParams{FailingChecksBlock: &on}) | |
| 1172 | + | got, err = r.repos.Update(r.ctx, root, r.repo, ports.UpdateRepoParams{FailingChecksBlock: &on}) | |
| 1172 | 1173 | require.NoError(t, err) | |
| 1173 | 1174 | assert.Equal(t, []domain.MergeMode{domain.MergeModeSquash}, got.Settings.AllowedMergeModes) | |
| 1174 | 1175 | assert.True(t, got.Settings.FailingChecksBlock) | |
| 1175 | 1176 | ||
| 1176 | 1177 | for _, bad := range [][]domain.MergeMode{{}, nil, {"rebase"}} { | |
| 1177 | 1178 | bad := bad | |
| 1178 | - | _, err = r.repos.Update(r.ctx, root, r.repo, app.UpdateParams{AllowedMergeModes: &bad}) | |
| 1179 | + | _, err = r.repos.Update(r.ctx, root, r.repo, ports.UpdateRepoParams{AllowedMergeModes: &bad}) | |
| 1179 | 1180 | assert.ErrorIs(t, err, domain.ErrInvalid, "%v", bad) | |
| 1180 | 1181 | } | |
| 1181 | 1182 | again, err = r.repos.Get(r.ctx, root, r.repo) | |
| @@ -1183,7 +1184,7 @@ func TestUpdateRepoSettings(t *testing.T) { | |||
| 1183 | 1184 | assert.Equal(t, got.Settings, again.Settings, "a refused change stores nothing") | |
| 1184 | 1185 | ||
| 1185 | 1186 | // repo:admin is needed, like for any other field. | |
| 1186 | - | _, err = r.repos.Update(r.ctx, writer(domain.ScopeRepoRead, domain.ScopeMRMerge), r.repo, app.UpdateParams{FailingChecksBlock: &off}) | |
| 1187 | + | _, err = r.repos.Update(r.ctx, writer(domain.ScopeRepoRead, domain.ScopeMRMerge), r.repo, ports.UpdateRepoParams{FailingChecksBlock: &off}) | |
| 1187 | 1188 | assert.ErrorIs(t, err, domain.ErrForbidden) | |
| 1188 | 1189 | } | |
| 1189 | 1190 | ||
| @@ -1194,13 +1195,13 @@ func TestDeletingARepositoryDropsItsMergeRequests(t *testing.T) { | |||
| 1194 | 1195 | r.open("feat") | |
| 1195 | 1196 | require.NoError(t, r.repos.Delete(r.ctx, root, r.repo)) | |
| 1196 | 1197 | ||
| 1197 | - | _, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{}) | |
| 1198 | + | _, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{}) | |
| 1198 | 1199 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| 1199 | 1200 | ||
| 1200 | 1201 | // Created again under the same name, it starts empty. | |
| 1201 | - | _, err = r.repos.Create(r.ctx, root, app.CreateParams{Name: r.repo}) | |
| 1202 | + | _, err = r.repos.Create(r.ctx, root, ports.CreateRepoParams{Name: r.repo}) | |
| 1202 | 1203 | require.NoError(t, err) | |
| 1203 | - | page, err := r.mrs.List(r.ctx, root, r.repo, app.ListMergeRequestsParams{}) | |
| 1204 | + | page, err := r.mrs.List(r.ctx, root, r.repo, ports.ListMergeRequestsParams{}) | |
| 1204 | 1205 | require.NoError(t, err) | |
| 1205 | 1206 | assert.Empty(t, page.MergeRequests) | |
| 1206 | 1207 | } | |
| @@ -1222,12 +1223,12 @@ func TestAgentPresetWorksOnItsPrivateRepository(t *testing.T) { | |||
| 1222 | 1223 | r.seed() | |
| 1223 | 1224 | head := r.feature("feat") | |
| 1224 | 1225 | ||
| 1225 | - | mr, err := r.mrs.Create(r.ctx, agent, r.repo, app.CreateMergeRequestParams{Title: "From the agent", Source: "feat"}) | |
| 1226 | + | mr, err := r.mrs.Create(r.ctx, agent, r.repo, ports.CreateMergeRequestParams{Title: "From the agent", Source: "feat"}) | |
| 1226 | 1227 | require.NoError(t, err) | |
| 1227 | 1228 | assert.Equal(t, head, mr.HeadID) | |
| 1228 | 1229 | assert.Equal(t, "agent-1", mr.Author) | |
| 1229 | 1230 | ||
| 1230 | - | c, err := r.mrs.AddComment(r.ctx, agent, r.repo, mr.Number, app.AddCommentParams{Text: "note"}) | |
| 1231 | + | c, err := r.mrs.AddComment(r.ctx, agent, r.repo, mr.Number, ports.AddCommentParams{Text: "note"}) | |
| 1231 | 1232 | require.NoError(t, err) | |
| 1232 | 1233 | _, err = r.mrs.ResolveComment(r.ctx, agent, r.repo, mr.Number, c.ID, true) | |
| 1233 | 1234 | require.NoError(t, err) | |
| @@ -1235,7 +1236,7 @@ func TestAgentPresetWorksOnItsPrivateRepository(t *testing.T) { | |||
| 1235 | 1236 | require.NoError(t, err) | |
| 1236 | 1237 | ||
| 1237 | 1238 | // repo:write alone does not read merge requests. | |
| 1238 | - | _, err = r.mrs.List(r.ctx, agent, r.repo, app.ListMergeRequestsParams{}) | |
| 1239 | + | _, err = r.mrs.List(r.ctx, agent, r.repo, ports.ListMergeRequestsParams{}) | |
| 1239 | 1240 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| 1240 | 1241 | _, err = r.mrs.Get(r.ctx, agent, r.repo, mr.Number, false) | |
| 1241 | 1242 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| @@ -1245,11 +1246,11 @@ func TestAgentPresetWorksOnItsPrivateRepository(t *testing.T) { | |||
| 1245 | 1246 | assert.Equal(t, domain.MRStateClosed, closed.State) | |
| 1246 | 1247 | ||
| 1247 | 1248 | // An unknown repository is not found whatever the scopes. | |
| 1248 | - | _, err = r.mrs.Create(r.ctx, agent, name(t, "ghost"), app.CreateMergeRequestParams{Title: "t", Source: "feat"}) | |
| 1249 | + | _, err = r.mrs.Create(r.ctx, agent, name(t, "ghost"), ports.CreateMergeRequestParams{Title: "t", Source: "feat"}) | |
| 1249 | 1250 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| 1250 | 1251 | // A token limited to other repositories does not get the scope here. | |
| 1251 | 1252 | elsewhere := domain.TokenPrincipal(domain.Token{ID: "e", Scopes: []domain.Scope{domain.ScopeRepoWrite, domain.ScopeMRWrite}, Repos: []domain.RepoName{name(t, "else")}}) | |
| 1252 | - | _, err = r.mrs.Create(r.ctx, elsewhere, r.repo, app.CreateMergeRequestParams{Title: "t", Source: "feat"}) | |
| 1253 | + | _, err = r.mrs.Create(r.ctx, elsewhere, r.repo, ports.CreateMergeRequestParams{Title: "t", Source: "feat"}) | |
| 1253 | 1254 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| 1254 | 1255 | } | |
| 1255 | 1256 | ||
| @@ -1267,7 +1268,7 @@ func TestMergeRecordsAPush(t *testing.T) { | |||
| 1267 | 1268 | require.True(t, before.PushedAt.IsZero(), "no push recorded yet") | |
| 1268 | 1269 | assert.Empty(t, r.queued.names()) | |
| 1269 | 1270 | ||
| 1270 | - | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, app.MergeParams{Mode: mode, HeadID: head}) | |
| 1271 | + | _, err = r.mrs.Merge(r.ctx, mrM, r.repo, mr.Number, ports.MergeParams{Mode: mode, HeadID: head}) | |
| 1271 | 1272 | require.NoError(t, err) | |
| 1272 | 1273 | ||
| 1273 | 1274 | after, err := r.repos.Get(r.ctx, root, r.repo) | |
| @@ -1285,10 +1286,10 @@ func TestCommentsPerMergeRequestAreBounded(t *testing.T) { | |||
| 1285 | 1286 | r.feature("feat") | |
| 1286 | 1287 | mr := r.open("feat") | |
| 1287 | 1288 | for i := range app.MaxCommentsPerMergeRequest { | |
| 1288 | - | _, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, app.AddCommentParams{Text: fmt.Sprintf("c%d", i)}) | |
| 1289 | + | _, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, ports.AddCommentParams{Text: fmt.Sprintf("c%d", i)}) | |
| 1289 | 1290 | require.NoError(t, err, "comment %d", i+1) | |
| 1290 | 1291 | } | |
| 1291 | - | _, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, app.AddCommentParams{Text: "one too many"}) | |
| 1292 | + | _, err := r.mrs.AddComment(r.ctx, mrW, r.repo, mr.Number, ports.AddCommentParams{Text: "one too many"}) | |
| 1292 | 1293 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | |
| 1293 | 1294 | d, err := r.mrs.Get(r.ctx, root, r.repo, mr.Number, false) | |
| 1294 | 1295 | require.NoError(t, err) | |
| @@ -1301,6 +1302,6 @@ func TestCommentsPerMergeRequestAreBounded(t *testing.T) { | |||
| 1301 | 1302 | r.commit(author, "o.txt", "o\n", "other") | |
| 1302 | 1303 | r.push("other") | |
| 1303 | 1304 | other := r.open("other") | |
| 1304 | - | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, other.Number, app.AddCommentParams{Text: "fine"}) | |
| 1305 | + | _, err = r.mrs.AddComment(r.ctx, mrW, r.repo, other.Number, ports.AddCommentParams{Text: "fine"}) | |
| 1305 | 1306 | require.NoError(t, err) | |
| 1306 | 1307 | } | |
M internal/app/mergerequests_test.go +5 -5
| @@ -12,8 +12,8 @@ import ( | |||
| 12 | 12 | "github.com/stretchr/testify/require" | |
| 13 | 13 | ||
| 14 | 14 | "bnema.dev/ermite/internal/app" | |
| 15 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |
| 16 | 15 | "bnema.dev/ermite/internal/domain" | |
| 16 | + | "bnema.dev/ermite/internal/ports" | |
| 17 | 17 | "bnema.dev/ermite/internal/ports/mocks" | |
| 18 | 18 | ) | |
| 19 | 19 | ||
| @@ -37,7 +37,7 @@ func newMRUnit(t *testing.T) *mrUnit { | |||
| 37 | 37 | } | |
| 38 | 38 | clock := mocks.NewClock(t) | |
| 39 | 39 | clock.EXPECT().Now().Return(now).Maybe() | |
| 40 | - | sched := appmocks.NewMaintenanceScheduler(t) | |
| 40 | + | sched := mocks.NewMaintenanceScheduler(t) | |
| 41 | 41 | sched.EXPECT().Schedule(mock.Anything, mock.Anything).Return().Maybe() | |
| 42 | 42 | u.mrs = app.NewMergeRequests(app.MergeRequestsConfig{ | |
| 43 | 43 | Meta: u.meta, Store: u.store, Repos: u.repos, Git: u.git, | |
| @@ -51,7 +51,7 @@ func newMRUnit(t *testing.T) *mrUnit { | |||
| 51 | 51 | func TestCreateReturnsGitFailuresAsErrors(t *testing.T) { | |
| 52 | 52 | t.Parallel() | |
| 53 | 53 | boom := errors.New("fatal: /srv/ermite/repos/proj.git: permission denied") | |
| 54 | - | params := app.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "main"} | |
| 54 | + | params := ports.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "main"} | |
| 55 | 55 | ||
| 56 | 56 | t.Run("reading a branch", func(t *testing.T) { | |
| 57 | 57 | t.Parallel() | |
| @@ -70,7 +70,7 @@ func TestCreateReturnsGitFailuresAsErrors(t *testing.T) { | |||
| 70 | 70 | u := newMRUnit(t) | |
| 71 | 71 | u.meta.EXPECT().Get(mock.Anything, u.repo.Name).Return(u.repo, nil) | |
| 72 | 72 | u.repos.EXPECT().DefaultBranch(mock.Anything, u.repo.Name).Return("", false, boom) | |
| 73 | - | _, err := u.mrs.Create(context.Background(), domain.Root(), u.repo.Name, app.CreateMergeRequestParams{Title: "t", Source: "feat"}) | |
| 73 | + | _, err := u.mrs.Create(context.Background(), domain.Root(), u.repo.Name, ports.CreateMergeRequestParams{Title: "t", Source: "feat"}) | |
| 74 | 74 | require.ErrorIs(t, err, boom) | |
| 75 | 75 | var fe *domain.InvalidFieldsError | |
| 76 | 76 | assert.False(t, errors.As(err, &fe), "not a field violation: %v", err) | |
| @@ -109,7 +109,7 @@ func TestMergeReturnsTheFailureToReadTheSettings(t *testing.T) { | |||
| 109 | 109 | u.store.EXPECT().Get(mock.Anything, u.repo.Name, int64(1)).Return(domain.MergeRequest{ | |
| 110 | 110 | Repo: u.repo.Name, Number: 1, State: domain.MRStateOpen, Source: "feat", Target: "main", | |
| 111 | 111 | }, nil) | |
| 112 | - | _, err := u.mrs.Merge(context.Background(), domain.Root(), u.repo.Name, 1, app.MergeParams{HeadID: someID(t)}) | |
| 112 | + | _, err := u.mrs.Merge(context.Background(), domain.Root(), u.repo.Name, 1, ports.MergeParams{HeadID: someID(t)}) | |
| 113 | 113 | require.ErrorIs(t, err, tc.want) | |
| 114 | 114 | if tc.want == boom { | |
| 115 | 115 | assert.NotErrorIs(t, err, domain.ErrNotFound) | |
M internal/app/paging.go +11 -24
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | 11 | "strings" | |
| 12 | 12 | ||
| 13 | 13 | "bnema.dev/ermite/internal/domain" | |
| 14 | + | "bnema.dev/ermite/internal/ports" | |
| 14 | 15 | ) | |
| 15 | 16 | ||
| 16 | 17 | const ( | |
| @@ -83,31 +84,24 @@ func pageAfter[T any](items []T, size int, after func(T) bool, token func(T) str | |||
| 83 | 84 | return page, "" | |
| 84 | 85 | } | |
| 85 | 86 | ||
| 86 | - | // RepoPage is a page of repositories ordered by name. | |
| 87 | - | type RepoPage struct { | |
| 88 | - | Repos []domain.Repo | |
| 89 | - | // NextPageToken is empty on the last page. | |
| 90 | - | NextPageToken string | |
| 91 | - | } | |
| 92 | - | ||
| 93 | 87 | // ListPage returns a page of the repositories the principal may read, ordered | |
| 94 | 88 | // by name. size is 0 for DefaultPageSize and lowered to MaxRepoPageSize; the page | |
| 95 | 89 | // token names the last repository of the previous page, so repositories that | |
| 96 | 90 | // appear or disappear between two pages never shift the others. | |
| 97 | - | func (r *Repos) ListPage(ctx context.Context, p domain.Principal, size int, token string) (RepoPage, error) { | |
| 91 | + | func (r *Repos) ListPage(ctx context.Context, p domain.Principal, size int, token string) (ports.RepoPage, error) { | |
| 98 | 92 | n, err := pageSizeUpTo(size, MaxRepoPageSize) | |
| 99 | 93 | if err != nil { | |
| 100 | - | return RepoPage{}, err | |
| 94 | + | return ports.RepoPage{}, err | |
| 101 | 95 | } | |
| 102 | 96 | after, err := decodeRepoToken(token) | |
| 103 | 97 | if err != nil { | |
| 104 | - | return RepoPage{}, err | |
| 98 | + | return ports.RepoPage{}, err | |
| 105 | 99 | } | |
| 106 | 100 | all, err := r.List(ctx, p) | |
| 107 | 101 | if err != nil { | |
| 108 | - | return RepoPage{}, err | |
| 102 | + | return ports.RepoPage{}, err | |
| 109 | 103 | } | |
| 110 | - | var page RepoPage | |
| 104 | + | var page ports.RepoPage | |
| 111 | 105 | page.Repos, page.NextPageToken = pageAfter(all, n, | |
| 112 | 106 | func(repo domain.Repo) bool { return after == "" || repo.Name.String() > after }, | |
| 113 | 107 | func(repo domain.Repo) string { return encodeRepoToken(repo.Name) }) | |
| @@ -130,28 +124,21 @@ func decodeRepoToken(tok string) (string, error) { | |||
| 130 | 124 | return raw, nil | |
| 131 | 125 | } | |
| 132 | 126 | ||
| 133 | - | // TokenPage is a page of stored tokens, newest first. | |
| 134 | - | type TokenPage struct { | |
| 135 | - | Tokens []domain.Token | |
| 136 | - | // NextPageToken is empty on the last page. | |
| 137 | - | NextPageToken string | |
| 138 | - | } | |
| 139 | - | ||
| 140 | 127 | // ListPage returns a page of the tokens List returns, newest first (then by | |
| 141 | 128 | // id). size and the page token work like Repos.ListPage; the token names the | |
| 142 | 129 | // last token of the previous page. | |
| 143 | - | func (t *Tokens) ListPage(ctx context.Context, p domain.Principal, size int, token string) (TokenPage, error) { | |
| 130 | + | func (t *Tokens) ListPage(ctx context.Context, p domain.Principal, size int, token string) (ports.TokenPage, error) { | |
| 144 | 131 | n, err := pageSize(size) | |
| 145 | 132 | if err != nil { | |
| 146 | - | return TokenPage{}, err | |
| 133 | + | return ports.TokenPage{}, err | |
| 147 | 134 | } | |
| 148 | 135 | after, err := decodeTokenCursor(token) | |
| 149 | 136 | if err != nil { | |
| 150 | - | return TokenPage{}, err | |
| 137 | + | return ports.TokenPage{}, err | |
| 151 | 138 | } | |
| 152 | 139 | all, err := t.List(ctx, p) | |
| 153 | 140 | if err != nil { | |
| 154 | - | return TokenPage{}, err | |
| 141 | + | return ports.TokenPage{}, err | |
| 155 | 142 | } | |
| 156 | 143 | slices.SortFunc(all, func(a, b domain.Token) int { | |
| 157 | 144 | if c := b.CreatedAt.Compare(a.CreatedAt); c != 0 { | |
| @@ -159,7 +146,7 @@ func (t *Tokens) ListPage(ctx context.Context, p domain.Principal, size int, tok | |||
| 159 | 146 | } | |
| 160 | 147 | return strings.Compare(b.ID, a.ID) | |
| 161 | 148 | }) | |
| 162 | - | var page TokenPage | |
| 149 | + | var page ports.TokenPage | |
| 163 | 150 | page.Tokens, page.NextPageToken = pageAfter(all, n, | |
| 164 | 151 | func(tok domain.Token) bool { return after == nil || tokenAfter(tok, *after) }, | |
| 165 | 152 | encodeTokenCursor) | |
M internal/app/pushes.go +9 -15
| @@ -18,17 +18,6 @@ import ( | |||
| 18 | 18 | // pushRetries bounds the retries of a metadata update that loses a race. | |
| 19 | 19 | const pushRetries = 5 | |
| 20 | 20 | ||
| 21 | - | // MaintenanceScheduler queues repository maintenance. *Maintainer fits. | |
| 22 | - | type MaintenanceScheduler interface { | |
| 23 | - | Schedule(ctx context.Context, name domain.RepoName) | |
| 24 | - | } | |
| 25 | - | ||
| 26 | - | // Revalidator confirms that a principal obtained earlier is still | |
| 27 | - | // authorized. *Auth fits. | |
| 28 | - | type Revalidator interface { | |
| 29 | - | Revalidate(ctx context.Context, p domain.Principal) error | |
| 30 | - | } | |
| 31 | - | ||
| 32 | 21 | // Pushes are the use cases around a Git push. | |
| 33 | 22 | type Pushes struct { | |
| 34 | 23 | meta ports.RepoMetaStore | |
| @@ -36,15 +25,20 @@ type Pushes struct { | |||
| 36 | 25 | git ports.GitRepos | |
| 37 | 26 | bus ports.EventBus | |
| 38 | 27 | clock ports.Clock | |
| 39 | - | maint MaintenanceScheduler | |
| 40 | - | auth Revalidator | |
| 28 | + | maint ports.MaintenanceScheduler | |
| 29 | + | auth ports.Revalidator | |
| 41 | 30 | fresh ports.RepoFreshener // nil: the reader needs no telling | |
| 42 | 31 | } | |
| 43 | 32 | ||
| 33 | + | var ( | |
| 34 | + | _ ports.PushService = (*Pushes)(nil) | |
| 35 | + | _ ports.PushHookService = (*Pushes)(nil) | |
| 36 | + | ) | |
| 37 | + | ||
| 44 | 38 | // NewPushes builds the push use cases. Every argument is required: auth | |
| 45 | 39 | // re-validates the token of a push when its pre-receive hook runs, maint | |
| 46 | 40 | // queues the maintenance that follows a push. | |
| 47 | - | func NewPushes(meta ports.RepoMetaStore, repos *Repos, git ports.GitRepos, bus ports.EventBus, clock ports.Clock, maint MaintenanceScheduler, auth Revalidator) *Pushes { | |
| 41 | + | func NewPushes(meta ports.RepoMetaStore, repos *Repos, git ports.GitRepos, bus ports.EventBus, clock ports.Clock, maint ports.MaintenanceScheduler, auth ports.Revalidator) *Pushes { | |
| 48 | 42 | return &Pushes{meta: meta, repos: repos, git: git, bus: bus, clock: clock, maint: maint, auth: auth} | |
| 49 | 43 | } | |
| 50 | 44 | ||
| @@ -78,7 +72,7 @@ func (u *Pushes) Open(ctx context.Context, p domain.Principal, name domain.RepoN | |||
| 78 | 72 | if !create || !canWrite(p, name) { | |
| 79 | 73 | return domain.ErrNotFound | |
| 80 | 74 | } | |
| 81 | - | _, err = u.repos.Create(ctx, p, CreateParams{Name: name, Visibility: domain.VisibilityPrivate}) | |
| 75 | + | _, err = u.repos.Create(ctx, p, ports.CreateRepoParams{Name: name, Visibility: domain.VisibilityPrivate}) | |
| 82 | 76 | switch { | |
| 83 | 77 | case err == nil: | |
| 84 | 78 | return nil // Create published RepoCreated | |
M internal/app/pushes_test.go +2 -3
| @@ -13,7 +13,6 @@ import ( | |||
| 13 | 13 | "github.com/stretchr/testify/require" | |
| 14 | 14 | ||
| 15 | 15 | "bnema.dev/ermite/internal/app" | |
| 16 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |
| 17 | 16 | "bnema.dev/ermite/internal/domain" | |
| 18 | 17 | "bnema.dev/ermite/internal/ports" | |
| 19 | 18 | "bnema.dev/ermite/internal/ports/mocks" | |
| @@ -25,7 +24,7 @@ type pushFixture struct { | |||
| 25 | 24 | bus *mocks.EventBus | |
| 26 | 25 | clock *mocks.Clock | |
| 27 | 26 | tokens *mocks.TokenStore | |
| 28 | - | sched *appmocks.MaintenanceScheduler | |
| 27 | + | sched *mocks.MaintenanceScheduler | |
| 29 | 28 | pushes *app.Pushes | |
| 30 | 29 | } | |
| 31 | 30 | ||
| @@ -37,7 +36,7 @@ func newPushFixture(t *testing.T) *pushFixture { | |||
| 37 | 36 | bus: mocks.NewEventBus(t), | |
| 38 | 37 | clock: mocks.NewClock(t), | |
| 39 | 38 | tokens: mocks.NewTokenStore(t), | |
| 40 | - | sched: appmocks.NewMaintenanceScheduler(t), | |
| 39 | + | sched: mocks.NewMaintenanceScheduler(t), | |
| 41 | 40 | } | |
| 42 | 41 | f.clock.EXPECT().Now().Return(now).Maybe() | |
| 43 | 42 | repos := app.NewRepos(f.meta, f.git, f.bus, f.clock) | |
M internal/app/repos.go +3 -9
| @@ -23,20 +23,14 @@ type Repos struct { | |||
| 23 | 23 | clock ports.Clock | |
| 24 | 24 | } | |
| 25 | 25 | ||
| 26 | + | var _ ports.RepoService = (*Repos)(nil) | |
| 27 | + | ||
| 26 | 28 | // NewRepos builds the repository use cases over their ports. Changes are | |
| 27 | 29 | // published on bus. | |
| 28 | 30 | func NewRepos(meta ports.RepoMetaStore, git ports.GitRepos, bus ports.EventBus, clock ports.Clock) *Repos { | |
| 29 | 31 | return &Repos{meta: meta, git: git, bus: bus, clock: clock} | |
| 30 | 32 | } | |
| 31 | 33 | ||
| 32 | - | // CreateParams are the settings of a new repository. | |
| 33 | - | type CreateParams struct { | |
| 34 | - | Name domain.RepoName | |
| 35 | - | Description string | |
| 36 | - | // Visibility defaults to private when empty. | |
| 37 | - | Visibility domain.Visibility | |
| 38 | - | } | |
| 39 | - | ||
| 40 | 34 | // Create makes a repository and publishes RepoCreated: it stages a bare repository, records the | |
| 41 | 35 | // metadata (which fails with domain.ErrAlreadyExists if the name is taken, | |
| 42 | 36 | // also when a concurrent Create wins) and publishes the directory. A failure | |
| @@ -45,7 +39,7 @@ type CreateParams struct { | |||
| 45 | 39 | // | |
| 46 | 40 | // The principal needs repo:write on the name: anonymous callers get | |
| 47 | 41 | // domain.ErrUnauthenticated, other callers without it domain.ErrForbidden. | |
| 48 | - | func (r *Repos) Create(ctx context.Context, p domain.Principal, params CreateParams) (domain.Repo, error) { | |
| 42 | + | func (r *Repos) Create(ctx context.Context, p domain.Principal, params ports.CreateRepoParams) (domain.Repo, error) { | |
| 49 | 43 | if params.Name.IsZero() { | |
| 50 | 44 | return domain.Repo{}, fmt.Errorf("%w: empty name", domain.ErrInvalidName) | |
| 51 | 45 | } | |
M internal/app/repos_integration_test.go +2 -1
| @@ -20,6 +20,7 @@ import ( | |||
| 20 | 20 | "bnema.dev/ermite/internal/adapters/kvstore" | |
| 21 | 21 | "bnema.dev/ermite/internal/app" | |
| 22 | 22 | "bnema.dev/ermite/internal/domain" | |
| 23 | + | "bnema.dev/ermite/internal/ports" | |
| 23 | 24 | ) | |
| 24 | 25 | ||
| 25 | 26 | type fixedClock struct{} | |
| @@ -56,7 +57,7 @@ func TestCreateConcurrentSameNameRealAdapters(t *testing.T) { | |||
| 56 | 57 | wg.Add(1) | |
| 57 | 58 | go func() { | |
| 58 | 59 | defer wg.Done() | |
| 59 | - | _, err := repos.Create(ctx, domain.Root(), app.CreateParams{Name: n}) | |
| 60 | + | _, err := repos.Create(ctx, domain.Root(), ports.CreateRepoParams{Name: n}) | |
| 60 | 61 | errs <- err | |
| 61 | 62 | }() | |
| 62 | 63 | } | |
M internal/app/repos_test.go +11 -11
| @@ -63,7 +63,7 @@ func TestCreate(t *testing.T) { | |||
| 63 | 63 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(nil) | |
| 64 | 64 | f.bus.EXPECT().Publish(ctx, domain.RepoCreated{Repo: n, Visibility: domain.VisibilityPrivate, At: now}).Return().Once() | |
| 65 | 65 | ||
| 66 | - | got, err := f.repos.Create(ctx, domain.Root(), app.CreateParams{Name: n, Description: "d"}) | |
| 66 | + | got, err := f.repos.Create(ctx, domain.Root(), ports.CreateRepoParams{Name: n, Description: "d"}) | |
| 67 | 67 | require.NoError(t, err) | |
| 68 | 68 | assert.Equal(t, want, got) | |
| 69 | 69 | }) | |
| @@ -71,7 +71,7 @@ func TestCreate(t *testing.T) { | |||
| 71 | 71 | t.Run("anonymous is refused before anything runs", func(t *testing.T) { | |
| 72 | 72 | t.Parallel() | |
| 73 | 73 | f := newFixture(t) | |
| 74 | - | _, err := f.repos.Create(ctx, domain.Anonymous(), app.CreateParams{Name: name(t, "tools")}) | |
| 74 | + | _, err := f.repos.Create(ctx, domain.Anonymous(), ports.CreateRepoParams{Name: name(t, "tools")}) | |
| 75 | 75 | assert.ErrorIs(t, err, domain.ErrUnauthenticated) | |
| 76 | 76 | }) | |
| 77 | 77 | ||
| @@ -81,7 +81,7 @@ func TestCreate(t *testing.T) { | |||
| 81 | 81 | tokenPrincipal(domain.ScopeRepoWrite, "other"), | |
| 82 | 82 | } { | |
| 83 | 83 | f := newFixture(t) | |
| 84 | - | _, err := f.repos.Create(ctx, p, app.CreateParams{Name: name(t, "tools")}) | |
| 84 | + | _, err := f.repos.Create(ctx, p, ports.CreateRepoParams{Name: name(t, "tools")}) | |
| 85 | 85 | assert.ErrorIs(t, err, domain.ErrForbidden) | |
| 86 | 86 | } | |
| 87 | 87 | }) | |
| @@ -94,21 +94,21 @@ func TestCreate(t *testing.T) { | |||
| 94 | 94 | f.meta.EXPECT().Create(ctx, mock.Anything).Return(nil) | |
| 95 | 95 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(nil) | |
| 96 | 96 | f.bus.EXPECT().Publish(ctx, mock.Anything).Return().Once() | |
| 97 | - | _, err := f.repos.Create(ctx, tokenPrincipal(domain.ScopeRepoWrite, "tools"), app.CreateParams{Name: n}) | |
| 97 | + | _, err := f.repos.Create(ctx, tokenPrincipal(domain.ScopeRepoWrite, "tools"), ports.CreateRepoParams{Name: n}) | |
| 98 | 98 | require.NoError(t, err) | |
| 99 | 99 | }) | |
| 100 | 100 | ||
| 101 | 101 | t.Run("zero name is invalid", func(t *testing.T) { | |
| 102 | 102 | t.Parallel() | |
| 103 | 103 | f := newFixture(t) | |
| 104 | - | _, err := f.repos.Create(ctx, domain.Root(), app.CreateParams{}) | |
| 104 | + | _, err := f.repos.Create(ctx, domain.Root(), ports.CreateRepoParams{}) | |
| 105 | 105 | assert.ErrorIs(t, err, domain.ErrInvalidName) | |
| 106 | 106 | }) | |
| 107 | 107 | ||
| 108 | 108 | t.Run("unknown visibility is invalid", func(t *testing.T) { | |
| 109 | 109 | t.Parallel() | |
| 110 | 110 | f := newFixture(t) | |
| 111 | - | _, err := f.repos.Create(ctx, domain.Root(), app.CreateParams{Name: name(t, "tools"), Visibility: "secret"}) | |
| 111 | + | _, err := f.repos.Create(ctx, domain.Root(), ports.CreateRepoParams{Name: name(t, "tools"), Visibility: "secret"}) | |
| 112 | 112 | assert.ErrorIs(t, err, domain.ErrInvalidVisibility) | |
| 113 | 113 | }) | |
| 114 | 114 | ||
| @@ -116,7 +116,7 @@ func TestCreate(t *testing.T) { | |||
| 116 | 116 | t.Parallel() | |
| 117 | 117 | f := newFixture(t) | |
| 118 | 118 | f.git.EXPECT().Stage(ctx).Return("", errBoom) | |
| 119 | - | _, err := f.repos.Create(ctx, domain.Root(), app.CreateParams{Name: name(t, "tools")}) | |
| 119 | + | _, err := f.repos.Create(ctx, domain.Root(), ports.CreateRepoParams{Name: name(t, "tools")}) | |
| 120 | 120 | assert.ErrorIs(t, err, errBoom) | |
| 121 | 121 | }) | |
| 122 | 122 | ||
| @@ -126,7 +126,7 @@ func TestCreate(t *testing.T) { | |||
| 126 | 126 | f.git.EXPECT().Stage(ctx).Return(ports.StagedID("s1"), nil) | |
| 127 | 127 | f.meta.EXPECT().Create(ctx, mock.Anything).Return(domain.ErrAlreadyExists) | |
| 128 | 128 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).Return(nil) | |
| 129 | - | _, err := f.repos.Create(ctx, domain.Root(), app.CreateParams{Name: name(t, "tools")}) | |
| 129 | + | _, err := f.repos.Create(ctx, domain.Root(), ports.CreateRepoParams{Name: name(t, "tools")}) | |
| 130 | 130 | assert.ErrorIs(t, err, domain.ErrAlreadyExists) | |
| 131 | 131 | }) | |
| 132 | 132 | ||
| @@ -139,7 +139,7 @@ func TestCreate(t *testing.T) { | |||
| 139 | 139 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(domain.ErrAlreadyExists) | |
| 140 | 140 | f.meta.EXPECT().Delete(mock.Anything, n).Return(nil) | |
| 141 | 141 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).Return(nil) | |
| 142 | - | _, err := f.repos.Create(ctx, domain.Root(), app.CreateParams{Name: n}) | |
| 142 | + | _, err := f.repos.Create(ctx, domain.Root(), ports.CreateRepoParams{Name: n}) | |
| 143 | 143 | assert.ErrorIs(t, err, domain.ErrAlreadyExists) | |
| 144 | 144 | }) | |
| 145 | 145 | ||
| @@ -152,7 +152,7 @@ func TestCreate(t *testing.T) { | |||
| 152 | 152 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(errBoom) | |
| 153 | 153 | f.meta.EXPECT().Delete(mock.Anything, n).Return(nil) | |
| 154 | 154 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).Return(nil) | |
| 155 | - | _, err := f.repos.Create(ctx, domain.Root(), app.CreateParams{Name: n}) | |
| 155 | + | _, err := f.repos.Create(ctx, domain.Root(), ports.CreateRepoParams{Name: n}) | |
| 156 | 156 | assert.ErrorIs(t, err, errBoom) | |
| 157 | 157 | }) | |
| 158 | 158 | ||
| @@ -174,7 +174,7 @@ func TestCreate(t *testing.T) { | |||
| 174 | 174 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).RunAndReturn(func(c context.Context, _ ports.StagedID) error { | |
| 175 | 175 | return c.Err() | |
| 176 | 176 | }) | |
| 177 | - | _, err := f.repos.Create(cctx, domain.Root(), app.CreateParams{Name: n}) | |
| 177 | + | _, err := f.repos.Create(cctx, domain.Root(), ports.CreateRepoParams{Name: n}) | |
| 178 | 178 | assert.ErrorIs(t, err, errBoom) | |
| 179 | 179 | }) | |
| 180 | 180 | } | |
M internal/app/repos_write.go +6 -25
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/bnema/zerowrap" | |
| 13 | 13 | ||
| 14 | 14 | "bnema.dev/ermite/internal/domain" | |
| 15 | + | "bnema.dev/ermite/internal/ports" | |
| 15 | 16 | ) | |
| 16 | 17 | ||
| 17 | 18 | // MaxDescriptionLen is the longest repository description, in bytes. | |
| @@ -33,34 +34,14 @@ func validateDescription(s string) error { | |||
| 33 | 34 | return nil | |
| 34 | 35 | } | |
| 35 | 36 | ||
| 36 | - | // RepoView is a repository with the Git state that belongs in its summary. | |
| 37 | - | type RepoView struct { | |
| 38 | - | domain.Repo | |
| 39 | - | // DefaultBranch is the branch HEAD points to, even when it does not exist | |
| 40 | - | // yet; empty when HEAD is detached or the directory is missing. | |
| 41 | - | DefaultBranch string | |
| 42 | - | } | |
| 43 | - | ||
| 44 | 37 | // View adds the default branch to a repository the caller has already been | |
| 45 | 38 | // allowed to see. A repository without a directory has no default branch. | |
| 46 | - | func (r *Repos) View(ctx context.Context, repo domain.Repo) (RepoView, error) { | |
| 39 | + | func (r *Repos) View(ctx context.Context, repo domain.Repo) (ports.RepoView, error) { | |
| 47 | 40 | branch, err := r.git.HeadBranch(ctx, repo.Name) | |
| 48 | 41 | if err != nil && !errors.Is(err, domain.ErrNotFound) { | |
| 49 | - | return RepoView{}, fmt.Errorf("read default branch of %q: %w", repo.Name, err) | |
| 42 | + | return ports.RepoView{}, fmt.Errorf("read default branch of %q: %w", repo.Name, err) | |
| 50 | 43 | } | |
| 51 | - | return RepoView{Repo: repo, DefaultBranch: branch}, nil | |
| 52 | - | } | |
| 53 | - | ||
| 54 | - | // UpdateParams are the changes of Update; a nil field is left alone. | |
| 55 | - | type UpdateParams struct { | |
| 56 | - | Description *string | |
| 57 | - | Visibility *domain.Visibility | |
| 58 | - | DefaultBranch *string | |
| 59 | - | // AllowedMergeModes replaces the allowed merge modes; it must hold at | |
| 60 | - | // least one known mode. | |
| 61 | - | AllowedMergeModes *[]domain.MergeMode | |
| 62 | - | // FailingChecksBlock replaces the setting of that name. | |
| 63 | - | FailingChecksBlock *bool | |
| 44 | + | return ports.RepoView{Repo: repo, DefaultBranch: branch}, nil | |
| 64 | 45 | } | |
| 65 | 46 | ||
| 66 | 47 | // Update changes the description, the visibility, the default branch and the | |
| @@ -71,7 +52,7 @@ type UpdateParams struct { | |||
| 71 | 52 | // The metadata is written first, then HEAD, and RepoUpdated is published after | |
| 72 | 53 | // both. When only the HEAD move fails, RepoUpdated is still published for the | |
| 73 | 54 | // stored metadata and the HEAD error is returned. | |
| 74 | - | func (r *Repos) Update(ctx context.Context, p domain.Principal, name domain.RepoName, params UpdateParams) (domain.Repo, error) { | |
| 55 | + | func (r *Repos) Update(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.UpdateRepoParams) (domain.Repo, error) { | |
| 75 | 56 | repo, err := lookupRepo(ctx, r.meta, name) | |
| 76 | 57 | if err != nil { | |
| 77 | 58 | return domain.Repo{}, err | |
| @@ -158,7 +139,7 @@ func (r *Repos) Update(ctx context.Context, p domain.Principal, name domain.Repo | |||
| 158 | 139 | ||
| 159 | 140 | // updateMeta applies the metadata fields, retrying when a write (a push | |
| 160 | 141 | // recording pushed_at) gets in between. | |
| 161 | - | func (r *Repos) updateMeta(ctx context.Context, name domain.RepoName, params UpdateParams) (domain.Repo, error) { | |
| 142 | + | func (r *Repos) updateMeta(ctx context.Context, name domain.RepoName, params ports.UpdateRepoParams) (domain.Repo, error) { | |
| 162 | 143 | for range pushRetries { | |
| 163 | 144 | repo, err := r.meta.Get(ctx, name) | |
| 164 | 145 | if err != nil { | |
M internal/app/repos_write_test.go +11 -10
| @@ -15,6 +15,7 @@ import ( | |||
| 15 | 15 | ||
| 16 | 16 | "bnema.dev/ermite/internal/app" | |
| 17 | 17 | "bnema.dev/ermite/internal/domain" | |
| 18 | + | "bnema.dev/ermite/internal/ports" | |
| 18 | 19 | ) | |
| 19 | 20 | ||
| 20 | 21 | func ptr[T any](v T) *T { return &v } | |
| @@ -36,7 +37,7 @@ func TestUpdate(t *testing.T) { | |||
| 36 | 37 | Repo: n, At: now, Visibility: domain.VisibilityPublic, Previous: domain.VisibilityPrivate, | |
| 37 | 38 | }).Return().Once() | |
| 38 | 39 | ||
| 39 | - | got, err := f.repos.Update(ctx, admin, n, app.UpdateParams{ | |
| 40 | + | got, err := f.repos.Update(ctx, admin, n, ports.UpdateRepoParams{ | |
| 40 | 41 | Description: ptr("new"), Visibility: ptr(domain.VisibilityPublic), | |
| 41 | 42 | }) | |
| 42 | 43 | require.NoError(t, err) | |
| @@ -50,7 +51,7 @@ func TestUpdate(t *testing.T) { | |||
| 50 | 51 | f.meta.EXPECT().Update(ctx, mock.Anything).Return(domain.ErrConflict).Once() | |
| 51 | 52 | f.meta.EXPECT().Update(ctx, mock.Anything).Return(nil).Once() | |
| 52 | 53 | f.bus.EXPECT().Publish(ctx, mock.Anything).Return().Once() | |
| 53 | - | _, err := f.repos.Update(ctx, admin, n, app.UpdateParams{Description: ptr("x")}) | |
| 54 | + | _, err := f.repos.Update(ctx, admin, n, ports.UpdateRepoParams{Description: ptr("x")}) | |
| 54 | 55 | require.NoError(t, err) | |
| 55 | 56 | }) | |
| 56 | 57 | ||
| @@ -61,7 +62,7 @@ func TestUpdate(t *testing.T) { | |||
| 61 | 62 | f.git.EXPECT().HasBranch(ctx, n, "dev").Return(true, nil) | |
| 62 | 63 | f.git.EXPECT().SetDefaultBranch(ctx, n, "dev").Return(nil) | |
| 63 | 64 | f.bus.EXPECT().Publish(ctx, mock.Anything).Return().Once() | |
| 64 | - | got, err := f.repos.Update(ctx, admin, n, app.UpdateParams{DefaultBranch: ptr("dev")}) | |
| 65 | + | got, err := f.repos.Update(ctx, admin, n, ports.UpdateRepoParams{DefaultBranch: ptr("dev")}) | |
| 65 | 66 | require.NoError(t, err) | |
| 66 | 67 | assert.Equal(t, priv, got) | |
| 67 | 68 | }) | |
| @@ -81,7 +82,7 @@ func TestUpdate(t *testing.T) { | |||
| 81 | 82 | return nil | |
| 82 | 83 | }) | |
| 83 | 84 | f.bus.EXPECT().Publish(ctx, mock.Anything).Run(func(context.Context, domain.Event) { order = append(order, "event") }).Return().Once() | |
| 84 | - | _, err := f.repos.Update(ctx, admin, n, app.UpdateParams{Description: ptr("x"), DefaultBranch: ptr("dev")}) | |
| 85 | + | _, err := f.repos.Update(ctx, admin, n, ports.UpdateRepoParams{Description: ptr("x"), DefaultBranch: ptr("dev")}) | |
| 85 | 86 | require.NoError(t, err) | |
| 86 | 87 | assert.Equal(t, []string{"meta", "head", "event"}, order) | |
| 87 | 88 | }) | |
| @@ -98,7 +99,7 @@ func TestUpdate(t *testing.T) { | |||
| 98 | 99 | f.bus.EXPECT().Publish(ctx, domain.RepoUpdated{ | |
| 99 | 100 | Repo: n, At: now, Visibility: domain.VisibilityPrivate, Previous: domain.VisibilityPublic, | |
| 100 | 101 | }).Return().Once() | |
| 101 | - | _, err := f.repos.Update(ctx, admin, n, app.UpdateParams{Visibility: ptr(domain.VisibilityPrivate), DefaultBranch: ptr("dev")}) | |
| 102 | + | _, err := f.repos.Update(ctx, admin, n, ports.UpdateRepoParams{Visibility: ptr(domain.VisibilityPrivate), DefaultBranch: ptr("dev")}) | |
| 102 | 103 | assert.ErrorIs(t, err, boom) | |
| 103 | 104 | }) | |
| 104 | 105 | ||
| @@ -109,7 +110,7 @@ func TestUpdate(t *testing.T) { | |||
| 109 | 110 | f.meta.EXPECT().Get(ctx, n).Return(priv, nil) | |
| 110 | 111 | f.git.EXPECT().HasBranch(ctx, n, "dev").Return(true, nil) | |
| 111 | 112 | f.git.EXPECT().SetDefaultBranch(ctx, n, "dev").Return(boom) | |
| 112 | - | _, err := f.repos.Update(ctx, admin, n, app.UpdateParams{DefaultBranch: ptr("dev")}) | |
| 113 | + | _, err := f.repos.Update(ctx, admin, n, ports.UpdateRepoParams{DefaultBranch: ptr("dev")}) | |
| 113 | 114 | assert.ErrorIs(t, err, boom) | |
| 114 | 115 | }) | |
| 115 | 116 | ||
| @@ -118,12 +119,12 @@ func TestUpdate(t *testing.T) { | |||
| 118 | 119 | f := newFixture(t) | |
| 119 | 120 | f.meta.EXPECT().Get(ctx, n).Return(priv, nil) | |
| 120 | 121 | f.git.EXPECT().HasBranch(ctx, n, "nope").Return(false, nil) | |
| 121 | - | _, err := f.repos.Update(ctx, admin, n, app.UpdateParams{Description: ptr("x"), DefaultBranch: ptr("nope")}) | |
| 122 | + | _, err := f.repos.Update(ctx, admin, n, ports.UpdateRepoParams{Description: ptr("x"), DefaultBranch: ptr("nope")}) | |
| 122 | 123 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | |
| 123 | 124 | }) | |
| 124 | 125 | ||
| 125 | 126 | t.Run("invalid input changes nothing", func(t *testing.T) { | |
| 126 | - | for name, params := range map[string]app.UpdateParams{ | |
| 127 | + | for name, params := range map[string]ports.UpdateRepoParams{ | |
| 127 | 128 | "empty": {}, | |
| 128 | 129 | "empty branch": {DefaultBranch: ptr("")}, | |
| 129 | 130 | "multi-line": {Description: ptr("a\nb")}, | |
| @@ -157,7 +158,7 @@ func TestUpdate(t *testing.T) { | |||
| 157 | 158 | t.Parallel() | |
| 158 | 159 | f := newFixture(t) | |
| 159 | 160 | f.meta.EXPECT().Get(ctx, n).Return(tt.repo, nil) | |
| 160 | - | _, err := f.repos.Update(ctx, tt.p, n, app.UpdateParams{Description: ptr("x")}) | |
| 161 | + | _, err := f.repos.Update(ctx, tt.p, n, ports.UpdateRepoParams{Description: ptr("x")}) | |
| 161 | 162 | assert.ErrorIs(t, err, tt.want) | |
| 162 | 163 | err = f.repos.Delete(ctx, tt.p, n) | |
| 163 | 164 | assert.ErrorIs(t, err, tt.want) | |
| @@ -168,7 +169,7 @@ func TestUpdate(t *testing.T) { | |||
| 168 | 169 | t.Parallel() | |
| 169 | 170 | f := newFixture(t) | |
| 170 | 171 | f.meta.EXPECT().Get(ctx, n).Return(domain.Repo{}, domain.ErrNotFound) | |
| 171 | - | _, err := f.repos.Update(ctx, domain.Root(), n, app.UpdateParams{Description: ptr("x")}) | |
| 172 | + | _, err := f.repos.Update(ctx, domain.Root(), n, ports.UpdateRepoParams{Description: ptr("x")}) | |
| 172 | 173 | assert.ErrorIs(t, err, domain.ErrNotFound) | |
| 173 | 174 | }) | |
| 174 | 175 | } | |
M internal/app/sessions.go +7 -12
| @@ -39,13 +39,6 @@ const ( | |||
| 39 | 39 | LoginPath = "/-/login/" | |
| 40 | 40 | ) | |
| 41 | 41 | ||
| 42 | - | // LoginLink is a login link as the owner receives it. | |
| 43 | - | type LoginLink struct { | |
| 44 | - | // URL holds the secret: show it once, never log it. | |
| 45 | - | URL string | |
| 46 | - | ExpiresAt time.Time | |
| 47 | - | } | |
| 48 | - | ||
| 49 | 42 | // Sessions are the use cases of the owner's browser sessions: login links, | |
| 50 | 43 | // session tokens and signing out everywhere. Login links live in memory only, | |
| 51 | 44 | // so a restart voids them; the signing key and the epoch are in the store. | |
| @@ -59,6 +52,8 @@ type Sessions struct { | |||
| 59 | 52 | links map[[sha256.Size]byte]pendingLink // by hash of the nonce | |
| 60 | 53 | } | |
| 61 | 54 | ||
| 55 | + | var _ ports.SessionService = (*Sessions)(nil) | |
| 56 | + | ||
| 62 | 57 | // pendingLink is a login link that waits to be used. | |
| 63 | 58 | type pendingLink struct { | |
| 64 | 59 | expires time.Time | |
| @@ -95,13 +90,13 @@ func requireOwner(p domain.Principal) error { | |||
| 95 | 90 | // created it: it is capped at that token's expiry (no cap for root, or a token | |
| 96 | 91 | // that never expires). It gives domain.ErrResourceExhausted when MaxPendingLoginLinks | |
| 97 | 92 | // links wait. The nonce is never logged. | |
| 98 | - | func (s *Sessions) CreateLoginLink(ctx context.Context, p domain.Principal) (LoginLink, error) { | |
| 93 | + | func (s *Sessions) CreateLoginLink(ctx context.Context, p domain.Principal) (ports.LoginLink, error) { | |
| 99 | 94 | if err := requireOwner(p); err != nil { | |
| 100 | - | return LoginLink{}, err | |
| 95 | + | return ports.LoginLink{}, err | |
| 101 | 96 | } | |
| 102 | 97 | var raw [loginNonceBytes]byte | |
| 103 | 98 | if _, err := rand.Read(raw[:]); err != nil { | |
| 104 | - | return LoginLink{}, fmt.Errorf("generate login link: %w", err) | |
| 99 | + | return ports.LoginLink{}, fmt.Errorf("generate login link: %w", err) | |
| 105 | 100 | } | |
| 106 | 101 | nonce := base64.RawURLEncoding.EncodeToString(raw[:]) | |
| 107 | 102 | now := s.clock.Now() | |
| @@ -115,14 +110,14 @@ func (s *Sessions) CreateLoginLink(ctx context.Context, p domain.Principal) (Log | |||
| 115 | 110 | } | |
| 116 | 111 | if len(s.links) >= MaxPendingLoginLinks { | |
| 117 | 112 | s.mu.Unlock() | |
| 118 | - | return LoginLink{}, fmt.Errorf("%w: %d login links are already pending, use one or wait a minute", domain.ErrResourceExhausted, MaxPendingLoginLinks) | |
| 113 | + | return ports.LoginLink{}, fmt.Errorf("%w: %d login links are already pending, use one or wait a minute", domain.ErrResourceExhausted, MaxPendingLoginLinks) | |
| 119 | 114 | } | |
| 120 | 115 | s.links[sha256.Sum256([]byte(nonce))] = pendingLink{expires: exp, sessionCap: p.ExpiresAt()} | |
| 121 | 116 | s.mu.Unlock() | |
| 122 | 117 | ||
| 123 | 118 | log := zerowrap.FromCtx(ctx) | |
| 124 | 119 | log.Info().Str("created_by", p.Label()).Str("created_by_token", p.TokenID()).Time("expires_at", exp).Msg("login link created") | |
| 125 | - | return LoginLink{URL: s.publicURL + LoginPath + nonce, ExpiresAt: exp.UTC()}, nil | |
| 120 | + | return ports.LoginLink{URL: s.publicURL + LoginPath + nonce, ExpiresAt: exp.UTC()}, nil | |
| 126 | 121 | } | |
| 127 | 122 | ||
| 128 | 123 | // LoginLinkValid reports whether the nonce is a pending link, without using | |
M internal/app/signing.go +2 -0
| @@ -14,6 +14,8 @@ type SigningKey struct { | |||
| 14 | 14 | committer domain.Identity | |
| 15 | 15 | } | |
| 16 | 16 | ||
| 17 | + | var _ ports.SigningKeyService = (*SigningKey)(nil) | |
| 18 | + | ||
| 17 | 19 | // NewSigningKey builds the use case over the signer and the identity recorded | |
| 18 | 20 | // as the committer of the signed commits. | |
| 19 | 21 | func NewSigningKey(signer ports.CommitSigner, committer domain.Identity) *SigningKey { | |
M internal/app/tokens.go +16 -27
| @@ -40,30 +40,14 @@ type Tokens struct { | |||
| 40 | 40 | sessions ports.SessionStore | |
| 41 | 41 | } | |
| 42 | 42 | ||
| 43 | + | var _ ports.TokenService = (*Tokens)(nil) | |
| 44 | + | ||
| 43 | 45 | // NewTokens builds the token use cases over their ports. sessions is where | |
| 44 | 46 | // revoking a token with owner rights ends every web session (see Revoke). | |
| 45 | 47 | func NewTokens(store ports.TokenStore, clock ports.Clock, sessions ports.SessionStore) *Tokens { | |
| 46 | 48 | return &Tokens{store: store, clock: clock, sessions: sessions} | |
| 47 | 49 | } | |
| 48 | 50 | ||
| 49 | - | // CreateTokenParams are the settings of a new token. | |
| 50 | - | type CreateTokenParams struct { | |
| 51 | - | Label string | |
| 52 | - | // Scopes must not be empty. | |
| 53 | - | Scopes []domain.Scope | |
| 54 | - | // Repos limits the token to these repositories; empty means every one. | |
| 55 | - | Repos []domain.RepoName | |
| 56 | - | // ExpiresAt is the zero time for a token that never expires. | |
| 57 | - | ExpiresAt time.Time | |
| 58 | - | } | |
| 59 | - | ||
| 60 | - | // CreatedToken is a new token with its secret, which is shown once and never | |
| 61 | - | // stored. | |
| 62 | - | type CreatedToken struct { | |
| 63 | - | Token domain.Token | |
| 64 | - | Secret string | |
| 65 | - | } | |
| 66 | - | ||
| 67 | 51 | // Create makes a stored token and returns it with its secret. | |
| 68 | 52 | // | |
| 69 | 53 | // The principal needs token:admin: anonymous callers get | |
| @@ -75,20 +59,20 @@ type CreatedToken struct { | |||
| 75 | 59 | // domain.ErrInvalidToken (this includes the labels "owner" and "root", which | |
| 76 | 60 | // are reserved, in any case and around spaces), an unknown scope | |
| 77 | 61 | // domain.ErrInvalidScope. | |
| 78 | - | func (t *Tokens) Create(ctx context.Context, p domain.Principal, params CreateTokenParams) (CreatedToken, error) { | |
| 62 | + | func (t *Tokens) Create(ctx context.Context, p domain.Principal, params ports.CreateTokenParams) (ports.CreatedToken, error) { | |
| 79 | 63 | if p.IsAnonymous() { | |
| 80 | - | return CreatedToken{}, domain.ErrUnauthenticated | |
| 64 | + | return ports.CreatedToken{}, domain.ErrUnauthenticated | |
| 81 | 65 | } | |
| 82 | 66 | if !canManageTokens(p) { | |
| 83 | - | return CreatedToken{}, fmt.Errorf("%w: creating tokens needs %s", domain.ErrForbidden, domain.ScopeTokenAdmin) | |
| 67 | + | return ports.CreatedToken{}, fmt.Errorf("%w: creating tokens needs %s", domain.ErrForbidden, domain.ScopeTokenAdmin) | |
| 84 | 68 | } | |
| 85 | 69 | now := t.clock.Now().UTC() | |
| 86 | 70 | tok, err := buildToken(params, now) | |
| 87 | 71 | if err != nil { | |
| 88 | - | return CreatedToken{}, err | |
| 72 | + | return ports.CreatedToken{}, err | |
| 89 | 73 | } | |
| 90 | 74 | if err := checkNoEscalation(p, tok); err != nil { | |
| 91 | - | return CreatedToken{}, err | |
| 75 | + | return ports.CreatedToken{}, err | |
| 92 | 76 | } | |
| 93 | 77 | ||
| 94 | 78 | for range 3 { | |
| @@ -99,7 +83,7 @@ func (t *Tokens) Create(ctx context.Context, p domain.Principal, params CreateTo | |||
| 99 | 83 | continue // a random id or secret collided: practically never | |
| 100 | 84 | } | |
| 101 | 85 | if err != nil { | |
| 102 | - | return CreatedToken{}, fmt.Errorf("store token: %w", err) | |
| 86 | + | return ports.CreatedToken{}, fmt.Errorf("store token: %w", err) | |
| 103 | 87 | } | |
| 104 | 88 | log := zerowrap.FromCtx(ctx) | |
| 105 | 89 | log.Info(). | |
| @@ -107,13 +91,13 @@ func (t *Tokens) Create(ctx context.Context, p domain.Principal, params CreateTo | |||
| 107 | 91 | Int("scopes", len(tok.Scopes)).Int("repos", len(tok.Repos)). | |
| 108 | 92 | Str("created_by", p.Label()).Str("created_by_token", p.TokenID()). | |
| 109 | 93 | Msg("token created") | |
| 110 | - | return CreatedToken{Token: tok, Secret: secret}, nil | |
| 94 | + | return ports.CreatedToken{Token: tok, Secret: secret}, nil | |
| 111 | 95 | } | |
| 112 | - | return CreatedToken{}, errors.New("store token: could not find a free id") | |
| 96 | + | return ports.CreatedToken{}, errors.New("store token: could not find a free id") | |
| 113 | 97 | } | |
| 114 | 98 | ||
| 115 | 99 | // buildToken validates the settings and returns the token without id and hash. | |
| 116 | - | func buildToken(params CreateTokenParams, now time.Time) (domain.Token, error) { | |
| 100 | + | func buildToken(params ports.CreateTokenParams, now time.Time) (domain.Token, error) { | |
| 117 | 101 | if params.Label == "" || len(params.Label) > MaxTokenLabelLen || !utf8.ValidString(params.Label) { | |
| 118 | 102 | return domain.Token{}, fmt.Errorf("%w: label must be 1 to %d bytes of UTF-8", domain.ErrInvalidToken, MaxTokenLabelLen) | |
| 119 | 103 | } | |
| @@ -274,6 +258,11 @@ type Auth struct { | |||
| 274 | 258 | clock ports.Clock | |
| 275 | 259 | } | |
| 276 | 260 | ||
| 261 | + | var ( | |
| 262 | + | _ ports.AuthService = (*Auth)(nil) | |
| 263 | + | _ ports.Revalidator = (*Auth)(nil) | |
| 264 | + | ) | |
| 265 | + | ||
| 277 | 266 | // NewAuth builds the authentication use case. rootHash is the SHA-256 of the | |
| 278 | 267 | // admin token. | |
| 279 | 268 | func NewAuth(rootHash domain.TokenHash, tokens ports.TokenStore, clock ports.Clock) *Auth { | |
M internal/app/tokens_test.go +35 -34
| @@ -16,6 +16,7 @@ import ( | |||
| 16 | 16 | ||
| 17 | 17 | "bnema.dev/ermite/internal/app" | |
| 18 | 18 | "bnema.dev/ermite/internal/domain" | |
| 19 | + | "bnema.dev/ermite/internal/ports" | |
| 19 | 20 | "bnema.dev/ermite/internal/ports/mocks" | |
| 20 | 21 | ) | |
| 21 | 22 | ||
| @@ -65,7 +66,7 @@ func TestTokensCreateAllowsLabelsNearReserved(t *testing.T) { | |||
| 65 | 66 | t.Parallel() | |
| 66 | 67 | f := newTokenFixture(t) | |
| 67 | 68 | f.store.EXPECT().Create(ctx, mock.Anything).Return(nil) | |
| 68 | - | _, err := f.tokens.Create(ctx, domain.Root(), app.CreateTokenParams{Label: tt.label, Scopes: scopes(domain.ScopeRepoRead)}) | |
| 69 | + | _, err := f.tokens.Create(ctx, domain.Root(), ports.CreateTokenParams{Label: tt.label, Scopes: scopes(domain.ScopeRepoRead)}) | |
| 69 | 70 | assert.NoError(t, err) | |
| 70 | 71 | }) | |
| 71 | 72 | } | |
| @@ -82,7 +83,7 @@ func TestTokensCreate(t *testing.T) { | |||
| 82 | 83 | f.store.EXPECT().Create(ctx, mock.Anything).Run(func(_ context.Context, tok domain.Token) { stored = tok }).Return(nil) | |
| 83 | 84 | ||
| 84 | 85 | exp := now.Add(48 * time.Hour) | |
| 85 | - | got, err := f.tokens.Create(ctx, domain.Root(), app.CreateTokenParams{ | |
| 86 | + | got, err := f.tokens.Create(ctx, domain.Root(), ports.CreateTokenParams{ | |
| 86 | 87 | Label: "ci", | |
| 87 | 88 | Scopes: scopes(domain.ScopeRepoWrite, domain.ScopeRepoRead, domain.ScopeRepoRead), | |
| 88 | 89 | Repos: names(t, "b", "a", "b"), | |
| @@ -109,9 +110,9 @@ func TestTokensCreate(t *testing.T) { | |||
| 109 | 110 | t.Parallel() | |
| 110 | 111 | f := newTokenFixture(t) | |
| 111 | 112 | f.store.EXPECT().Create(ctx, mock.Anything).Return(nil) | |
| 112 | - | a, err := f.tokens.Create(ctx, domain.Root(), app.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 113 | + | a, err := f.tokens.Create(ctx, domain.Root(), ports.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 113 | 114 | require.NoError(t, err) | |
| 114 | - | b, err := f.tokens.Create(ctx, domain.Root(), app.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 115 | + | b, err := f.tokens.Create(ctx, domain.Root(), ports.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 115 | 116 | require.NoError(t, err) | |
| 116 | 117 | assert.NotEqual(t, a.Secret, b.Secret) | |
| 117 | 118 | assert.NotEqual(t, a.Token.ID, b.Token.ID) | |
| @@ -122,7 +123,7 @@ func TestTokensCreate(t *testing.T) { | |||
| 122 | 123 | f := newTokenFixture(t) | |
| 123 | 124 | f.store.EXPECT().Create(ctx, mock.Anything).Return(domain.ErrAlreadyExists).Once() | |
| 124 | 125 | f.store.EXPECT().Create(ctx, mock.Anything).Return(nil).Once() | |
| 125 | - | _, err := f.tokens.Create(ctx, domain.Root(), app.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 126 | + | _, err := f.tokens.Create(ctx, domain.Root(), ports.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 126 | 127 | require.NoError(t, err) | |
| 127 | 128 | }) | |
| 128 | 129 | ||
| @@ -131,27 +132,27 @@ func TestTokensCreate(t *testing.T) { | |||
| 131 | 132 | f := newTokenFixture(t) | |
| 132 | 133 | boom := errors.New("boom") | |
| 133 | 134 | f.store.EXPECT().Create(ctx, mock.Anything).Return(boom) | |
| 134 | - | _, err := f.tokens.Create(ctx, domain.Root(), app.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 135 | + | _, err := f.tokens.Create(ctx, domain.Root(), ports.CreateTokenParams{Label: "a", Scopes: scopes(domain.ScopeRepoRead)}) | |
| 135 | 136 | assert.ErrorIs(t, err, boom) | |
| 136 | 137 | }) | |
| 137 | 138 | ||
| 138 | 139 | invalid := []struct { | |
| 139 | 140 | name string | |
| 140 | - | params app.CreateTokenParams | |
| 141 | + | params ports.CreateTokenParams | |
| 141 | 142 | want error | |
| 142 | 143 | }{ | |
| 143 | - | {"empty label", app.CreateTokenParams{Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 144 | - | {"long label", app.CreateTokenParams{Label: strings.Repeat("x", 101), Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 145 | - | {"bad utf8 label", app.CreateTokenParams{Label: "\xff", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 146 | - | {"reserved owner", app.CreateTokenParams{Label: "owner", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 147 | - | {"reserved root", app.CreateTokenParams{Label: "root", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 148 | - | {"reserved, upper case", app.CreateTokenParams{Label: "OWNER", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 149 | - | {"reserved, mixed case", app.CreateTokenParams{Label: "Root", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 150 | - | {"reserved, padded", app.CreateTokenParams{Label: " \towner \n", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 151 | - | {"no scopes", app.CreateTokenParams{Label: "x"}, domain.ErrInvalidToken}, | |
| 152 | - | {"unknown scope", app.CreateTokenParams{Label: "x", Scopes: scopes("nope")}, domain.ErrInvalidScope}, | |
| 153 | - | {"past expiry", app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: now}, domain.ErrInvalidToken}, | |
| 154 | - | {"zero repo name", app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: []domain.RepoName{{}}}, domain.ErrInvalidToken}, | |
| 144 | + | {"empty label", ports.CreateTokenParams{Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 145 | + | {"long label", ports.CreateTokenParams{Label: strings.Repeat("x", 101), Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 146 | + | {"bad utf8 label", ports.CreateTokenParams{Label: "\xff", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 147 | + | {"reserved owner", ports.CreateTokenParams{Label: "owner", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 148 | + | {"reserved root", ports.CreateTokenParams{Label: "root", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 149 | + | {"reserved, upper case", ports.CreateTokenParams{Label: "OWNER", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 150 | + | {"reserved, mixed case", ports.CreateTokenParams{Label: "Root", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 151 | + | {"reserved, padded", ports.CreateTokenParams{Label: " \towner \n", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | |
| 152 | + | {"no scopes", ports.CreateTokenParams{Label: "x"}, domain.ErrInvalidToken}, | |
| 153 | + | {"unknown scope", ports.CreateTokenParams{Label: "x", Scopes: scopes("nope")}, domain.ErrInvalidScope}, | |
| 154 | + | {"past expiry", ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: now}, domain.ErrInvalidToken}, | |
| 155 | + | {"zero repo name", ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: []domain.RepoName{{}}}, domain.ErrInvalidToken}, | |
| 155 | 156 | } | |
| 156 | 157 | for _, tt := range invalid { | |
| 157 | 158 | t.Run("invalid/"+tt.name, func(t *testing.T) { | |
| @@ -179,37 +180,37 @@ func TestTokensCreateNoEscalation(t *testing.T) { | |||
| 179 | 180 | tests := []struct { | |
| 180 | 181 | name string | |
| 181 | 182 | principal domain.Principal | |
| 182 | - | params app.CreateTokenParams | |
| 183 | + | params ports.CreateTokenParams | |
| 183 | 184 | want error // nil = allowed | |
| 184 | 185 | }{ | |
| 185 | - | {"anonymous", domain.Anonymous(), app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrUnauthenticated}, | |
| 186 | + | {"anonymous", domain.Anonymous(), ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrUnauthenticated}, | |
| 186 | 187 | {"token without token:admin", | |
| 187 | 188 | domain.TokenPrincipal(domain.Token{Scopes: scopes(domain.ScopeRepoWrite)}), | |
| 188 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrForbidden}, | |
| 189 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrForbidden}, | |
| 189 | 190 | {"subset of scopes", admin(nil, time.Time{}), | |
| 190 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, nil}, | |
| 191 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, nil}, | |
| 191 | 192 | {"same scopes incl. token:admin", admin(nil, time.Time{}), | |
| 192 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeTokenAdmin, domain.ScopeRepoWrite)}, nil}, | |
| 193 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeTokenAdmin, domain.ScopeRepoWrite)}, nil}, | |
| 193 | 194 | {"scope it lacks", admin(nil, time.Time{}), | |
| 194 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead, domain.ScopeRepoAdmin)}, domain.ErrForbidden}, | |
| 195 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead, domain.ScopeRepoAdmin)}, domain.ErrForbidden}, | |
| 195 | 196 | {"limited creator, same repos", admin(names(t, "a", "b"), time.Time{}), | |
| 196 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: names(t, "a")}, nil}, | |
| 197 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: names(t, "a")}, nil}, | |
| 197 | 198 | {"limited creator, repo outside its list", admin(names(t, "a"), time.Time{}), | |
| 198 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: names(t, "a", "z")}, domain.ErrForbidden}, | |
| 199 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: names(t, "a", "z")}, domain.ErrForbidden}, | |
| 199 | 200 | {"limited creator, unlimited child", admin(names(t, "a"), time.Time{}), | |
| 200 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrForbidden}, | |
| 201 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrForbidden}, | |
| 201 | 202 | {"unlimited creator may limit", admin(nil, time.Time{}), | |
| 202 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: names(t, "z")}, nil}, | |
| 203 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: names(t, "z")}, nil}, | |
| 203 | 204 | {"expiring creator, child never expires", admin(nil, exp), | |
| 204 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrForbidden}, | |
| 205 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrForbidden}, | |
| 205 | 206 | {"expiring creator, child outlasts", admin(nil, exp), | |
| 206 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: exp.Add(time.Second)}, domain.ErrForbidden}, | |
| 207 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: exp.Add(time.Second)}, domain.ErrForbidden}, | |
| 207 | 208 | {"expiring creator, child within", admin(nil, exp), | |
| 208 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: exp.Add(-time.Second)}, nil}, | |
| 209 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: exp.Add(-time.Second)}, nil}, | |
| 209 | 210 | {"expiring creator, child same expiry", admin(nil, exp), | |
| 210 | - | app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: exp}, nil}, | |
| 211 | + | ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: exp}, nil}, | |
| 211 | 212 | {"root: everything", domain.Root(), | |
| 212 | - | app.CreateTokenParams{Label: "x", Scopes: domain.AllScopes()}, nil}, | |
| 213 | + | ports.CreateTokenParams{Label: "x", Scopes: domain.AllScopes()}, nil}, | |
| 213 | 214 | } | |
| 214 | 215 | for _, tt := range tests { | |
| 215 | 216 | t.Run(tt.name, func(t *testing.T) { | |
M internal/clientlimit/limiter.go +4 -0
| @@ -16,6 +16,8 @@ import ( | |||
| 16 | 16 | "time" | |
| 17 | 17 | ||
| 18 | 18 | "github.com/bnema/zerowrap" | |
| 19 | + | ||
| 20 | + | "bnema.dev/ermite/internal/ports" | |
| 19 | 21 | ) | |
| 20 | 22 | ||
| 21 | 23 | // Limiter defaults: 10 failed authentications in 10 minutes block the client | |
| @@ -54,6 +56,8 @@ type Limiter struct { | |||
| 54 | 56 | lastSweep time.Time | |
| 55 | 57 | } | |
| 56 | 58 | ||
| 59 | + | var _ ports.FailureLimiter = (*Limiter)(nil) | |
| 60 | + | ||
| 57 | 61 | // NewLimiter builds a limiter. now defaults to time.Now. | |
| 58 | 62 | func NewLimiter(now func() time.Time) *Limiter { | |
| 59 | 63 | if now == nil { | |
A internal/ports/dto.go +228 -0
| @@ -0,0 +1,228 @@ | |||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | + | ||
| 3 | + | package ports | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "time" | |
| 7 | + | ||
| 8 | + | "bnema.dev/ermite/internal/domain" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | // The parameters and results of the use case interfaces (services.go). They | |
| 12 | + | // live here so that the adapters that call the use cases and the use cases | |
| 13 | + | // themselves share them without importing each other. | |
| 14 | + | ||
| 15 | + | // RepoPage is a page of repositories ordered by name. | |
| 16 | + | type RepoPage struct { | |
| 17 | + | Repos []domain.Repo | |
| 18 | + | // NextPageToken is empty on the last page. | |
| 19 | + | NextPageToken string | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | // RepoView is a repository with the Git state that belongs in its summary. | |
| 23 | + | type RepoView struct { | |
| 24 | + | domain.Repo | |
| 25 | + | // DefaultBranch is the branch HEAD points to, even when it does not exist | |
| 26 | + | // yet; empty when HEAD is detached or the directory is missing. | |
| 27 | + | DefaultBranch string | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | // CreateRepoParams are the settings of a new repository. | |
| 31 | + | type CreateRepoParams struct { | |
| 32 | + | Name domain.RepoName | |
| 33 | + | Description string | |
| 34 | + | // Visibility defaults to private when empty. | |
| 35 | + | Visibility domain.Visibility | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | // UpdateRepoParams are the changes of Update; a nil field is left alone. | |
| 39 | + | type UpdateRepoParams struct { | |
| 40 | + | Description *string | |
| 41 | + | Visibility *domain.Visibility | |
| 42 | + | DefaultBranch *string | |
| 43 | + | // AllowedMergeModes replaces the allowed merge modes; it must hold at | |
| 44 | + | // least one known mode. | |
| 45 | + | AllowedMergeModes *[]domain.MergeMode | |
| 46 | + | // FailingChecksBlock replaces the setting of that name. | |
| 47 | + | FailingChecksBlock *bool | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // TokenPage is a page of stored tokens, newest first. | |
| 51 | + | type TokenPage struct { | |
| 52 | + | Tokens []domain.Token | |
| 53 | + | // NextPageToken is empty on the last page. | |
| 54 | + | NextPageToken string | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | // CreateTokenParams are the settings of a new token. | |
| 58 | + | type CreateTokenParams struct { | |
| 59 | + | Label string | |
| 60 | + | // Scopes must not be empty. | |
| 61 | + | Scopes []domain.Scope | |
| 62 | + | // Repos limits the token to these repositories; empty means every one. | |
| 63 | + | Repos []domain.RepoName | |
| 64 | + | // ExpiresAt is the zero time for a token that never expires. | |
| 65 | + | ExpiresAt time.Time | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // CreatedToken is a new token with its secret, which is shown once and never | |
| 69 | + | // stored. | |
| 70 | + | type CreatedToken struct { | |
| 71 | + | Token domain.Token | |
| 72 | + | Secret string | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | // ListRefsParams selects the refs to list. | |
| 76 | + | type ListRefsParams struct { | |
| 77 | + | // Kinds restricts the result; empty means every kind. | |
| 78 | + | Kinds []domain.RefKind | |
| 79 | + | // PageSize is 0 for the default, and lowered to MaxRefPageSize. | |
| 80 | + | PageSize int | |
| 81 | + | // PageToken is the NextPageToken of the previous page, or empty. | |
| 82 | + | PageToken string | |
| 83 | + | } | |
| 84 | + | ||
| 85 | + | // RefPage is a page of refs. | |
| 86 | + | type RefPage struct { | |
| 87 | + | Refs []domain.Ref | |
| 88 | + | // NextPageToken is empty on the last page. | |
| 89 | + | NextPageToken string | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | // ListCommitsParams selects a page of history. | |
| 93 | + | type ListCommitsParams struct { | |
| 94 | + | // Revision is where the history starts; the zero value is HEAD. Ignored | |
| 95 | + | // when PageToken is set: the token pins the commit the first page started | |
| 96 | + | // from, so every page walks the same history even if a branch moves. | |
| 97 | + | Revision domain.Revision | |
| 98 | + | // Path limits the history to the commits that changed it. It must be the | |
| 99 | + | // same on every page of a listing. | |
| 100 | + | Path domain.TreePath | |
| 101 | + | // PageSize is 0 for the default, and lowered to MaxPageSize. | |
| 102 | + | PageSize int | |
| 103 | + | // PageToken is the NextPageToken of the previous page, or empty. | |
| 104 | + | PageToken string | |
| 105 | + | } | |
| 106 | + | ||
| 107 | + | // HistoryPage is a page of history, newest first. | |
| 108 | + | type HistoryPage struct { | |
| 109 | + | Commits []domain.Commit | |
| 110 | + | // NextPageToken is empty on the last page. | |
| 111 | + | NextPageToken string | |
| 112 | + | } | |
| 113 | + | ||
| 114 | + | // WatchParams select the events of a watch. | |
| 115 | + | type WatchParams struct { | |
| 116 | + | // Topics are TopicHome or "repo:<name>"; empty means TopicHome. | |
| 117 | + | Topics []string | |
| 118 | + | // ResumeAfter is the id of the last event the caller saw; empty to | |
| 119 | + | // receive only new events. | |
| 120 | + | ResumeAfter string | |
| 121 | + | // Client identifies where the watch comes from, for the limit per client | |
| 122 | + | // (MaxWatchersPerClient): an opaque key such as a normalized address; the | |
| 123 | + | // web passes its visitor's. Empty only for callers with no client, which | |
| 124 | + | // count against MaxWatchers alone. | |
| 125 | + | Client string | |
| 126 | + | // Ready, when not nil, is called once the topics are valid and the watch | |
| 127 | + | // is registered: events published from then on are not missed. Nothing is | |
| 128 | + | // sent before it returns. | |
| 129 | + | Ready func() | |
| 130 | + | } | |
| 131 | + | ||
| 132 | + | // WatchEvent is one item of a watch. | |
| 133 | + | type WatchEvent struct { | |
| 134 | + | // ID identifies the event, for resuming. Empty on a gap. | |
| 135 | + | ID string | |
| 136 | + | // Gap tells that events were lost: the caller must reload what it shows. | |
| 137 | + | // Event is nil then. | |
| 138 | + | Gap bool | |
| 139 | + | // Event is a domain.RepoCreated, RepoUpdated, RepoDeleted, PushEvent, | |
| 140 | + | // MergeRequestOpened, MergeRequestMerged, MergeRequestClosed or | |
| 141 | + | // CommentAdded. | |
| 142 | + | Event domain.Event | |
| 143 | + | // Repo is the state of the repository at delivery, for RepoCreated and | |
| 144 | + | // RepoUpdated. | |
| 145 | + | Repo *RepoView | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // CreateMergeRequestParams describes the merge request to open. | |
| 149 | + | type CreateMergeRequestParams struct { | |
| 150 | + | Title string | |
| 151 | + | Description string | |
| 152 | + | // Source is required; Target defaults to the default branch. | |
| 153 | + | Source, Target string | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | // ListMergeRequestsParams selects a page of merge requests. | |
| 157 | + | type ListMergeRequestsParams struct { | |
| 158 | + | // State restricts the result; empty means every state. | |
| 159 | + | State domain.MRState | |
| 160 | + | // PageSize is 0 for the default, and lowered to MaxPageSize. | |
| 161 | + | PageSize int | |
| 162 | + | // PageToken is the NextPageToken of the previous page, or empty. | |
| 163 | + | PageToken string | |
| 164 | + | } | |
| 165 | + | ||
| 166 | + | // MergeRequestPage is a page of merge requests, highest number first. | |
| 167 | + | type MergeRequestPage struct { | |
| 168 | + | MergeRequests []domain.MergeRequest | |
| 169 | + | // NextPageToken is empty on the last page. | |
| 170 | + | NextPageToken string | |
| 171 | + | } | |
| 172 | + | ||
| 173 | + | // MergeRequestDetail is a merge request with its review data. | |
| 174 | + | type MergeRequestDetail struct { | |
| 175 | + | MergeRequest domain.MergeRequest | |
| 176 | + | // Commits are the commits of the head that the target lacks, newest | |
| 177 | + | // first, at most MaxMergeRequestCommits. | |
| 178 | + | Commits []domain.Commit | |
| 179 | + | CommitsTruncated bool | |
| 180 | + | // DiffBaseID is the commit the diff compares from; zero when the source | |
| 181 | + | // branch is gone, then the diff is empty. | |
| 182 | + | DiffBaseID domain.ObjectID | |
| 183 | + | Stats domain.DiffStats | |
| 184 | + | Diff domain.Diff | |
| 185 | + | // Comments are the comments, oldest first. | |
| 186 | + | Comments []domain.Comment | |
| 187 | + | // LastReadID is the head recorded by MarkRead; zero when none. | |
| 188 | + | LastReadID domain.ObjectID | |
| 189 | + | // LastReadLost tells that since-last-read was asked for, a head was | |
| 190 | + | // recorded, but that commit is gone: the diff is against the target. | |
| 191 | + | LastReadLost bool | |
| 192 | + | } | |
| 193 | + | ||
| 194 | + | // AddCommentParams describes the comment to add. | |
| 195 | + | type AddCommentParams struct { | |
| 196 | + | // Path, Line and Side designate a line of the diff; all empty for a | |
| 197 | + | // general comment. | |
| 198 | + | Path string | |
| 199 | + | Line int | |
| 200 | + | Side domain.DiffSide | |
| 201 | + | Text string | |
| 202 | + | } | |
| 203 | + | ||
| 204 | + | // MergeParams describes the merge to perform. | |
| 205 | + | type MergeParams struct { | |
| 206 | + | // Mode defaults to fast-forward. | |
| 207 | + | Mode domain.MergeMode | |
| 208 | + | // HeadID is the commit the caller reviewed; the source branch must still | |
| 209 | + | // point to it. | |
| 210 | + | HeadID domain.ObjectID | |
| 211 | + | // DeleteSource deletes the source branch after the merge. | |
| 212 | + | DeleteSource bool | |
| 213 | + | } | |
| 214 | + | ||
| 215 | + | // MergeResult is a merged request and what happened to its source branch. | |
| 216 | + | type MergeResult struct { | |
| 217 | + | domain.MergeRequest | |
| 218 | + | // SourceDeleted is true when DeleteSource was asked and the branch is | |
| 219 | + | // gone. | |
| 220 | + | SourceDeleted bool | |
| 221 | + | } | |
| 222 | + | ||
| 223 | + | // LoginLink is a login link as the owner receives it. | |
| 224 | + | type LoginLink struct { | |
| 225 | + | // URL holds the secret: show it once, never log it. | |
| 226 | + | URL string | |
| 227 | + | ExpiresAt time.Time | |
| 228 | + | } | |
R internal/adapters/githttp/mocks/Authenticator.go → internal/ports/mocks/AuthService.go +18 -18 renamed, 52% similar
| @@ -11,17 +11,17 @@ import ( | |||
| 11 | 11 | mock "github.com/stretchr/testify/mock" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | // NewAuthenticator creates a new instance of Authenticator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 14 | + | // NewAuthService creates a new instance of AuthService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | 15 | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewAuthenticator(t interface { | |
| 16 | + | func NewAuthService(t interface { | |
| 17 | 17 | mock.TestingT | |
| 18 | 18 | Cleanup(func()) | |
| 19 | - | }) *Authenticator { | |
| 19 | + | }) *AuthService { | |
| 20 | 20 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | 21 | helper.Helper() | |
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | - | mock := &Authenticator{} | |
| 24 | + | mock := &AuthService{} | |
| 25 | 25 | mock.Mock.Test(t) | |
| 26 | 26 | ||
| 27 | 27 | t.Cleanup(func() { | |
| @@ -34,21 +34,21 @@ func NewAuthenticator(t interface { | |||
| 34 | 34 | return mock | |
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | - | // Authenticator is an autogenerated mock type for the Authenticator type | |
| 38 | - | type Authenticator struct { | |
| 37 | + | // AuthService is an autogenerated mock type for the AuthService type | |
| 38 | + | type AuthService struct { | |
| 39 | 39 | mock.Mock | |
| 40 | 40 | } | |
| 41 | 41 | ||
| 42 | - | type Authenticator_Expecter struct { | |
| 42 | + | type AuthService_Expecter struct { | |
| 43 | 43 | mock *mock.Mock | |
| 44 | 44 | } | |
| 45 | 45 | ||
| 46 | - | func (_m *Authenticator) EXPECT() *Authenticator_Expecter { | |
| 47 | - | return &Authenticator_Expecter{mock: &_m.Mock} | |
| 46 | + | func (_m *AuthService) EXPECT() *AuthService_Expecter { | |
| 47 | + | return &AuthService_Expecter{mock: &_m.Mock} | |
| 48 | 48 | } | |
| 49 | 49 | ||
| 50 | - | // Authenticate provides a mock function for the type Authenticator | |
| 51 | - | func (_mock *Authenticator) Authenticate(ctx context.Context, secret string) (domain.Principal, error) { | |
| 50 | + | // Authenticate provides a mock function for the type AuthService | |
| 51 | + | func (_mock *AuthService) Authenticate(ctx context.Context, secret string) (domain.Principal, error) { | |
| 52 | 52 | ret := _mock.Called(ctx, secret) | |
| 53 | 53 | ||
| 54 | 54 | if len(ret) == 0 { | |
| @@ -73,19 +73,19 @@ func (_mock *Authenticator) Authenticate(ctx context.Context, secret string) (do | |||
| 73 | 73 | return r0, r1 | |
| 74 | 74 | } | |
| 75 | 75 | ||
| 76 | - | // Authenticator_Authenticate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Authenticate' | |
| 77 | - | type Authenticator_Authenticate_Call struct { | |
| 76 | + | // AuthService_Authenticate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Authenticate' | |
| 77 | + | type AuthService_Authenticate_Call struct { | |
| 78 | 78 | *mock.Call | |
| 79 | 79 | } | |
| 80 | 80 | ||
| 81 | 81 | // Authenticate is a helper method to define mock.On call | |
| 82 | 82 | // - ctx context.Context | |
| 83 | 83 | // - secret string | |
| 84 | - | func (_e *Authenticator_Expecter) Authenticate(ctx any, secret any) *Authenticator_Authenticate_Call { | |
| 85 | - | return &Authenticator_Authenticate_Call{Call: _e.mock.On("Authenticate", ctx, secret)} | |
| 84 | + | func (_e *AuthService_Expecter) Authenticate(ctx any, secret any) *AuthService_Authenticate_Call { | |
| 85 | + | return &AuthService_Authenticate_Call{Call: _e.mock.On("Authenticate", ctx, secret)} | |
| 86 | 86 | } | |
| 87 | 87 | ||
| 88 | - | func (_c *Authenticator_Authenticate_Call) Run(run func(ctx context.Context, secret string)) *Authenticator_Authenticate_Call { | |
| 88 | + | func (_c *AuthService_Authenticate_Call) Run(run func(ctx context.Context, secret string)) *AuthService_Authenticate_Call { | |
| 89 | 89 | _c.Call.Run(func(args mock.Arguments) { | |
| 90 | 90 | var arg0 context.Context | |
| 91 | 91 | if args[0] != nil { | |
| @@ -103,12 +103,12 @@ func (_c *Authenticator_Authenticate_Call) Run(run func(ctx context.Context, sec | |||
| 103 | 103 | return _c | |
| 104 | 104 | } | |
| 105 | 105 | ||
| 106 | - | func (_c *Authenticator_Authenticate_Call) Return(principal domain.Principal, err error) *Authenticator_Authenticate_Call { | |
| 106 | + | func (_c *AuthService_Authenticate_Call) Return(principal domain.Principal, err error) *AuthService_Authenticate_Call { | |
| 107 | 107 | _c.Call.Return(principal, err) | |
| 108 | 108 | return _c | |
| 109 | 109 | } | |
| 110 | 110 | ||
| 111 | - | func (_c *Authenticator_Authenticate_Call) RunAndReturn(run func(ctx context.Context, secret string) (domain.Principal, error)) *Authenticator_Authenticate_Call { | |
| 111 | + | func (_c *AuthService_Authenticate_Call) RunAndReturn(run func(ctx context.Context, secret string) (domain.Principal, error)) *AuthService_Authenticate_Call { | |
| 112 | 112 | _c.Call.Return(run) | |
| 113 | 113 | return _c | |
| 114 | 114 | } | |
R internal/adapters/rpc/mocks/Browse.go → internal/ports/mocks/BrowseService.go +81 -81 renamed, 55% similar
| @@ -8,22 +8,22 @@ import ( | |||
| 8 | 8 | "context" | |
| 9 | 9 | "io" | |
| 10 | 10 | ||
| 11 | - | "bnema.dev/ermite/internal/app" | |
| 12 | 11 | "bnema.dev/ermite/internal/domain" | |
| 12 | + | "bnema.dev/ermite/internal/ports" | |
| 13 | 13 | mock "github.com/stretchr/testify/mock" | |
| 14 | 14 | ) | |
| 15 | 15 | ||
| 16 | - | // NewBrowse creates a new instance of Browse. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | + | // NewBrowseService creates a new instance of BrowseService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 17 | 17 | // The first argument is typically a *testing.T value. | |
| 18 | - | func NewBrowse(t interface { | |
| 18 | + | func NewBrowseService(t interface { | |
| 19 | 19 | mock.TestingT | |
| 20 | 20 | Cleanup(func()) | |
| 21 | - | }) *Browse { | |
| 21 | + | }) *BrowseService { | |
| 22 | 22 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 23 | 23 | helper.Helper() | |
| 24 | 24 | } | |
| 25 | 25 | ||
| 26 | - | mock := &Browse{} | |
| 26 | + | mock := &BrowseService{} | |
| 27 | 27 | mock.Mock.Test(t) | |
| 28 | 28 | ||
| 29 | 29 | t.Cleanup(func() { | |
| @@ -36,21 +36,21 @@ func NewBrowse(t interface { | |||
| 36 | 36 | return mock | |
| 37 | 37 | } | |
| 38 | 38 | ||
| 39 | - | // Browse is an autogenerated mock type for the Browse type | |
| 40 | - | type Browse struct { | |
| 39 | + | // BrowseService is an autogenerated mock type for the BrowseService type | |
| 40 | + | type BrowseService struct { | |
| 41 | 41 | mock.Mock | |
| 42 | 42 | } | |
| 43 | 43 | ||
| 44 | - | type Browse_Expecter struct { | |
| 44 | + | type BrowseService_Expecter struct { | |
| 45 | 45 | mock *mock.Mock | |
| 46 | 46 | } | |
| 47 | 47 | ||
| 48 | - | func (_m *Browse) EXPECT() *Browse_Expecter { | |
| 49 | - | return &Browse_Expecter{mock: &_m.Mock} | |
| 48 | + | func (_m *BrowseService) EXPECT() *BrowseService_Expecter { | |
| 49 | + | return &BrowseService_Expecter{mock: &_m.Mock} | |
| 50 | 50 | } | |
| 51 | 51 | ||
| 52 | - | // GetCommit provides a mock function for the type Browse | |
| 53 | - | func (_mock *Browse) GetCommit(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error) { | |
| 52 | + | // GetCommit provides a mock function for the type BrowseService | |
| 53 | + | func (_mock *BrowseService) GetCommit(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error) { | |
| 54 | 54 | ret := _mock.Called(ctx, p, repo, rev) | |
| 55 | 55 | ||
| 56 | 56 | if len(ret) == 0 { | |
| @@ -75,8 +75,8 @@ func (_mock *Browse) GetCommit(ctx context.Context, p domain.Principal, repo dom | |||
| 75 | 75 | return r0, r1 | |
| 76 | 76 | } | |
| 77 | 77 | ||
| 78 | - | // Browse_GetCommit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommit' | |
| 79 | - | type Browse_GetCommit_Call struct { | |
| 78 | + | // BrowseService_GetCommit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommit' | |
| 79 | + | type BrowseService_GetCommit_Call struct { | |
| 80 | 80 | *mock.Call | |
| 81 | 81 | } | |
| 82 | 82 | ||
| @@ -85,11 +85,11 @@ type Browse_GetCommit_Call struct { | |||
| 85 | 85 | // - p domain.Principal | |
| 86 | 86 | // - repo domain.RepoName | |
| 87 | 87 | // - rev domain.Revision | |
| 88 | - | func (_e *Browse_Expecter) GetCommit(ctx any, p any, repo any, rev any) *Browse_GetCommit_Call { | |
| 89 | - | return &Browse_GetCommit_Call{Call: _e.mock.On("GetCommit", ctx, p, repo, rev)} | |
| 88 | + | func (_e *BrowseService_Expecter) GetCommit(ctx any, p any, repo any, rev any) *BrowseService_GetCommit_Call { | |
| 89 | + | return &BrowseService_GetCommit_Call{Call: _e.mock.On("GetCommit", ctx, p, repo, rev)} | |
| 90 | 90 | } | |
| 91 | 91 | ||
| 92 | - | func (_c *Browse_GetCommit_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision)) *Browse_GetCommit_Call { | |
| 92 | + | func (_c *BrowseService_GetCommit_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision)) *BrowseService_GetCommit_Call { | |
| 93 | 93 | _c.Call.Run(func(args mock.Arguments) { | |
| 94 | 94 | var arg0 context.Context | |
| 95 | 95 | if args[0] != nil { | |
| @@ -117,18 +117,18 @@ func (_c *Browse_GetCommit_Call) Run(run func(ctx context.Context, p domain.Prin | |||
| 117 | 117 | return _c | |
| 118 | 118 | } | |
| 119 | 119 | ||
| 120 | - | func (_c *Browse_GetCommit_Call) Return(commitDetail domain.CommitDetail, err error) *Browse_GetCommit_Call { | |
| 120 | + | func (_c *BrowseService_GetCommit_Call) Return(commitDetail domain.CommitDetail, err error) *BrowseService_GetCommit_Call { | |
| 121 | 121 | _c.Call.Return(commitDetail, err) | |
| 122 | 122 | return _c | |
| 123 | 123 | } | |
| 124 | 124 | ||
| 125 | - | func (_c *Browse_GetCommit_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error)) *Browse_GetCommit_Call { | |
| 125 | + | func (_c *BrowseService_GetCommit_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error)) *BrowseService_GetCommit_Call { | |
| 126 | 126 | _c.Call.Return(run) | |
| 127 | 127 | return _c | |
| 128 | 128 | } | |
| 129 | 129 | ||
| 130 | - | // GetTree provides a mock function for the type Browse | |
| 131 | - | func (_mock *Browse) GetTree(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool) (domain.Tree, error) { | |
| 130 | + | // GetTree provides a mock function for the type BrowseService | |
| 131 | + | func (_mock *BrowseService) GetTree(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool) (domain.Tree, error) { | |
| 132 | 132 | ret := _mock.Called(ctx, p, repo, rev, path, includeLastCommit) | |
| 133 | 133 | ||
| 134 | 134 | if len(ret) == 0 { | |
| @@ -153,8 +153,8 @@ func (_mock *Browse) GetTree(ctx context.Context, p domain.Principal, repo domai | |||
| 153 | 153 | return r0, r1 | |
| 154 | 154 | } | |
| 155 | 155 | ||
| 156 | - | // Browse_GetTree_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTree' | |
| 157 | - | type Browse_GetTree_Call struct { | |
| 156 | + | // BrowseService_GetTree_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTree' | |
| 157 | + | type BrowseService_GetTree_Call struct { | |
| 158 | 158 | *mock.Call | |
| 159 | 159 | } | |
| 160 | 160 | ||
| @@ -165,11 +165,11 @@ type Browse_GetTree_Call struct { | |||
| 165 | 165 | // - rev domain.Revision | |
| 166 | 166 | // - path domain.TreePath | |
| 167 | 167 | // - includeLastCommit bool | |
| 168 | - | func (_e *Browse_Expecter) GetTree(ctx any, p any, repo any, rev any, path any, includeLastCommit any) *Browse_GetTree_Call { | |
| 169 | - | return &Browse_GetTree_Call{Call: _e.mock.On("GetTree", ctx, p, repo, rev, path, includeLastCommit)} | |
| 168 | + | func (_e *BrowseService_Expecter) GetTree(ctx any, p any, repo any, rev any, path any, includeLastCommit any) *BrowseService_GetTree_Call { | |
| 169 | + | return &BrowseService_GetTree_Call{Call: _e.mock.On("GetTree", ctx, p, repo, rev, path, includeLastCommit)} | |
| 170 | 170 | } | |
| 171 | 171 | ||
| 172 | - | func (_c *Browse_GetTree_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool)) *Browse_GetTree_Call { | |
| 172 | + | func (_c *BrowseService_GetTree_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool)) *BrowseService_GetTree_Call { | |
| 173 | 173 | _c.Call.Run(func(args mock.Arguments) { | |
| 174 | 174 | var arg0 context.Context | |
| 175 | 175 | if args[0] != nil { | |
| @@ -207,35 +207,35 @@ func (_c *Browse_GetTree_Call) Run(run func(ctx context.Context, p domain.Princi | |||
| 207 | 207 | return _c | |
| 208 | 208 | } | |
| 209 | 209 | ||
| 210 | - | func (_c *Browse_GetTree_Call) Return(tree domain.Tree, err error) *Browse_GetTree_Call { | |
| 210 | + | func (_c *BrowseService_GetTree_Call) Return(tree domain.Tree, err error) *BrowseService_GetTree_Call { | |
| 211 | 211 | _c.Call.Return(tree, err) | |
| 212 | 212 | return _c | |
| 213 | 213 | } | |
| 214 | 214 | ||
| 215 | - | func (_c *Browse_GetTree_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool) (domain.Tree, error)) *Browse_GetTree_Call { | |
| 215 | + | func (_c *BrowseService_GetTree_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool) (domain.Tree, error)) *BrowseService_GetTree_Call { | |
| 216 | 216 | _c.Call.Return(run) | |
| 217 | 217 | return _c | |
| 218 | 218 | } | |
| 219 | 219 | ||
| 220 | - | // ListCommits provides a mock function for the type Browse | |
| 221 | - | func (_mock *Browse) ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListCommitsParams) (app.CommitPage, error) { | |
| 220 | + | // ListCommits provides a mock function for the type BrowseService | |
| 221 | + | func (_mock *BrowseService) ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListCommitsParams) (ports.HistoryPage, error) { | |
| 222 | 222 | ret := _mock.Called(ctx, p, repo, params) | |
| 223 | 223 | ||
| 224 | 224 | if len(ret) == 0 { | |
| 225 | 225 | panic("no return value specified for ListCommits") | |
| 226 | 226 | } | |
| 227 | 227 | ||
| 228 | - | var r0 app.CommitPage | |
| 228 | + | var r0 ports.HistoryPage | |
| 229 | 229 | var r1 error | |
| 230 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.ListCommitsParams) (app.CommitPage, error)); ok { | |
| 230 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.ListCommitsParams) (ports.HistoryPage, error)); ok { | |
| 231 | 231 | return returnFunc(ctx, p, repo, params) | |
| 232 | 232 | } | |
| 233 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.ListCommitsParams) app.CommitPage); ok { | |
| 233 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.ListCommitsParams) ports.HistoryPage); ok { | |
| 234 | 234 | r0 = returnFunc(ctx, p, repo, params) | |
| 235 | 235 | } else { | |
| 236 | - | r0 = ret.Get(0).(app.CommitPage) | |
| 236 | + | r0 = ret.Get(0).(ports.HistoryPage) | |
| 237 | 237 | } | |
| 238 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, app.ListCommitsParams) error); ok { | |
| 238 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, ports.ListCommitsParams) error); ok { | |
| 239 | 239 | r1 = returnFunc(ctx, p, repo, params) | |
| 240 | 240 | } else { | |
| 241 | 241 | r1 = ret.Error(1) | |
| @@ -243,8 +243,8 @@ func (_mock *Browse) ListCommits(ctx context.Context, p domain.Principal, repo d | |||
| 243 | 243 | return r0, r1 | |
| 244 | 244 | } | |
| 245 | 245 | ||
| 246 | - | // Browse_ListCommits_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListCommits' | |
| 247 | - | type Browse_ListCommits_Call struct { | |
| 246 | + | // BrowseService_ListCommits_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListCommits' | |
| 247 | + | type BrowseService_ListCommits_Call struct { | |
| 248 | 248 | *mock.Call | |
| 249 | 249 | } | |
| 250 | 250 | ||
| @@ -252,12 +252,12 @@ type Browse_ListCommits_Call struct { | |||
| 252 | 252 | // - ctx context.Context | |
| 253 | 253 | // - p domain.Principal | |
| 254 | 254 | // - repo domain.RepoName | |
| 255 | - | // - params app.ListCommitsParams | |
| 256 | - | func (_e *Browse_Expecter) ListCommits(ctx any, p any, repo any, params any) *Browse_ListCommits_Call { | |
| 257 | - | return &Browse_ListCommits_Call{Call: _e.mock.On("ListCommits", ctx, p, repo, params)} | |
| 255 | + | // - params ports.ListCommitsParams | |
| 256 | + | func (_e *BrowseService_Expecter) ListCommits(ctx any, p any, repo any, params any) *BrowseService_ListCommits_Call { | |
| 257 | + | return &BrowseService_ListCommits_Call{Call: _e.mock.On("ListCommits", ctx, p, repo, params)} | |
| 258 | 258 | } | |
| 259 | 259 | ||
| 260 | - | func (_c *Browse_ListCommits_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListCommitsParams)) *Browse_ListCommits_Call { | |
| 260 | + | func (_c *BrowseService_ListCommits_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListCommitsParams)) *BrowseService_ListCommits_Call { | |
| 261 | 261 | _c.Call.Run(func(args mock.Arguments) { | |
| 262 | 262 | var arg0 context.Context | |
| 263 | 263 | if args[0] != nil { | |
| @@ -271,9 +271,9 @@ func (_c *Browse_ListCommits_Call) Run(run func(ctx context.Context, p domain.Pr | |||
| 271 | 271 | if args[2] != nil { | |
| 272 | 272 | arg2 = args[2].(domain.RepoName) | |
| 273 | 273 | } | |
| 274 | - | var arg3 app.ListCommitsParams | |
| 274 | + | var arg3 ports.ListCommitsParams | |
| 275 | 275 | if args[3] != nil { | |
| 276 | - | arg3 = args[3].(app.ListCommitsParams) | |
| 276 | + | arg3 = args[3].(ports.ListCommitsParams) | |
| 277 | 277 | } | |
| 278 | 278 | run( | |
| 279 | 279 | arg0, | |
| @@ -285,35 +285,35 @@ func (_c *Browse_ListCommits_Call) Run(run func(ctx context.Context, p domain.Pr | |||
| 285 | 285 | return _c | |
| 286 | 286 | } | |
| 287 | 287 | ||
| 288 | - | func (_c *Browse_ListCommits_Call) Return(commitPage app.CommitPage, err error) *Browse_ListCommits_Call { | |
| 289 | - | _c.Call.Return(commitPage, err) | |
| 288 | + | func (_c *BrowseService_ListCommits_Call) Return(historyPage ports.HistoryPage, err error) *BrowseService_ListCommits_Call { | |
| 289 | + | _c.Call.Return(historyPage, err) | |
| 290 | 290 | return _c | |
| 291 | 291 | } | |
| 292 | 292 | ||
| 293 | - | func (_c *Browse_ListCommits_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListCommitsParams) (app.CommitPage, error)) *Browse_ListCommits_Call { | |
| 293 | + | func (_c *BrowseService_ListCommits_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListCommitsParams) (ports.HistoryPage, error)) *BrowseService_ListCommits_Call { | |
| 294 | 294 | _c.Call.Return(run) | |
| 295 | 295 | return _c | |
| 296 | 296 | } | |
| 297 | 297 | ||
| 298 | - | // ListRefs provides a mock function for the type Browse | |
| 299 | - | func (_mock *Browse) ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListRefsParams) (app.RefPage, error) { | |
| 298 | + | // ListRefs provides a mock function for the type BrowseService | |
| 299 | + | func (_mock *BrowseService) ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListRefsParams) (ports.RefPage, error) { | |
| 300 | 300 | ret := _mock.Called(ctx, p, repo, params) | |
| 301 | 301 | ||
| 302 | 302 | if len(ret) == 0 { | |
| 303 | 303 | panic("no return value specified for ListRefs") | |
| 304 | 304 | } | |
| 305 | 305 | ||
| 306 | - | var r0 app.RefPage | |
| 306 | + | var r0 ports.RefPage | |
| 307 | 307 | var r1 error | |
| 308 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.ListRefsParams) (app.RefPage, error)); ok { | |
| 308 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.ListRefsParams) (ports.RefPage, error)); ok { | |
| 309 | 309 | return returnFunc(ctx, p, repo, params) | |
| 310 | 310 | } | |
| 311 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.ListRefsParams) app.RefPage); ok { | |
| 311 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.ListRefsParams) ports.RefPage); ok { | |
| 312 | 312 | r0 = returnFunc(ctx, p, repo, params) | |
| 313 | 313 | } else { | |
| 314 | - | r0 = ret.Get(0).(app.RefPage) | |
| 314 | + | r0 = ret.Get(0).(ports.RefPage) | |
| 315 | 315 | } | |
| 316 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, app.ListRefsParams) error); ok { | |
| 316 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, ports.ListRefsParams) error); ok { | |
| 317 | 317 | r1 = returnFunc(ctx, p, repo, params) | |
| 318 | 318 | } else { | |
| 319 | 319 | r1 = ret.Error(1) | |
| @@ -321,8 +321,8 @@ func (_mock *Browse) ListRefs(ctx context.Context, p domain.Principal, repo doma | |||
| 321 | 321 | return r0, r1 | |
| 322 | 322 | } | |
| 323 | 323 | ||
| 324 | - | // Browse_ListRefs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRefs' | |
| 325 | - | type Browse_ListRefs_Call struct { | |
| 324 | + | // BrowseService_ListRefs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRefs' | |
| 325 | + | type BrowseService_ListRefs_Call struct { | |
| 326 | 326 | *mock.Call | |
| 327 | 327 | } | |
| 328 | 328 | ||
| @@ -330,12 +330,12 @@ type Browse_ListRefs_Call struct { | |||
| 330 | 330 | // - ctx context.Context | |
| 331 | 331 | // - p domain.Principal | |
| 332 | 332 | // - repo domain.RepoName | |
| 333 | - | // - params app.ListRefsParams | |
| 334 | - | func (_e *Browse_Expecter) ListRefs(ctx any, p any, repo any, params any) *Browse_ListRefs_Call { | |
| 335 | - | return &Browse_ListRefs_Call{Call: _e.mock.On("ListRefs", ctx, p, repo, params)} | |
| 333 | + | // - params ports.ListRefsParams | |
| 334 | + | func (_e *BrowseService_Expecter) ListRefs(ctx any, p any, repo any, params any) *BrowseService_ListRefs_Call { | |
| 335 | + | return &BrowseService_ListRefs_Call{Call: _e.mock.On("ListRefs", ctx, p, repo, params)} | |
| 336 | 336 | } | |
| 337 | 337 | ||
| 338 | - | func (_c *Browse_ListRefs_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListRefsParams)) *Browse_ListRefs_Call { | |
| 338 | + | func (_c *BrowseService_ListRefs_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListRefsParams)) *BrowseService_ListRefs_Call { | |
| 339 | 339 | _c.Call.Run(func(args mock.Arguments) { | |
| 340 | 340 | var arg0 context.Context | |
| 341 | 341 | if args[0] != nil { | |
| @@ -349,9 +349,9 @@ func (_c *Browse_ListRefs_Call) Run(run func(ctx context.Context, p domain.Princ | |||
| 349 | 349 | if args[2] != nil { | |
| 350 | 350 | arg2 = args[2].(domain.RepoName) | |
| 351 | 351 | } | |
| 352 | - | var arg3 app.ListRefsParams | |
| 352 | + | var arg3 ports.ListRefsParams | |
| 353 | 353 | if args[3] != nil { | |
| 354 | - | arg3 = args[3].(app.ListRefsParams) | |
| 354 | + | arg3 = args[3].(ports.ListRefsParams) | |
| 355 | 355 | } | |
| 356 | 356 | run( | |
| 357 | 357 | arg0, | |
| @@ -363,18 +363,18 @@ func (_c *Browse_ListRefs_Call) Run(run func(ctx context.Context, p domain.Princ | |||
| 363 | 363 | return _c | |
| 364 | 364 | } | |
| 365 | 365 | ||
| 366 | - | func (_c *Browse_ListRefs_Call) Return(refPage app.RefPage, err error) *Browse_ListRefs_Call { | |
| 366 | + | func (_c *BrowseService_ListRefs_Call) Return(refPage ports.RefPage, err error) *BrowseService_ListRefs_Call { | |
| 367 | 367 | _c.Call.Return(refPage, err) | |
| 368 | 368 | return _c | |
| 369 | 369 | } | |
| 370 | 370 | ||
| 371 | - | func (_c *Browse_ListRefs_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListRefsParams) (app.RefPage, error)) *Browse_ListRefs_Call { | |
| 371 | + | func (_c *BrowseService_ListRefs_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListRefsParams) (ports.RefPage, error)) *BrowseService_ListRefs_Call { | |
| 372 | 372 | _c.Call.Return(run) | |
| 373 | 373 | return _c | |
| 374 | 374 | } | |
| 375 | 375 | ||
| 376 | - | // OpenBlob provides a mock function for the type Browse | |
| 377 | - | func (_mock *Browse) OpenBlob(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath) (domain.BlobInfo, io.ReadCloser, error) { | |
| 376 | + | // OpenBlob provides a mock function for the type BrowseService | |
| 377 | + | func (_mock *BrowseService) OpenBlob(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath) (domain.BlobInfo, io.ReadCloser, error) { | |
| 378 | 378 | ret := _mock.Called(ctx, p, repo, rev, path) | |
| 379 | 379 | ||
| 380 | 380 | if len(ret) == 0 { | |
| @@ -407,8 +407,8 @@ func (_mock *Browse) OpenBlob(ctx context.Context, p domain.Principal, repo doma | |||
| 407 | 407 | return r0, r1, r2 | |
| 408 | 408 | } | |
| 409 | 409 | ||
| 410 | - | // Browse_OpenBlob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenBlob' | |
| 411 | - | type Browse_OpenBlob_Call struct { | |
| 410 | + | // BrowseService_OpenBlob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenBlob' | |
| 411 | + | type BrowseService_OpenBlob_Call struct { | |
| 412 | 412 | *mock.Call | |
| 413 | 413 | } | |
| 414 | 414 | ||
| @@ -418,11 +418,11 @@ type Browse_OpenBlob_Call struct { | |||
| 418 | 418 | // - repo domain.RepoName | |
| 419 | 419 | // - rev domain.Revision | |
| 420 | 420 | // - path domain.TreePath | |
| 421 | - | func (_e *Browse_Expecter) OpenBlob(ctx any, p any, repo any, rev any, path any) *Browse_OpenBlob_Call { | |
| 422 | - | return &Browse_OpenBlob_Call{Call: _e.mock.On("OpenBlob", ctx, p, repo, rev, path)} | |
| 421 | + | func (_e *BrowseService_Expecter) OpenBlob(ctx any, p any, repo any, rev any, path any) *BrowseService_OpenBlob_Call { | |
| 422 | + | return &BrowseService_OpenBlob_Call{Call: _e.mock.On("OpenBlob", ctx, p, repo, rev, path)} | |
| 423 | 423 | } | |
| 424 | 424 | ||
| 425 | - | func (_c *Browse_OpenBlob_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath)) *Browse_OpenBlob_Call { | |
| 425 | + | func (_c *BrowseService_OpenBlob_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath)) *BrowseService_OpenBlob_Call { | |
| 426 | 426 | _c.Call.Run(func(args mock.Arguments) { | |
| 427 | 427 | var arg0 context.Context | |
| 428 | 428 | if args[0] != nil { | |
| @@ -455,18 +455,18 @@ func (_c *Browse_OpenBlob_Call) Run(run func(ctx context.Context, p domain.Princ | |||
| 455 | 455 | return _c | |
| 456 | 456 | } | |
| 457 | 457 | ||
| 458 | - | func (_c *Browse_OpenBlob_Call) Return(blobInfo domain.BlobInfo, readCloser io.ReadCloser, err error) *Browse_OpenBlob_Call { | |
| 458 | + | func (_c *BrowseService_OpenBlob_Call) Return(blobInfo domain.BlobInfo, readCloser io.ReadCloser, err error) *BrowseService_OpenBlob_Call { | |
| 459 | 459 | _c.Call.Return(blobInfo, readCloser, err) | |
| 460 | 460 | return _c | |
| 461 | 461 | } | |
| 462 | 462 | ||
| 463 | - | func (_c *Browse_OpenBlob_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath) (domain.BlobInfo, io.ReadCloser, error)) *Browse_OpenBlob_Call { | |
| 463 | + | func (_c *BrowseService_OpenBlob_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath) (domain.BlobInfo, io.ReadCloser, error)) *BrowseService_OpenBlob_Call { | |
| 464 | 464 | _c.Call.Return(run) | |
| 465 | 465 | return _c | |
| 466 | 466 | } | |
| 467 | 467 | ||
| 468 | - | // ResolveRevision provides a mock function for the type Browse | |
| 469 | - | func (_mock *Browse) ResolveRevision(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) { | |
| 468 | + | // ResolveRevision provides a mock function for the type BrowseService | |
| 469 | + | func (_mock *BrowseService) ResolveRevision(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) { | |
| 470 | 470 | ret := _mock.Called(ctx, p, repo, rev) | |
| 471 | 471 | ||
| 472 | 472 | if len(ret) == 0 { | |
| @@ -491,8 +491,8 @@ func (_mock *Browse) ResolveRevision(ctx context.Context, p domain.Principal, re | |||
| 491 | 491 | return r0, r1 | |
| 492 | 492 | } | |
| 493 | 493 | ||
| 494 | - | // Browse_ResolveRevision_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveRevision' | |
| 495 | - | type Browse_ResolveRevision_Call struct { | |
| 494 | + | // BrowseService_ResolveRevision_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveRevision' | |
| 495 | + | type BrowseService_ResolveRevision_Call struct { | |
| 496 | 496 | *mock.Call | |
| 497 | 497 | } | |
| 498 | 498 | ||
| @@ -501,11 +501,11 @@ type Browse_ResolveRevision_Call struct { | |||
| 501 | 501 | // - p domain.Principal | |
| 502 | 502 | // - repo domain.RepoName | |
| 503 | 503 | // - rev domain.Revision | |
| 504 | - | func (_e *Browse_Expecter) ResolveRevision(ctx any, p any, repo any, rev any) *Browse_ResolveRevision_Call { | |
| 505 | - | return &Browse_ResolveRevision_Call{Call: _e.mock.On("ResolveRevision", ctx, p, repo, rev)} | |
| 504 | + | func (_e *BrowseService_Expecter) ResolveRevision(ctx any, p any, repo any, rev any) *BrowseService_ResolveRevision_Call { | |
| 505 | + | return &BrowseService_ResolveRevision_Call{Call: _e.mock.On("ResolveRevision", ctx, p, repo, rev)} | |
| 506 | 506 | } | |
| 507 | 507 | ||
| 508 | - | func (_c *Browse_ResolveRevision_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision)) *Browse_ResolveRevision_Call { | |
| 508 | + | func (_c *BrowseService_ResolveRevision_Call) Run(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision)) *BrowseService_ResolveRevision_Call { | |
| 509 | 509 | _c.Call.Run(func(args mock.Arguments) { | |
| 510 | 510 | var arg0 context.Context | |
| 511 | 511 | if args[0] != nil { | |
| @@ -533,12 +533,12 @@ func (_c *Browse_ResolveRevision_Call) Run(run func(ctx context.Context, p domai | |||
| 533 | 533 | return _c | |
| 534 | 534 | } | |
| 535 | 535 | ||
| 536 | - | func (_c *Browse_ResolveRevision_Call) Return(resolvedRevision domain.ResolvedRevision, err error) *Browse_ResolveRevision_Call { | |
| 536 | + | func (_c *BrowseService_ResolveRevision_Call) Return(resolvedRevision domain.ResolvedRevision, err error) *BrowseService_ResolveRevision_Call { | |
| 537 | 537 | _c.Call.Return(resolvedRevision, err) | |
| 538 | 538 | return _c | |
| 539 | 539 | } | |
| 540 | 540 | ||
| 541 | - | func (_c *Browse_ResolveRevision_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error)) *Browse_ResolveRevision_Call { | |
| 541 | + | func (_c *BrowseService_ResolveRevision_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error)) *BrowseService_ResolveRevision_Call { | |
| 542 | 542 | _c.Call.Return(run) | |
| 543 | 543 | return _c | |
| 544 | 544 | } | |
A internal/ports/mocks/EventService.go +118 -0
| @@ -0,0 +1,118 @@ | |||
| 1 | + | // Code generated by mockery; DO NOT EDIT. | |
| 2 | + | // github.com/vektra/mockery | |
| 3 | + | // template: testify | |
| 4 | + | ||
| 5 | + | package mocks | |
| 6 | + | ||
| 7 | + | import ( | |
| 8 | + | "context" | |
| 9 | + | ||
| 10 | + | "bnema.dev/ermite/internal/domain" | |
| 11 | + | "bnema.dev/ermite/internal/ports" | |
| 12 | + | mock "github.com/stretchr/testify/mock" | |
| 13 | + | ) | |
| 14 | + | ||
| 15 | + | // NewEventService creates a new instance of EventService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | + | // The first argument is typically a *testing.T value. | |
| 17 | + | func NewEventService(t interface { | |
| 18 | + | mock.TestingT | |
| 19 | + | Cleanup(func()) | |
| 20 | + | }) *EventService { | |
| 21 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | + | helper.Helper() | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | mock := &EventService{} | |
| 26 | + | mock.Mock.Test(t) | |
| 27 | + | ||
| 28 | + | t.Cleanup(func() { | |
| 29 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 30 | + | helper.Helper() | |
| 31 | + | } | |
| 32 | + | mock.AssertExpectations(t) | |
| 33 | + | }) | |
| 34 | + | ||
| 35 | + | return mock | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | // EventService is an autogenerated mock type for the EventService type | |
| 39 | + | type EventService struct { | |
| 40 | + | mock.Mock | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | type EventService_Expecter struct { | |
| 44 | + | mock *mock.Mock | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | func (_m *EventService) EXPECT() *EventService_Expecter { | |
| 48 | + | return &EventService_Expecter{mock: &_m.Mock} | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // Watch provides a mock function for the type EventService | |
| 52 | + | func (_mock *EventService) Watch(ctx context.Context, p domain.Principal, params ports.WatchParams, send func(ports.WatchEvent) error) error { | |
| 53 | + | ret := _mock.Called(ctx, p, params, send) | |
| 54 | + | ||
| 55 | + | if len(ret) == 0 { | |
| 56 | + | panic("no return value specified for Watch") | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | var r0 error | |
| 60 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, ports.WatchParams, func(ports.WatchEvent) error) error); ok { | |
| 61 | + | r0 = returnFunc(ctx, p, params, send) | |
| 62 | + | } else { | |
| 63 | + | r0 = ret.Error(0) | |
| 64 | + | } | |
| 65 | + | return r0 | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | // EventService_Watch_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Watch' | |
| 69 | + | type EventService_Watch_Call struct { | |
| 70 | + | *mock.Call | |
| 71 | + | } | |
| 72 | + | ||
| 73 | + | // Watch is a helper method to define mock.On call | |
| 74 | + | // - ctx context.Context | |
| 75 | + | // - p domain.Principal | |
| 76 | + | // - params ports.WatchParams | |
| 77 | + | // - send func(ports.WatchEvent) error | |
| 78 | + | func (_e *EventService_Expecter) Watch(ctx any, p any, params any, send any) *EventService_Watch_Call { | |
| 79 | + | return &EventService_Watch_Call{Call: _e.mock.On("Watch", ctx, p, params, send)} | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | func (_c *EventService_Watch_Call) Run(run func(ctx context.Context, p domain.Principal, params ports.WatchParams, send func(ports.WatchEvent) error)) *EventService_Watch_Call { | |
| 83 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 84 | + | var arg0 context.Context | |
| 85 | + | if args[0] != nil { | |
| 86 | + | arg0 = args[0].(context.Context) | |
| 87 | + | } | |
| 88 | + | var arg1 domain.Principal | |
| 89 | + | if args[1] != nil { | |
| 90 | + | arg1 = args[1].(domain.Principal) | |
| 91 | + | } | |
| 92 | + | var arg2 ports.WatchParams | |
| 93 | + | if args[2] != nil { | |
| 94 | + | arg2 = args[2].(ports.WatchParams) | |
| 95 | + | } | |
| 96 | + | var arg3 func(ports.WatchEvent) error | |
| 97 | + | if args[3] != nil { | |
| 98 | + | arg3 = args[3].(func(ports.WatchEvent) error) | |
| 99 | + | } | |
| 100 | + | run( | |
| 101 | + | arg0, | |
| 102 | + | arg1, | |
| 103 | + | arg2, | |
| 104 | + | arg3, | |
| 105 | + | ) | |
| 106 | + | }) | |
| 107 | + | return _c | |
| 108 | + | } | |
| 109 | + | ||
| 110 | + | func (_c *EventService_Watch_Call) Return(err error) *EventService_Watch_Call { | |
| 111 | + | _c.Call.Return(err) | |
| 112 | + | return _c | |
| 113 | + | } | |
| 114 | + | ||
| 115 | + | func (_c *EventService_Watch_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, params ports.WatchParams, send func(ports.WatchEvent) error) error) *EventService_Watch_Call { | |
| 116 | + | _c.Call.Return(run) | |
| 117 | + | return _c | |
| 118 | + | } | |
R internal/adapters/githttp/mocks/FailureLimiter.go → internal/ports/mocks/FailureLimiter.go +0 -0 renamed, 100% similar
renamed, 100% similar
R internal/adapters/githttp/mocks/HookTokens.go → internal/ports/mocks/HookTokens.go +0 -0 renamed, 100% similar
renamed, 100% similar
R internal/app/mocks/MaintenanceScheduler.go → internal/ports/mocks/MaintenanceScheduler.go +0 -0 renamed, 100% similar
renamed, 100% similar
R internal/adapters/rpc/mocks/MergeRequests.go → internal/ports/mocks/MergeRequestService.go +114 -114 renamed, 50% similar
| @@ -7,22 +7,22 @@ package mocks | |||
| 7 | 7 | import ( | |
| 8 | 8 | "context" | |
| 9 | 9 | ||
| 10 | - | "bnema.dev/ermite/internal/app" | |
| 11 | 10 | "bnema.dev/ermite/internal/domain" | |
| 11 | + | "bnema.dev/ermite/internal/ports" | |
| 12 | 12 | mock "github.com/stretchr/testify/mock" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | - | // NewMergeRequests creates a new instance of MergeRequests. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | + | // NewMergeRequestService creates a new instance of MergeRequestService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | 16 | // The first argument is typically a *testing.T value. | |
| 17 | - | func NewMergeRequests(t interface { | |
| 17 | + | func NewMergeRequestService(t interface { | |
| 18 | 18 | mock.TestingT | |
| 19 | 19 | Cleanup(func()) | |
| 20 | - | }) *MergeRequests { | |
| 20 | + | }) *MergeRequestService { | |
| 21 | 21 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | 22 | helper.Helper() | |
| 23 | 23 | } | |
| 24 | 24 | ||
| 25 | - | mock := &MergeRequests{} | |
| 25 | + | mock := &MergeRequestService{} | |
| 26 | 26 | mock.Mock.Test(t) | |
| 27 | 27 | ||
| 28 | 28 | t.Cleanup(func() { | |
| @@ -35,21 +35,21 @@ func NewMergeRequests(t interface { | |||
| 35 | 35 | return mock | |
| 36 | 36 | } | |
| 37 | 37 | ||
| 38 | - | // MergeRequests is an autogenerated mock type for the MergeRequests type | |
| 39 | - | type MergeRequests struct { | |
| 38 | + | // MergeRequestService is an autogenerated mock type for the MergeRequestService type | |
| 39 | + | type MergeRequestService struct { | |
| 40 | 40 | mock.Mock | |
| 41 | 41 | } | |
| 42 | 42 | ||
| 43 | - | type MergeRequests_Expecter struct { | |
| 43 | + | type MergeRequestService_Expecter struct { | |
| 44 | 44 | mock *mock.Mock | |
| 45 | 45 | } | |
| 46 | 46 | ||
| 47 | - | func (_m *MergeRequests) EXPECT() *MergeRequests_Expecter { | |
| 48 | - | return &MergeRequests_Expecter{mock: &_m.Mock} | |
| 47 | + | func (_m *MergeRequestService) EXPECT() *MergeRequestService_Expecter { | |
| 48 | + | return &MergeRequestService_Expecter{mock: &_m.Mock} | |
| 49 | 49 | } | |
| 50 | 50 | ||
| 51 | - | // AddComment provides a mock function for the type MergeRequests | |
| 52 | - | func (_mock *MergeRequests) AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.AddCommentParams) (domain.Comment, error) { | |
| 51 | + | // AddComment provides a mock function for the type MergeRequestService | |
| 52 | + | func (_mock *MergeRequestService) AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.AddCommentParams) (domain.Comment, error) { | |
| 53 | 53 | ret := _mock.Called(ctx, p, name, number, params) | |
| 54 | 54 | ||
| 55 | 55 | if len(ret) == 0 { | |
| @@ -58,15 +58,15 @@ func (_mock *MergeRequests) AddComment(ctx context.Context, p domain.Principal, | |||
| 58 | 58 | ||
| 59 | 59 | var r0 domain.Comment | |
| 60 | 60 | var r1 error | |
| 61 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, app.AddCommentParams) (domain.Comment, error)); ok { | |
| 61 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.AddCommentParams) (domain.Comment, error)); ok { | |
| 62 | 62 | return returnFunc(ctx, p, name, number, params) | |
| 63 | 63 | } | |
| 64 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, app.AddCommentParams) domain.Comment); ok { | |
| 64 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.AddCommentParams) domain.Comment); ok { | |
| 65 | 65 | r0 = returnFunc(ctx, p, name, number, params) | |
| 66 | 66 | } else { | |
| 67 | 67 | r0 = ret.Get(0).(domain.Comment) | |
| 68 | 68 | } | |
| 69 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, app.AddCommentParams) error); ok { | |
| 69 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.AddCommentParams) error); ok { | |
| 70 | 70 | r1 = returnFunc(ctx, p, name, number, params) | |
| 71 | 71 | } else { | |
| 72 | 72 | r1 = ret.Error(1) | |
| @@ -74,8 +74,8 @@ func (_mock *MergeRequests) AddComment(ctx context.Context, p domain.Principal, | |||
| 74 | 74 | return r0, r1 | |
| 75 | 75 | } | |
| 76 | 76 | ||
| 77 | - | // MergeRequests_AddComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddComment' | |
| 78 | - | type MergeRequests_AddComment_Call struct { | |
| 77 | + | // MergeRequestService_AddComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddComment' | |
| 78 | + | type MergeRequestService_AddComment_Call struct { | |
| 79 | 79 | *mock.Call | |
| 80 | 80 | } | |
| 81 | 81 | ||
| @@ -84,12 +84,12 @@ type MergeRequests_AddComment_Call struct { | |||
| 84 | 84 | // - p domain.Principal | |
| 85 | 85 | // - name domain.RepoName | |
| 86 | 86 | // - number int64 | |
| 87 | - | // - params app.AddCommentParams | |
| 88 | - | func (_e *MergeRequests_Expecter) AddComment(ctx any, p any, name any, number any, params any) *MergeRequests_AddComment_Call { | |
| 89 | - | return &MergeRequests_AddComment_Call{Call: _e.mock.On("AddComment", ctx, p, name, number, params)} | |
| 87 | + | // - params ports.AddCommentParams | |
| 88 | + | func (_e *MergeRequestService_Expecter) AddComment(ctx any, p any, name any, number any, params any) *MergeRequestService_AddComment_Call { | |
| 89 | + | return &MergeRequestService_AddComment_Call{Call: _e.mock.On("AddComment", ctx, p, name, number, params)} | |
| 90 | 90 | } | |
| 91 | 91 | ||
| 92 | - | func (_c *MergeRequests_AddComment_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.AddCommentParams)) *MergeRequests_AddComment_Call { | |
| 92 | + | func (_c *MergeRequestService_AddComment_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.AddCommentParams)) *MergeRequestService_AddComment_Call { | |
| 93 | 93 | _c.Call.Run(func(args mock.Arguments) { | |
| 94 | 94 | var arg0 context.Context | |
| 95 | 95 | if args[0] != nil { | |
| @@ -107,9 +107,9 @@ func (_c *MergeRequests_AddComment_Call) Run(run func(ctx context.Context, p dom | |||
| 107 | 107 | if args[3] != nil { | |
| 108 | 108 | arg3 = args[3].(int64) | |
| 109 | 109 | } | |
| 110 | - | var arg4 app.AddCommentParams | |
| 110 | + | var arg4 ports.AddCommentParams | |
| 111 | 111 | if args[4] != nil { | |
| 112 | - | arg4 = args[4].(app.AddCommentParams) | |
| 112 | + | arg4 = args[4].(ports.AddCommentParams) | |
| 113 | 113 | } | |
| 114 | 114 | run( | |
| 115 | 115 | arg0, | |
| @@ -122,18 +122,18 @@ func (_c *MergeRequests_AddComment_Call) Run(run func(ctx context.Context, p dom | |||
| 122 | 122 | return _c | |
| 123 | 123 | } | |
| 124 | 124 | ||
| 125 | - | func (_c *MergeRequests_AddComment_Call) Return(comment domain.Comment, err error) *MergeRequests_AddComment_Call { | |
| 125 | + | func (_c *MergeRequestService_AddComment_Call) Return(comment domain.Comment, err error) *MergeRequestService_AddComment_Call { | |
| 126 | 126 | _c.Call.Return(comment, err) | |
| 127 | 127 | return _c | |
| 128 | 128 | } | |
| 129 | 129 | ||
| 130 | - | func (_c *MergeRequests_AddComment_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.AddCommentParams) (domain.Comment, error)) *MergeRequests_AddComment_Call { | |
| 130 | + | func (_c *MergeRequestService_AddComment_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.AddCommentParams) (domain.Comment, error)) *MergeRequestService_AddComment_Call { | |
| 131 | 131 | _c.Call.Return(run) | |
| 132 | 132 | return _c | |
| 133 | 133 | } | |
| 134 | 134 | ||
| 135 | - | // Close provides a mock function for the type MergeRequests | |
| 136 | - | func (_mock *MergeRequests) Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) { | |
| 135 | + | // Close provides a mock function for the type MergeRequestService | |
| 136 | + | func (_mock *MergeRequestService) Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) { | |
| 137 | 137 | ret := _mock.Called(ctx, p, name, number) | |
| 138 | 138 | ||
| 139 | 139 | if len(ret) == 0 { | |
| @@ -158,8 +158,8 @@ func (_mock *MergeRequests) Close(ctx context.Context, p domain.Principal, name | |||
| 158 | 158 | return r0, r1 | |
| 159 | 159 | } | |
| 160 | 160 | ||
| 161 | - | // MergeRequests_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' | |
| 162 | - | type MergeRequests_Close_Call struct { | |
| 161 | + | // MergeRequestService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' | |
| 162 | + | type MergeRequestService_Close_Call struct { | |
| 163 | 163 | *mock.Call | |
| 164 | 164 | } | |
| 165 | 165 | ||
| @@ -168,11 +168,11 @@ type MergeRequests_Close_Call struct { | |||
| 168 | 168 | // - p domain.Principal | |
| 169 | 169 | // - name domain.RepoName | |
| 170 | 170 | // - number int64 | |
| 171 | - | func (_e *MergeRequests_Expecter) Close(ctx any, p any, name any, number any) *MergeRequests_Close_Call { | |
| 172 | - | return &MergeRequests_Close_Call{Call: _e.mock.On("Close", ctx, p, name, number)} | |
| 171 | + | func (_e *MergeRequestService_Expecter) Close(ctx any, p any, name any, number any) *MergeRequestService_Close_Call { | |
| 172 | + | return &MergeRequestService_Close_Call{Call: _e.mock.On("Close", ctx, p, name, number)} | |
| 173 | 173 | } | |
| 174 | 174 | ||
| 175 | - | func (_c *MergeRequests_Close_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64)) *MergeRequests_Close_Call { | |
| 175 | + | func (_c *MergeRequestService_Close_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64)) *MergeRequestService_Close_Call { | |
| 176 | 176 | _c.Call.Run(func(args mock.Arguments) { | |
| 177 | 177 | var arg0 context.Context | |
| 178 | 178 | if args[0] != nil { | |
| @@ -200,18 +200,18 @@ func (_c *MergeRequests_Close_Call) Run(run func(ctx context.Context, p domain.P | |||
| 200 | 200 | return _c | |
| 201 | 201 | } | |
| 202 | 202 | ||
| 203 | - | func (_c *MergeRequests_Close_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequests_Close_Call { | |
| 203 | + | func (_c *MergeRequestService_Close_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequestService_Close_Call { | |
| 204 | 204 | _c.Call.Return(mergeRequest, err) | |
| 205 | 205 | return _c | |
| 206 | 206 | } | |
| 207 | 207 | ||
| 208 | - | func (_c *MergeRequests_Close_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)) *MergeRequests_Close_Call { | |
| 208 | + | func (_c *MergeRequestService_Close_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error)) *MergeRequestService_Close_Call { | |
| 209 | 209 | _c.Call.Return(run) | |
| 210 | 210 | return _c | |
| 211 | 211 | } | |
| 212 | 212 | ||
| 213 | - | // Create provides a mock function for the type MergeRequests | |
| 214 | - | func (_mock *MergeRequests) Create(ctx context.Context, p domain.Principal, name domain.RepoName, params app.CreateMergeRequestParams) (domain.MergeRequest, error) { | |
| 213 | + | // Create provides a mock function for the type MergeRequestService | |
| 214 | + | func (_mock *MergeRequestService) Create(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.CreateMergeRequestParams) (domain.MergeRequest, error) { | |
| 215 | 215 | ret := _mock.Called(ctx, p, name, params) | |
| 216 | 216 | ||
| 217 | 217 | if len(ret) == 0 { | |
| @@ -220,15 +220,15 @@ func (_mock *MergeRequests) Create(ctx context.Context, p domain.Principal, name | |||
| 220 | 220 | ||
| 221 | 221 | var r0 domain.MergeRequest | |
| 222 | 222 | var r1 error | |
| 223 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.CreateMergeRequestParams) (domain.MergeRequest, error)); ok { | |
| 223 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.CreateMergeRequestParams) (domain.MergeRequest, error)); ok { | |
| 224 | 224 | return returnFunc(ctx, p, name, params) | |
| 225 | 225 | } | |
| 226 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.CreateMergeRequestParams) domain.MergeRequest); ok { | |
| 226 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.CreateMergeRequestParams) domain.MergeRequest); ok { | |
| 227 | 227 | r0 = returnFunc(ctx, p, name, params) | |
| 228 | 228 | } else { | |
| 229 | 229 | r0 = ret.Get(0).(domain.MergeRequest) | |
| 230 | 230 | } | |
| 231 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, app.CreateMergeRequestParams) error); ok { | |
| 231 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, ports.CreateMergeRequestParams) error); ok { | |
| 232 | 232 | r1 = returnFunc(ctx, p, name, params) | |
| 233 | 233 | } else { | |
| 234 | 234 | r1 = ret.Error(1) | |
| @@ -236,8 +236,8 @@ func (_mock *MergeRequests) Create(ctx context.Context, p domain.Principal, name | |||
| 236 | 236 | return r0, r1 | |
| 237 | 237 | } | |
| 238 | 238 | ||
| 239 | - | // MergeRequests_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' | |
| 240 | - | type MergeRequests_Create_Call struct { | |
| 239 | + | // MergeRequestService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' | |
| 240 | + | type MergeRequestService_Create_Call struct { | |
| 241 | 241 | *mock.Call | |
| 242 | 242 | } | |
| 243 | 243 | ||
| @@ -245,12 +245,12 @@ type MergeRequests_Create_Call struct { | |||
| 245 | 245 | // - ctx context.Context | |
| 246 | 246 | // - p domain.Principal | |
| 247 | 247 | // - name domain.RepoName | |
| 248 | - | // - params app.CreateMergeRequestParams | |
| 249 | - | func (_e *MergeRequests_Expecter) Create(ctx any, p any, name any, params any) *MergeRequests_Create_Call { | |
| 250 | - | return &MergeRequests_Create_Call{Call: _e.mock.On("Create", ctx, p, name, params)} | |
| 248 | + | // - params ports.CreateMergeRequestParams | |
| 249 | + | func (_e *MergeRequestService_Expecter) Create(ctx any, p any, name any, params any) *MergeRequestService_Create_Call { | |
| 250 | + | return &MergeRequestService_Create_Call{Call: _e.mock.On("Create", ctx, p, name, params)} | |
| 251 | 251 | } | |
| 252 | 252 | ||
| 253 | - | func (_c *MergeRequests_Create_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params app.CreateMergeRequestParams)) *MergeRequests_Create_Call { | |
| 253 | + | func (_c *MergeRequestService_Create_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.CreateMergeRequestParams)) *MergeRequestService_Create_Call { | |
| 254 | 254 | _c.Call.Run(func(args mock.Arguments) { | |
| 255 | 255 | var arg0 context.Context | |
| 256 | 256 | if args[0] != nil { | |
| @@ -264,9 +264,9 @@ func (_c *MergeRequests_Create_Call) Run(run func(ctx context.Context, p domain. | |||
| 264 | 264 | if args[2] != nil { | |
| 265 | 265 | arg2 = args[2].(domain.RepoName) | |
| 266 | 266 | } | |
| 267 | - | var arg3 app.CreateMergeRequestParams | |
| 267 | + | var arg3 ports.CreateMergeRequestParams | |
| 268 | 268 | if args[3] != nil { | |
| 269 | - | arg3 = args[3].(app.CreateMergeRequestParams) | |
| 269 | + | arg3 = args[3].(ports.CreateMergeRequestParams) | |
| 270 | 270 | } | |
| 271 | 271 | run( | |
| 272 | 272 | arg0, | |
| @@ -278,33 +278,33 @@ func (_c *MergeRequests_Create_Call) Run(run func(ctx context.Context, p domain. | |||
| 278 | 278 | return _c | |
| 279 | 279 | } | |
| 280 | 280 | ||
| 281 | - | func (_c *MergeRequests_Create_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequests_Create_Call { | |
| 281 | + | func (_c *MergeRequestService_Create_Call) Return(mergeRequest domain.MergeRequest, err error) *MergeRequestService_Create_Call { | |
| 282 | 282 | _c.Call.Return(mergeRequest, err) | |
| 283 | 283 | return _c | |
| 284 | 284 | } | |
| 285 | 285 | ||
| 286 | - | func (_c *MergeRequests_Create_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params app.CreateMergeRequestParams) (domain.MergeRequest, error)) *MergeRequests_Create_Call { | |
| 286 | + | func (_c *MergeRequestService_Create_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.CreateMergeRequestParams) (domain.MergeRequest, error)) *MergeRequestService_Create_Call { | |
| 287 | 287 | _c.Call.Return(run) | |
| 288 | 288 | return _c | |
| 289 | 289 | } | |
| 290 | 290 | ||
| 291 | - | // Get provides a mock function for the type MergeRequests | |
| 292 | - | func (_mock *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (app.MergeRequestDetail, error) { | |
| 291 | + | // Get provides a mock function for the type MergeRequestService | |
| 292 | + | func (_mock *MergeRequestService) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (ports.MergeRequestDetail, error) { | |
| 293 | 293 | ret := _mock.Called(ctx, p, name, number, sinceLastRead) | |
| 294 | 294 | ||
| 295 | 295 | if len(ret) == 0 { | |
| 296 | 296 | panic("no return value specified for Get") | |
| 297 | 297 | } | |
| 298 | 298 | ||
| 299 | - | var r0 app.MergeRequestDetail | |
| 299 | + | var r0 ports.MergeRequestDetail | |
| 300 | 300 | var r1 error | |
| 301 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, bool) (app.MergeRequestDetail, error)); ok { | |
| 301 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, bool) (ports.MergeRequestDetail, error)); ok { | |
| 302 | 302 | return returnFunc(ctx, p, name, number, sinceLastRead) | |
| 303 | 303 | } | |
| 304 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, bool) app.MergeRequestDetail); ok { | |
| 304 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, bool) ports.MergeRequestDetail); ok { | |
| 305 | 305 | r0 = returnFunc(ctx, p, name, number, sinceLastRead) | |
| 306 | 306 | } else { | |
| 307 | - | r0 = ret.Get(0).(app.MergeRequestDetail) | |
| 307 | + | r0 = ret.Get(0).(ports.MergeRequestDetail) | |
| 308 | 308 | } | |
| 309 | 309 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, bool) error); ok { | |
| 310 | 310 | r1 = returnFunc(ctx, p, name, number, sinceLastRead) | |
| @@ -314,8 +314,8 @@ func (_mock *MergeRequests) Get(ctx context.Context, p domain.Principal, name do | |||
| 314 | 314 | return r0, r1 | |
| 315 | 315 | } | |
| 316 | 316 | ||
| 317 | - | // MergeRequests_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' | |
| 318 | - | type MergeRequests_Get_Call struct { | |
| 317 | + | // MergeRequestService_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' | |
| 318 | + | type MergeRequestService_Get_Call struct { | |
| 319 | 319 | *mock.Call | |
| 320 | 320 | } | |
| 321 | 321 | ||
| @@ -325,11 +325,11 @@ type MergeRequests_Get_Call struct { | |||
| 325 | 325 | // - name domain.RepoName | |
| 326 | 326 | // - number int64 | |
| 327 | 327 | // - sinceLastRead bool | |
| 328 | - | func (_e *MergeRequests_Expecter) Get(ctx any, p any, name any, number any, sinceLastRead any) *MergeRequests_Get_Call { | |
| 329 | - | return &MergeRequests_Get_Call{Call: _e.mock.On("Get", ctx, p, name, number, sinceLastRead)} | |
| 328 | + | func (_e *MergeRequestService_Expecter) Get(ctx any, p any, name any, number any, sinceLastRead any) *MergeRequestService_Get_Call { | |
| 329 | + | return &MergeRequestService_Get_Call{Call: _e.mock.On("Get", ctx, p, name, number, sinceLastRead)} | |
| 330 | 330 | } | |
| 331 | 331 | ||
| 332 | - | func (_c *MergeRequests_Get_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool)) *MergeRequests_Get_Call { | |
| 332 | + | func (_c *MergeRequestService_Get_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool)) *MergeRequestService_Get_Call { | |
| 333 | 333 | _c.Call.Run(func(args mock.Arguments) { | |
| 334 | 334 | var arg0 context.Context | |
| 335 | 335 | if args[0] != nil { | |
| @@ -362,35 +362,35 @@ func (_c *MergeRequests_Get_Call) Run(run func(ctx context.Context, p domain.Pri | |||
| 362 | 362 | return _c | |
| 363 | 363 | } | |
| 364 | 364 | ||
| 365 | - | func (_c *MergeRequests_Get_Call) Return(mergeRequestDetail app.MergeRequestDetail, err error) *MergeRequests_Get_Call { | |
| 365 | + | func (_c *MergeRequestService_Get_Call) Return(mergeRequestDetail ports.MergeRequestDetail, err error) *MergeRequestService_Get_Call { | |
| 366 | 366 | _c.Call.Return(mergeRequestDetail, err) | |
| 367 | 367 | return _c | |
| 368 | 368 | } | |
| 369 | 369 | ||
| 370 | - | func (_c *MergeRequests_Get_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (app.MergeRequestDetail, error)) *MergeRequests_Get_Call { | |
| 370 | + | func (_c *MergeRequestService_Get_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (ports.MergeRequestDetail, error)) *MergeRequestService_Get_Call { | |
| 371 | 371 | _c.Call.Return(run) | |
| 372 | 372 | return _c | |
| 373 | 373 | } | |
| 374 | 374 | ||
| 375 | - | // List provides a mock function for the type MergeRequests | |
| 376 | - | func (_mock *MergeRequests) List(ctx context.Context, p domain.Principal, name domain.RepoName, params app.ListMergeRequestsParams) (app.MergeRequestPage, error) { | |
| 375 | + | // List provides a mock function for the type MergeRequestService | |
| 376 | + | func (_mock *MergeRequestService) List(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.ListMergeRequestsParams) (ports.MergeRequestPage, error) { | |
| 377 | 377 | ret := _mock.Called(ctx, p, name, params) | |
| 378 | 378 | ||
| 379 | 379 | if len(ret) == 0 { | |
| 380 | 380 | panic("no return value specified for List") | |
| 381 | 381 | } | |
| 382 | 382 | ||
| 383 | - | var r0 app.MergeRequestPage | |
| 383 | + | var r0 ports.MergeRequestPage | |
| 384 | 384 | var r1 error | |
| 385 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.ListMergeRequestsParams) (app.MergeRequestPage, error)); ok { | |
| 385 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.ListMergeRequestsParams) (ports.MergeRequestPage, error)); ok { | |
| 386 | 386 | return returnFunc(ctx, p, name, params) | |
| 387 | 387 | } | |
| 388 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.ListMergeRequestsParams) app.MergeRequestPage); ok { | |
| 388 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.ListMergeRequestsParams) ports.MergeRequestPage); ok { | |
| 389 | 389 | r0 = returnFunc(ctx, p, name, params) | |
| 390 | 390 | } else { | |
| 391 | - | r0 = ret.Get(0).(app.MergeRequestPage) | |
| 391 | + | r0 = ret.Get(0).(ports.MergeRequestPage) | |
| 392 | 392 | } | |
| 393 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, app.ListMergeRequestsParams) error); ok { | |
| 393 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, ports.ListMergeRequestsParams) error); ok { | |
| 394 | 394 | r1 = returnFunc(ctx, p, name, params) | |
| 395 | 395 | } else { | |
| 396 | 396 | r1 = ret.Error(1) | |
| @@ -398,8 +398,8 @@ func (_mock *MergeRequests) List(ctx context.Context, p domain.Principal, name d | |||
| 398 | 398 | return r0, r1 | |
| 399 | 399 | } | |
| 400 | 400 | ||
| 401 | - | // MergeRequests_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List' | |
| 402 | - | type MergeRequests_List_Call struct { | |
| 401 | + | // MergeRequestService_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List' | |
| 402 | + | type MergeRequestService_List_Call struct { | |
| 403 | 403 | *mock.Call | |
| 404 | 404 | } | |
| 405 | 405 | ||
| @@ -407,12 +407,12 @@ type MergeRequests_List_Call struct { | |||
| 407 | 407 | // - ctx context.Context | |
| 408 | 408 | // - p domain.Principal | |
| 409 | 409 | // - name domain.RepoName | |
| 410 | - | // - params app.ListMergeRequestsParams | |
| 411 | - | func (_e *MergeRequests_Expecter) List(ctx any, p any, name any, params any) *MergeRequests_List_Call { | |
| 412 | - | return &MergeRequests_List_Call{Call: _e.mock.On("List", ctx, p, name, params)} | |
| 410 | + | // - params ports.ListMergeRequestsParams | |
| 411 | + | func (_e *MergeRequestService_Expecter) List(ctx any, p any, name any, params any) *MergeRequestService_List_Call { | |
| 412 | + | return &MergeRequestService_List_Call{Call: _e.mock.On("List", ctx, p, name, params)} | |
| 413 | 413 | } | |
| 414 | 414 | ||
| 415 | - | func (_c *MergeRequests_List_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params app.ListMergeRequestsParams)) *MergeRequests_List_Call { | |
| 415 | + | func (_c *MergeRequestService_List_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.ListMergeRequestsParams)) *MergeRequestService_List_Call { | |
| 416 | 416 | _c.Call.Run(func(args mock.Arguments) { | |
| 417 | 417 | var arg0 context.Context | |
| 418 | 418 | if args[0] != nil { | |
| @@ -426,9 +426,9 @@ func (_c *MergeRequests_List_Call) Run(run func(ctx context.Context, p domain.Pr | |||
| 426 | 426 | if args[2] != nil { | |
| 427 | 427 | arg2 = args[2].(domain.RepoName) | |
| 428 | 428 | } | |
| 429 | - | var arg3 app.ListMergeRequestsParams | |
| 429 | + | var arg3 ports.ListMergeRequestsParams | |
| 430 | 430 | if args[3] != nil { | |
| 431 | - | arg3 = args[3].(app.ListMergeRequestsParams) | |
| 431 | + | arg3 = args[3].(ports.ListMergeRequestsParams) | |
| 432 | 432 | } | |
| 433 | 433 | run( | |
| 434 | 434 | arg0, | |
| @@ -440,18 +440,18 @@ func (_c *MergeRequests_List_Call) Run(run func(ctx context.Context, p domain.Pr | |||
| 440 | 440 | return _c | |
| 441 | 441 | } | |
| 442 | 442 | ||
| 443 | - | func (_c *MergeRequests_List_Call) Return(mergeRequestPage app.MergeRequestPage, err error) *MergeRequests_List_Call { | |
| 443 | + | func (_c *MergeRequestService_List_Call) Return(mergeRequestPage ports.MergeRequestPage, err error) *MergeRequestService_List_Call { | |
| 444 | 444 | _c.Call.Return(mergeRequestPage, err) | |
| 445 | 445 | return _c | |
| 446 | 446 | } | |
| 447 | 447 | ||
| 448 | - | func (_c *MergeRequests_List_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params app.ListMergeRequestsParams) (app.MergeRequestPage, error)) *MergeRequests_List_Call { | |
| 448 | + | func (_c *MergeRequestService_List_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.ListMergeRequestsParams) (ports.MergeRequestPage, error)) *MergeRequestService_List_Call { | |
| 449 | 449 | _c.Call.Return(run) | |
| 450 | 450 | return _c | |
| 451 | 451 | } | |
| 452 | 452 | ||
| 453 | - | // MarkRead provides a mock function for the type MergeRequests | |
| 454 | - | func (_mock *MergeRequests) MarkRead(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error) { | |
| 453 | + | // MarkRead provides a mock function for the type MergeRequestService | |
| 454 | + | func (_mock *MergeRequestService) MarkRead(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error) { | |
| 455 | 455 | ret := _mock.Called(ctx, p, name, number, head) | |
| 456 | 456 | ||
| 457 | 457 | if len(ret) == 0 { | |
| @@ -476,8 +476,8 @@ func (_mock *MergeRequests) MarkRead(ctx context.Context, p domain.Principal, na | |||
| 476 | 476 | return r0, r1 | |
| 477 | 477 | } | |
| 478 | 478 | ||
| 479 | - | // MergeRequests_MarkRead_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarkRead' | |
| 480 | - | type MergeRequests_MarkRead_Call struct { | |
| 479 | + | // MergeRequestService_MarkRead_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarkRead' | |
| 480 | + | type MergeRequestService_MarkRead_Call struct { | |
| 481 | 481 | *mock.Call | |
| 482 | 482 | } | |
| 483 | 483 | ||
| @@ -487,11 +487,11 @@ type MergeRequests_MarkRead_Call struct { | |||
| 487 | 487 | // - name domain.RepoName | |
| 488 | 488 | // - number int64 | |
| 489 | 489 | // - head domain.ObjectID | |
| 490 | - | func (_e *MergeRequests_Expecter) MarkRead(ctx any, p any, name any, number any, head any) *MergeRequests_MarkRead_Call { | |
| 491 | - | return &MergeRequests_MarkRead_Call{Call: _e.mock.On("MarkRead", ctx, p, name, number, head)} | |
| 490 | + | func (_e *MergeRequestService_Expecter) MarkRead(ctx any, p any, name any, number any, head any) *MergeRequestService_MarkRead_Call { | |
| 491 | + | return &MergeRequestService_MarkRead_Call{Call: _e.mock.On("MarkRead", ctx, p, name, number, head)} | |
| 492 | 492 | } | |
| 493 | 493 | ||
| 494 | - | func (_c *MergeRequests_MarkRead_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID)) *MergeRequests_MarkRead_Call { | |
| 494 | + | func (_c *MergeRequestService_MarkRead_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID)) *MergeRequestService_MarkRead_Call { | |
| 495 | 495 | _c.Call.Run(func(args mock.Arguments) { | |
| 496 | 496 | var arg0 context.Context | |
| 497 | 497 | if args[0] != nil { | |
| @@ -524,35 +524,35 @@ func (_c *MergeRequests_MarkRead_Call) Run(run func(ctx context.Context, p domai | |||
| 524 | 524 | return _c | |
| 525 | 525 | } | |
| 526 | 526 | ||
| 527 | - | func (_c *MergeRequests_MarkRead_Call) Return(objectID domain.ObjectID, err error) *MergeRequests_MarkRead_Call { | |
| 527 | + | func (_c *MergeRequestService_MarkRead_Call) Return(objectID domain.ObjectID, err error) *MergeRequestService_MarkRead_Call { | |
| 528 | 528 | _c.Call.Return(objectID, err) | |
| 529 | 529 | return _c | |
| 530 | 530 | } | |
| 531 | 531 | ||
| 532 | - | func (_c *MergeRequests_MarkRead_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error)) *MergeRequests_MarkRead_Call { | |
| 532 | + | func (_c *MergeRequestService_MarkRead_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error)) *MergeRequestService_MarkRead_Call { | |
| 533 | 533 | _c.Call.Return(run) | |
| 534 | 534 | return _c | |
| 535 | 535 | } | |
| 536 | 536 | ||
| 537 | - | // Merge provides a mock function for the type MergeRequests | |
| 538 | - | func (_mock *MergeRequests) Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.MergeParams) (app.MergeResult, error) { | |
| 537 | + | // Merge provides a mock function for the type MergeRequestService | |
| 538 | + | func (_mock *MergeRequestService) Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.MergeParams) (ports.MergeResult, error) { | |
| 539 | 539 | ret := _mock.Called(ctx, p, name, number, params) | |
| 540 | 540 | ||
| 541 | 541 | if len(ret) == 0 { | |
| 542 | 542 | panic("no return value specified for Merge") | |
| 543 | 543 | } | |
| 544 | 544 | ||
| 545 | - | var r0 app.MergeResult | |
| 545 | + | var r0 ports.MergeResult | |
| 546 | 546 | var r1 error | |
| 547 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, app.MergeParams) (app.MergeResult, error)); ok { | |
| 547 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.MergeParams) (ports.MergeResult, error)); ok { | |
| 548 | 548 | return returnFunc(ctx, p, name, number, params) | |
| 549 | 549 | } | |
| 550 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, app.MergeParams) app.MergeResult); ok { | |
| 550 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.MergeParams) ports.MergeResult); ok { | |
| 551 | 551 | r0 = returnFunc(ctx, p, name, number, params) | |
| 552 | 552 | } else { | |
| 553 | - | r0 = ret.Get(0).(app.MergeResult) | |
| 553 | + | r0 = ret.Get(0).(ports.MergeResult) | |
| 554 | 554 | } | |
| 555 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, app.MergeParams) error); ok { | |
| 555 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, ports.MergeParams) error); ok { | |
| 556 | 556 | r1 = returnFunc(ctx, p, name, number, params) | |
| 557 | 557 | } else { | |
| 558 | 558 | r1 = ret.Error(1) | |
| @@ -560,8 +560,8 @@ func (_mock *MergeRequests) Merge(ctx context.Context, p domain.Principal, name | |||
| 560 | 560 | return r0, r1 | |
| 561 | 561 | } | |
| 562 | 562 | ||
| 563 | - | // MergeRequests_Merge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Merge' | |
| 564 | - | type MergeRequests_Merge_Call struct { | |
| 563 | + | // MergeRequestService_Merge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Merge' | |
| 564 | + | type MergeRequestService_Merge_Call struct { | |
| 565 | 565 | *mock.Call | |
| 566 | 566 | } | |
| 567 | 567 | ||
| @@ -570,12 +570,12 @@ type MergeRequests_Merge_Call struct { | |||
| 570 | 570 | // - p domain.Principal | |
| 571 | 571 | // - name domain.RepoName | |
| 572 | 572 | // - number int64 | |
| 573 | - | // - params app.MergeParams | |
| 574 | - | func (_e *MergeRequests_Expecter) Merge(ctx any, p any, name any, number any, params any) *MergeRequests_Merge_Call { | |
| 575 | - | return &MergeRequests_Merge_Call{Call: _e.mock.On("Merge", ctx, p, name, number, params)} | |
| 573 | + | // - params ports.MergeParams | |
| 574 | + | func (_e *MergeRequestService_Expecter) Merge(ctx any, p any, name any, number any, params any) *MergeRequestService_Merge_Call { | |
| 575 | + | return &MergeRequestService_Merge_Call{Call: _e.mock.On("Merge", ctx, p, name, number, params)} | |
| 576 | 576 | } | |
| 577 | 577 | ||
| 578 | - | func (_c *MergeRequests_Merge_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.MergeParams)) *MergeRequests_Merge_Call { | |
| 578 | + | func (_c *MergeRequestService_Merge_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.MergeParams)) *MergeRequestService_Merge_Call { | |
| 579 | 579 | _c.Call.Run(func(args mock.Arguments) { | |
| 580 | 580 | var arg0 context.Context | |
| 581 | 581 | if args[0] != nil { | |
| @@ -593,9 +593,9 @@ func (_c *MergeRequests_Merge_Call) Run(run func(ctx context.Context, p domain.P | |||
| 593 | 593 | if args[3] != nil { | |
| 594 | 594 | arg3 = args[3].(int64) | |
| 595 | 595 | } | |
| 596 | - | var arg4 app.MergeParams | |
| 596 | + | var arg4 ports.MergeParams | |
| 597 | 597 | if args[4] != nil { | |
| 598 | - | arg4 = args[4].(app.MergeParams) | |
| 598 | + | arg4 = args[4].(ports.MergeParams) | |
| 599 | 599 | } | |
| 600 | 600 | run( | |
| 601 | 601 | arg0, | |
| @@ -608,18 +608,18 @@ func (_c *MergeRequests_Merge_Call) Run(run func(ctx context.Context, p domain.P | |||
| 608 | 608 | return _c | |
| 609 | 609 | } | |
| 610 | 610 | ||
| 611 | - | func (_c *MergeRequests_Merge_Call) Return(mergeResult app.MergeResult, err error) *MergeRequests_Merge_Call { | |
| 611 | + | func (_c *MergeRequestService_Merge_Call) Return(mergeResult ports.MergeResult, err error) *MergeRequestService_Merge_Call { | |
| 612 | 612 | _c.Call.Return(mergeResult, err) | |
| 613 | 613 | return _c | |
| 614 | 614 | } | |
| 615 | 615 | ||
| 616 | - | func (_c *MergeRequests_Merge_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.MergeParams) (app.MergeResult, error)) *MergeRequests_Merge_Call { | |
| 616 | + | func (_c *MergeRequestService_Merge_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.MergeParams) (ports.MergeResult, error)) *MergeRequestService_Merge_Call { | |
| 617 | 617 | _c.Call.Return(run) | |
| 618 | 618 | return _c | |
| 619 | 619 | } | |
| 620 | 620 | ||
| 621 | - | // ResolveComment provides a mock function for the type MergeRequests | |
| 622 | - | func (_mock *MergeRequests) ResolveComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool) (domain.Comment, error) { | |
| 621 | + | // ResolveComment provides a mock function for the type MergeRequestService | |
| 622 | + | func (_mock *MergeRequestService) ResolveComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool) (domain.Comment, error) { | |
| 623 | 623 | ret := _mock.Called(ctx, p, name, number, commentID, resolved) | |
| 624 | 624 | ||
| 625 | 625 | if len(ret) == 0 { | |
| @@ -644,8 +644,8 @@ func (_mock *MergeRequests) ResolveComment(ctx context.Context, p domain.Princip | |||
| 644 | 644 | return r0, r1 | |
| 645 | 645 | } | |
| 646 | 646 | ||
| 647 | - | // MergeRequests_ResolveComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveComment' | |
| 648 | - | type MergeRequests_ResolveComment_Call struct { | |
| 647 | + | // MergeRequestService_ResolveComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveComment' | |
| 648 | + | type MergeRequestService_ResolveComment_Call struct { | |
| 649 | 649 | *mock.Call | |
| 650 | 650 | } | |
| 651 | 651 | ||
| @@ -656,11 +656,11 @@ type MergeRequests_ResolveComment_Call struct { | |||
| 656 | 656 | // - number int64 | |
| 657 | 657 | // - commentID int64 | |
| 658 | 658 | // - resolved bool | |
| 659 | - | func (_e *MergeRequests_Expecter) ResolveComment(ctx any, p any, name any, number any, commentID any, resolved any) *MergeRequests_ResolveComment_Call { | |
| 660 | - | return &MergeRequests_ResolveComment_Call{Call: _e.mock.On("ResolveComment", ctx, p, name, number, commentID, resolved)} | |
| 659 | + | func (_e *MergeRequestService_Expecter) ResolveComment(ctx any, p any, name any, number any, commentID any, resolved any) *MergeRequestService_ResolveComment_Call { | |
| 660 | + | return &MergeRequestService_ResolveComment_Call{Call: _e.mock.On("ResolveComment", ctx, p, name, number, commentID, resolved)} | |
| 661 | 661 | } | |
| 662 | 662 | ||
| 663 | - | func (_c *MergeRequests_ResolveComment_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool)) *MergeRequests_ResolveComment_Call { | |
| 663 | + | func (_c *MergeRequestService_ResolveComment_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool)) *MergeRequestService_ResolveComment_Call { | |
| 664 | 664 | _c.Call.Run(func(args mock.Arguments) { | |
| 665 | 665 | var arg0 context.Context | |
| 666 | 666 | if args[0] != nil { | |
| @@ -698,12 +698,12 @@ func (_c *MergeRequests_ResolveComment_Call) Run(run func(ctx context.Context, p | |||
| 698 | 698 | return _c | |
| 699 | 699 | } | |
| 700 | 700 | ||
| 701 | - | func (_c *MergeRequests_ResolveComment_Call) Return(comment domain.Comment, err error) *MergeRequests_ResolveComment_Call { | |
| 701 | + | func (_c *MergeRequestService_ResolveComment_Call) Return(comment domain.Comment, err error) *MergeRequestService_ResolveComment_Call { | |
| 702 | 702 | _c.Call.Return(comment, err) | |
| 703 | 703 | return _c | |
| 704 | 704 | } | |
| 705 | 705 | ||
| 706 | - | func (_c *MergeRequests_ResolveComment_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool) (domain.Comment, error)) *MergeRequests_ResolveComment_Call { | |
| 706 | + | func (_c *MergeRequestService_ResolveComment_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool) (domain.Comment, error)) *MergeRequestService_ResolveComment_Call { | |
| 707 | 707 | _c.Call.Return(run) | |
| 708 | 708 | return _c | |
| 709 | 709 | } | |
R internal/adapters/githttp/mocks/PushHooks.go → internal/ports/mocks/PushHookService.go +27 -27 renamed, 51% similar
| @@ -11,17 +11,17 @@ import ( | |||
| 11 | 11 | mock "github.com/stretchr/testify/mock" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | // NewPushHooks creates a new instance of PushHooks. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 14 | + | // NewPushHookService creates a new instance of PushHookService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | 15 | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewPushHooks(t interface { | |
| 16 | + | func NewPushHookService(t interface { | |
| 17 | 17 | mock.TestingT | |
| 18 | 18 | Cleanup(func()) | |
| 19 | - | }) *PushHooks { | |
| 19 | + | }) *PushHookService { | |
| 20 | 20 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | 21 | helper.Helper() | |
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | - | mock := &PushHooks{} | |
| 24 | + | mock := &PushHookService{} | |
| 25 | 25 | mock.Mock.Test(t) | |
| 26 | 26 | ||
| 27 | 27 | t.Cleanup(func() { | |
| @@ -34,21 +34,21 @@ func NewPushHooks(t interface { | |||
| 34 | 34 | return mock | |
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | - | // PushHooks is an autogenerated mock type for the PushHooks type | |
| 38 | - | type PushHooks struct { | |
| 37 | + | // PushHookService is an autogenerated mock type for the PushHookService type | |
| 38 | + | type PushHookService struct { | |
| 39 | 39 | mock.Mock | |
| 40 | 40 | } | |
| 41 | 41 | ||
| 42 | - | type PushHooks_Expecter struct { | |
| 42 | + | type PushHookService_Expecter struct { | |
| 43 | 43 | mock *mock.Mock | |
| 44 | 44 | } | |
| 45 | 45 | ||
| 46 | - | func (_m *PushHooks) EXPECT() *PushHooks_Expecter { | |
| 47 | - | return &PushHooks_Expecter{mock: &_m.Mock} | |
| 46 | + | func (_m *PushHookService) EXPECT() *PushHookService_Expecter { | |
| 47 | + | return &PushHookService_Expecter{mock: &_m.Mock} | |
| 48 | 48 | } | |
| 49 | 49 | ||
| 50 | - | // Check provides a mock function for the type PushHooks | |
| 51 | - | func (_mock *PushHooks) Check(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { | |
| 50 | + | // Check provides a mock function for the type PushHookService | |
| 51 | + | func (_mock *PushHookService) Check(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { | |
| 52 | 52 | ret := _mock.Called(ctx, p, name, updates) | |
| 53 | 53 | ||
| 54 | 54 | if len(ret) == 0 { | |
| @@ -64,8 +64,8 @@ func (_mock *PushHooks) Check(ctx context.Context, p domain.Principal, name doma | |||
| 64 | 64 | return r0 | |
| 65 | 65 | } | |
| 66 | 66 | ||
| 67 | - | // PushHooks_Check_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Check' | |
| 68 | - | type PushHooks_Check_Call struct { | |
| 67 | + | // PushHookService_Check_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Check' | |
| 68 | + | type PushHookService_Check_Call struct { | |
| 69 | 69 | *mock.Call | |
| 70 | 70 | } | |
| 71 | 71 | ||
| @@ -74,11 +74,11 @@ type PushHooks_Check_Call struct { | |||
| 74 | 74 | // - p domain.Principal | |
| 75 | 75 | // - name domain.RepoName | |
| 76 | 76 | // - updates []domain.RefUpdate | |
| 77 | - | func (_e *PushHooks_Expecter) Check(ctx any, p any, name any, updates any) *PushHooks_Check_Call { | |
| 78 | - | return &PushHooks_Check_Call{Call: _e.mock.On("Check", ctx, p, name, updates)} | |
| 77 | + | func (_e *PushHookService_Expecter) Check(ctx any, p any, name any, updates any) *PushHookService_Check_Call { | |
| 78 | + | return &PushHookService_Check_Call{Call: _e.mock.On("Check", ctx, p, name, updates)} | |
| 79 | 79 | } | |
| 80 | 80 | ||
| 81 | - | func (_c *PushHooks_Check_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate)) *PushHooks_Check_Call { | |
| 81 | + | func (_c *PushHookService_Check_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate)) *PushHookService_Check_Call { | |
| 82 | 82 | _c.Call.Run(func(args mock.Arguments) { | |
| 83 | 83 | var arg0 context.Context | |
| 84 | 84 | if args[0] != nil { | |
| @@ -106,18 +106,18 @@ func (_c *PushHooks_Check_Call) Run(run func(ctx context.Context, p domain.Princ | |||
| 106 | 106 | return _c | |
| 107 | 107 | } | |
| 108 | 108 | ||
| 109 | - | func (_c *PushHooks_Check_Call) Return(err error) *PushHooks_Check_Call { | |
| 109 | + | func (_c *PushHookService_Check_Call) Return(err error) *PushHookService_Check_Call { | |
| 110 | 110 | _c.Call.Return(err) | |
| 111 | 111 | return _c | |
| 112 | 112 | } | |
| 113 | 113 | ||
| 114 | - | func (_c *PushHooks_Check_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error) *PushHooks_Check_Call { | |
| 114 | + | func (_c *PushHookService_Check_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error) *PushHookService_Check_Call { | |
| 115 | 115 | _c.Call.Return(run) | |
| 116 | 116 | return _c | |
| 117 | 117 | } | |
| 118 | 118 | ||
| 119 | - | // Record provides a mock function for the type PushHooks | |
| 120 | - | func (_mock *PushHooks) Record(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { | |
| 119 | + | // Record provides a mock function for the type PushHookService | |
| 120 | + | func (_mock *PushHookService) Record(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { | |
| 121 | 121 | ret := _mock.Called(ctx, p, name, updates) | |
| 122 | 122 | ||
| 123 | 123 | if len(ret) == 0 { | |
| @@ -133,8 +133,8 @@ func (_mock *PushHooks) Record(ctx context.Context, p domain.Principal, name dom | |||
| 133 | 133 | return r0 | |
| 134 | 134 | } | |
| 135 | 135 | ||
| 136 | - | // PushHooks_Record_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Record' | |
| 137 | - | type PushHooks_Record_Call struct { | |
| 136 | + | // PushHookService_Record_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Record' | |
| 137 | + | type PushHookService_Record_Call struct { | |
| 138 | 138 | *mock.Call | |
| 139 | 139 | } | |
| 140 | 140 | ||
| @@ -143,11 +143,11 @@ type PushHooks_Record_Call struct { | |||
| 143 | 143 | // - p domain.Principal | |
| 144 | 144 | // - name domain.RepoName | |
| 145 | 145 | // - updates []domain.RefUpdate | |
| 146 | - | func (_e *PushHooks_Expecter) Record(ctx any, p any, name any, updates any) *PushHooks_Record_Call { | |
| 147 | - | return &PushHooks_Record_Call{Call: _e.mock.On("Record", ctx, p, name, updates)} | |
| 146 | + | func (_e *PushHookService_Expecter) Record(ctx any, p any, name any, updates any) *PushHookService_Record_Call { | |
| 147 | + | return &PushHookService_Record_Call{Call: _e.mock.On("Record", ctx, p, name, updates)} | |
| 148 | 148 | } | |
| 149 | 149 | ||
| 150 | - | func (_c *PushHooks_Record_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate)) *PushHooks_Record_Call { | |
| 150 | + | func (_c *PushHookService_Record_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate)) *PushHookService_Record_Call { | |
| 151 | 151 | _c.Call.Run(func(args mock.Arguments) { | |
| 152 | 152 | var arg0 context.Context | |
| 153 | 153 | if args[0] != nil { | |
| @@ -175,12 +175,12 @@ func (_c *PushHooks_Record_Call) Run(run func(ctx context.Context, p domain.Prin | |||
| 175 | 175 | return _c | |
| 176 | 176 | } | |
| 177 | 177 | ||
| 178 | - | func (_c *PushHooks_Record_Call) Return(err error) *PushHooks_Record_Call { | |
| 178 | + | func (_c *PushHookService_Record_Call) Return(err error) *PushHookService_Record_Call { | |
| 179 | 179 | _c.Call.Return(err) | |
| 180 | 180 | return _c | |
| 181 | 181 | } | |
| 182 | 182 | ||
| 183 | - | func (_c *PushHooks_Record_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error) *PushHooks_Record_Call { | |
| 183 | + | func (_c *PushHookService_Record_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error) *PushHookService_Record_Call { | |
| 184 | 184 | _c.Call.Return(run) | |
| 185 | 185 | return _c | |
| 186 | 186 | } | |
R internal/adapters/githttp/mocks/Pushes.go → internal/ports/mocks/PushService.go +18 -18 renamed, 53% similar
| @@ -11,17 +11,17 @@ import ( | |||
| 11 | 11 | mock "github.com/stretchr/testify/mock" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | // NewPushes creates a new instance of Pushes. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 14 | + | // NewPushService creates a new instance of PushService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | 15 | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewPushes(t interface { | |
| 16 | + | func NewPushService(t interface { | |
| 17 | 17 | mock.TestingT | |
| 18 | 18 | Cleanup(func()) | |
| 19 | - | }) *Pushes { | |
| 19 | + | }) *PushService { | |
| 20 | 20 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | 21 | helper.Helper() | |
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | - | mock := &Pushes{} | |
| 24 | + | mock := &PushService{} | |
| 25 | 25 | mock.Mock.Test(t) | |
| 26 | 26 | ||
| 27 | 27 | t.Cleanup(func() { | |
| @@ -34,21 +34,21 @@ func NewPushes(t interface { | |||
| 34 | 34 | return mock | |
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | - | // Pushes is an autogenerated mock type for the Pushes type | |
| 38 | - | type Pushes struct { | |
| 37 | + | // PushService is an autogenerated mock type for the PushService type | |
| 38 | + | type PushService struct { | |
| 39 | 39 | mock.Mock | |
| 40 | 40 | } | |
| 41 | 41 | ||
| 42 | - | type Pushes_Expecter struct { | |
| 42 | + | type PushService_Expecter struct { | |
| 43 | 43 | mock *mock.Mock | |
| 44 | 44 | } | |
| 45 | 45 | ||
| 46 | - | func (_m *Pushes) EXPECT() *Pushes_Expecter { | |
| 47 | - | return &Pushes_Expecter{mock: &_m.Mock} | |
| 46 | + | func (_m *PushService) EXPECT() *PushService_Expecter { | |
| 47 | + | return &PushService_Expecter{mock: &_m.Mock} | |
| 48 | 48 | } | |
| 49 | 49 | ||
| 50 | - | // Open provides a mock function for the type Pushes | |
| 51 | - | func (_mock *Pushes) Open(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error { | |
| 50 | + | // Open provides a mock function for the type PushService | |
| 51 | + | func (_mock *PushService) Open(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error { | |
| 52 | 52 | ret := _mock.Called(ctx, p, name, create) | |
| 53 | 53 | ||
| 54 | 54 | if len(ret) == 0 { | |
| @@ -64,8 +64,8 @@ func (_mock *Pushes) Open(ctx context.Context, p domain.Principal, name domain.R | |||
| 64 | 64 | return r0 | |
| 65 | 65 | } | |
| 66 | 66 | ||
| 67 | - | // Pushes_Open_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Open' | |
| 68 | - | type Pushes_Open_Call struct { | |
| 67 | + | // PushService_Open_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Open' | |
| 68 | + | type PushService_Open_Call struct { | |
| 69 | 69 | *mock.Call | |
| 70 | 70 | } | |
| 71 | 71 | ||
| @@ -74,11 +74,11 @@ type Pushes_Open_Call struct { | |||
| 74 | 74 | // - p domain.Principal | |
| 75 | 75 | // - name domain.RepoName | |
| 76 | 76 | // - create bool | |
| 77 | - | func (_e *Pushes_Expecter) Open(ctx any, p any, name any, create any) *Pushes_Open_Call { | |
| 78 | - | return &Pushes_Open_Call{Call: _e.mock.On("Open", ctx, p, name, create)} | |
| 77 | + | func (_e *PushService_Expecter) Open(ctx any, p any, name any, create any) *PushService_Open_Call { | |
| 78 | + | return &PushService_Open_Call{Call: _e.mock.On("Open", ctx, p, name, create)} | |
| 79 | 79 | } | |
| 80 | 80 | ||
| 81 | - | func (_c *Pushes_Open_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, create bool)) *Pushes_Open_Call { | |
| 81 | + | func (_c *PushService_Open_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, create bool)) *PushService_Open_Call { | |
| 82 | 82 | _c.Call.Run(func(args mock.Arguments) { | |
| 83 | 83 | var arg0 context.Context | |
| 84 | 84 | if args[0] != nil { | |
| @@ -106,12 +106,12 @@ func (_c *Pushes_Open_Call) Run(run func(ctx context.Context, p domain.Principal | |||
| 106 | 106 | return _c | |
| 107 | 107 | } | |
| 108 | 108 | ||
| 109 | - | func (_c *Pushes_Open_Call) Return(err error) *Pushes_Open_Call { | |
| 109 | + | func (_c *PushService_Open_Call) Return(err error) *PushService_Open_Call { | |
| 110 | 110 | _c.Call.Return(err) | |
| 111 | 111 | return _c | |
| 112 | 112 | } | |
| 113 | 113 | ||
| 114 | - | func (_c *Pushes_Open_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error) *Pushes_Open_Call { | |
| 114 | + | func (_c *PushService_Open_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error) *PushService_Open_Call { | |
| 115 | 115 | _c.Call.Return(run) | |
| 116 | 116 | return _c | |
| 117 | 117 | } | |
R internal/adapters/githttp/mocks/Repos.go → internal/ports/mocks/RepoLookup.go +18 -18 renamed, 58% similar
| @@ -11,17 +11,17 @@ import ( | |||
| 11 | 11 | mock "github.com/stretchr/testify/mock" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | // NewRepos creates a new instance of Repos. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 14 | + | // NewRepoLookup creates a new instance of RepoLookup. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | 15 | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewRepos(t interface { | |
| 16 | + | func NewRepoLookup(t interface { | |
| 17 | 17 | mock.TestingT | |
| 18 | 18 | Cleanup(func()) | |
| 19 | - | }) *Repos { | |
| 19 | + | }) *RepoLookup { | |
| 20 | 20 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | 21 | helper.Helper() | |
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | - | mock := &Repos{} | |
| 24 | + | mock := &RepoLookup{} | |
| 25 | 25 | mock.Mock.Test(t) | |
| 26 | 26 | ||
| 27 | 27 | t.Cleanup(func() { | |
| @@ -34,21 +34,21 @@ func NewRepos(t interface { | |||
| 34 | 34 | return mock | |
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | - | // Repos is an autogenerated mock type for the Repos type | |
| 38 | - | type Repos struct { | |
| 37 | + | // RepoLookup is an autogenerated mock type for the RepoLookup type | |
| 38 | + | type RepoLookup struct { | |
| 39 | 39 | mock.Mock | |
| 40 | 40 | } | |
| 41 | 41 | ||
| 42 | - | type Repos_Expecter struct { | |
| 42 | + | type RepoLookup_Expecter struct { | |
| 43 | 43 | mock *mock.Mock | |
| 44 | 44 | } | |
| 45 | 45 | ||
| 46 | - | func (_m *Repos) EXPECT() *Repos_Expecter { | |
| 47 | - | return &Repos_Expecter{mock: &_m.Mock} | |
| 46 | + | func (_m *RepoLookup) EXPECT() *RepoLookup_Expecter { | |
| 47 | + | return &RepoLookup_Expecter{mock: &_m.Mock} | |
| 48 | 48 | } | |
| 49 | 49 | ||
| 50 | - | // Get provides a mock function for the type Repos | |
| 51 | - | func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { | |
| 50 | + | // Get provides a mock function for the type RepoLookup | |
| 51 | + | func (_mock *RepoLookup) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { | |
| 52 | 52 | ret := _mock.Called(ctx, p, name) | |
| 53 | 53 | ||
| 54 | 54 | if len(ret) == 0 { | |
| @@ -73,8 +73,8 @@ func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.Rep | |||
| 73 | 73 | return r0, r1 | |
| 74 | 74 | } | |
| 75 | 75 | ||
| 76 | - | // Repos_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' | |
| 77 | - | type Repos_Get_Call struct { | |
| 76 | + | // RepoLookup_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' | |
| 77 | + | type RepoLookup_Get_Call struct { | |
| 78 | 78 | *mock.Call | |
| 79 | 79 | } | |
| 80 | 80 | ||
| @@ -82,11 +82,11 @@ type Repos_Get_Call struct { | |||
| 82 | 82 | // - ctx context.Context | |
| 83 | 83 | // - p domain.Principal | |
| 84 | 84 | // - name domain.RepoName | |
| 85 | - | func (_e *Repos_Expecter) Get(ctx any, p any, name any) *Repos_Get_Call { | |
| 86 | - | return &Repos_Get_Call{Call: _e.mock.On("Get", ctx, p, name)} | |
| 85 | + | func (_e *RepoLookup_Expecter) Get(ctx any, p any, name any) *RepoLookup_Get_Call { | |
| 86 | + | return &RepoLookup_Get_Call{Call: _e.mock.On("Get", ctx, p, name)} | |
| 87 | 87 | } | |
| 88 | 88 | ||
| 89 | - | func (_c *Repos_Get_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName)) *Repos_Get_Call { | |
| 89 | + | func (_c *RepoLookup_Get_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName)) *RepoLookup_Get_Call { | |
| 90 | 90 | _c.Call.Run(func(args mock.Arguments) { | |
| 91 | 91 | var arg0 context.Context | |
| 92 | 92 | if args[0] != nil { | |
| @@ -109,12 +109,12 @@ func (_c *Repos_Get_Call) Run(run func(ctx context.Context, p domain.Principal, | |||
| 109 | 109 | return _c | |
| 110 | 110 | } | |
| 111 | 111 | ||
| 112 | - | func (_c *Repos_Get_Call) Return(repo domain.Repo, err error) *Repos_Get_Call { | |
| 112 | + | func (_c *RepoLookup_Get_Call) Return(repo domain.Repo, err error) *RepoLookup_Get_Call { | |
| 113 | 113 | _c.Call.Return(repo, err) | |
| 114 | 114 | return _c | |
| 115 | 115 | } | |
| 116 | 116 | ||
| 117 | - | func (_c *Repos_Get_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error)) *Repos_Get_Call { | |
| 117 | + | func (_c *RepoLookup_Get_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error)) *RepoLookup_Get_Call { | |
| 118 | 118 | _c.Call.Return(run) | |
| 119 | 119 | return _c | |
| 120 | 120 | } | |
R internal/adapters/rpc/mocks/Repos.go → internal/ports/mocks/RepoService.go +84 -84 renamed, 50% similar
| @@ -7,22 +7,22 @@ package mocks | |||
| 7 | 7 | import ( | |
| 8 | 8 | "context" | |
| 9 | 9 | ||
| 10 | - | "bnema.dev/ermite/internal/app" | |
| 11 | 10 | "bnema.dev/ermite/internal/domain" | |
| 11 | + | "bnema.dev/ermite/internal/ports" | |
| 12 | 12 | mock "github.com/stretchr/testify/mock" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | - | // NewRepos creates a new instance of Repos. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | + | // NewRepoService creates a new instance of RepoService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | 16 | // The first argument is typically a *testing.T value. | |
| 17 | - | func NewRepos(t interface { | |
| 17 | + | func NewRepoService(t interface { | |
| 18 | 18 | mock.TestingT | |
| 19 | 19 | Cleanup(func()) | |
| 20 | - | }) *Repos { | |
| 20 | + | }) *RepoService { | |
| 21 | 21 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | 22 | helper.Helper() | |
| 23 | 23 | } | |
| 24 | 24 | ||
| 25 | - | mock := &Repos{} | |
| 25 | + | mock := &RepoService{} | |
| 26 | 26 | mock.Mock.Test(t) | |
| 27 | 27 | ||
| 28 | 28 | t.Cleanup(func() { | |
| @@ -35,21 +35,21 @@ func NewRepos(t interface { | |||
| 35 | 35 | return mock | |
| 36 | 36 | } | |
| 37 | 37 | ||
| 38 | - | // Repos is an autogenerated mock type for the Repos type | |
| 39 | - | type Repos struct { | |
| 38 | + | // RepoService is an autogenerated mock type for the RepoService type | |
| 39 | + | type RepoService struct { | |
| 40 | 40 | mock.Mock | |
| 41 | 41 | } | |
| 42 | 42 | ||
| 43 | - | type Repos_Expecter struct { | |
| 43 | + | type RepoService_Expecter struct { | |
| 44 | 44 | mock *mock.Mock | |
| 45 | 45 | } | |
| 46 | 46 | ||
| 47 | - | func (_m *Repos) EXPECT() *Repos_Expecter { | |
| 48 | - | return &Repos_Expecter{mock: &_m.Mock} | |
| 47 | + | func (_m *RepoService) EXPECT() *RepoService_Expecter { | |
| 48 | + | return &RepoService_Expecter{mock: &_m.Mock} | |
| 49 | 49 | } | |
| 50 | 50 | ||
| 51 | - | // Create provides a mock function for the type Repos | |
| 52 | - | func (_mock *Repos) Create(ctx context.Context, p domain.Principal, params app.CreateParams) (domain.Repo, error) { | |
| 51 | + | // Create provides a mock function for the type RepoService | |
| 52 | + | func (_mock *RepoService) Create(ctx context.Context, p domain.Principal, params ports.CreateRepoParams) (domain.Repo, error) { | |
| 53 | 53 | ret := _mock.Called(ctx, p, params) | |
| 54 | 54 | ||
| 55 | 55 | if len(ret) == 0 { | |
| @@ -58,15 +58,15 @@ func (_mock *Repos) Create(ctx context.Context, p domain.Principal, params app.C | |||
| 58 | 58 | ||
| 59 | 59 | var r0 domain.Repo | |
| 60 | 60 | var r1 error | |
| 61 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, app.CreateParams) (domain.Repo, error)); ok { | |
| 61 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, ports.CreateRepoParams) (domain.Repo, error)); ok { | |
| 62 | 62 | return returnFunc(ctx, p, params) | |
| 63 | 63 | } | |
| 64 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, app.CreateParams) domain.Repo); ok { | |
| 64 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, ports.CreateRepoParams) domain.Repo); ok { | |
| 65 | 65 | r0 = returnFunc(ctx, p, params) | |
| 66 | 66 | } else { | |
| 67 | 67 | r0 = ret.Get(0).(domain.Repo) | |
| 68 | 68 | } | |
| 69 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, app.CreateParams) error); ok { | |
| 69 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, ports.CreateRepoParams) error); ok { | |
| 70 | 70 | r1 = returnFunc(ctx, p, params) | |
| 71 | 71 | } else { | |
| 72 | 72 | r1 = ret.Error(1) | |
| @@ -74,20 +74,20 @@ func (_mock *Repos) Create(ctx context.Context, p domain.Principal, params app.C | |||
| 74 | 74 | return r0, r1 | |
| 75 | 75 | } | |
| 76 | 76 | ||
| 77 | - | // Repos_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' | |
| 78 | - | type Repos_Create_Call struct { | |
| 77 | + | // RepoService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' | |
| 78 | + | type RepoService_Create_Call struct { | |
| 79 | 79 | *mock.Call | |
| 80 | 80 | } | |
| 81 | 81 | ||
| 82 | 82 | // Create is a helper method to define mock.On call | |
| 83 | 83 | // - ctx context.Context | |
| 84 | 84 | // - p domain.Principal | |
| 85 | - | // - params app.CreateParams | |
| 86 | - | func (_e *Repos_Expecter) Create(ctx any, p any, params any) *Repos_Create_Call { | |
| 87 | - | return &Repos_Create_Call{Call: _e.mock.On("Create", ctx, p, params)} | |
| 85 | + | // - params ports.CreateRepoParams | |
| 86 | + | func (_e *RepoService_Expecter) Create(ctx any, p any, params any) *RepoService_Create_Call { | |
| 87 | + | return &RepoService_Create_Call{Call: _e.mock.On("Create", ctx, p, params)} | |
| 88 | 88 | } | |
| 89 | 89 | ||
| 90 | - | func (_c *Repos_Create_Call) Run(run func(ctx context.Context, p domain.Principal, params app.CreateParams)) *Repos_Create_Call { | |
| 90 | + | func (_c *RepoService_Create_Call) Run(run func(ctx context.Context, p domain.Principal, params ports.CreateRepoParams)) *RepoService_Create_Call { | |
| 91 | 91 | _c.Call.Run(func(args mock.Arguments) { | |
| 92 | 92 | var arg0 context.Context | |
| 93 | 93 | if args[0] != nil { | |
| @@ -97,9 +97,9 @@ func (_c *Repos_Create_Call) Run(run func(ctx context.Context, p domain.Principa | |||
| 97 | 97 | if args[1] != nil { | |
| 98 | 98 | arg1 = args[1].(domain.Principal) | |
| 99 | 99 | } | |
| 100 | - | var arg2 app.CreateParams | |
| 100 | + | var arg2 ports.CreateRepoParams | |
| 101 | 101 | if args[2] != nil { | |
| 102 | - | arg2 = args[2].(app.CreateParams) | |
| 102 | + | arg2 = args[2].(ports.CreateRepoParams) | |
| 103 | 103 | } | |
| 104 | 104 | run( | |
| 105 | 105 | arg0, | |
| @@ -110,18 +110,18 @@ func (_c *Repos_Create_Call) Run(run func(ctx context.Context, p domain.Principa | |||
| 110 | 110 | return _c | |
| 111 | 111 | } | |
| 112 | 112 | ||
| 113 | - | func (_c *Repos_Create_Call) Return(repo domain.Repo, err error) *Repos_Create_Call { | |
| 113 | + | func (_c *RepoService_Create_Call) Return(repo domain.Repo, err error) *RepoService_Create_Call { | |
| 114 | 114 | _c.Call.Return(repo, err) | |
| 115 | 115 | return _c | |
| 116 | 116 | } | |
| 117 | 117 | ||
| 118 | - | func (_c *Repos_Create_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, params app.CreateParams) (domain.Repo, error)) *Repos_Create_Call { | |
| 118 | + | func (_c *RepoService_Create_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, params ports.CreateRepoParams) (domain.Repo, error)) *RepoService_Create_Call { | |
| 119 | 119 | _c.Call.Return(run) | |
| 120 | 120 | return _c | |
| 121 | 121 | } | |
| 122 | 122 | ||
| 123 | - | // Delete provides a mock function for the type Repos | |
| 124 | - | func (_mock *Repos) Delete(ctx context.Context, p domain.Principal, name domain.RepoName) error { | |
| 123 | + | // Delete provides a mock function for the type RepoService | |
| 124 | + | func (_mock *RepoService) Delete(ctx context.Context, p domain.Principal, name domain.RepoName) error { | |
| 125 | 125 | ret := _mock.Called(ctx, p, name) | |
| 126 | 126 | ||
| 127 | 127 | if len(ret) == 0 { | |
| @@ -137,8 +137,8 @@ func (_mock *Repos) Delete(ctx context.Context, p domain.Principal, name domain. | |||
| 137 | 137 | return r0 | |
| 138 | 138 | } | |
| 139 | 139 | ||
| 140 | - | // Repos_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' | |
| 141 | - | type Repos_Delete_Call struct { | |
| 140 | + | // RepoService_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' | |
| 141 | + | type RepoService_Delete_Call struct { | |
| 142 | 142 | *mock.Call | |
| 143 | 143 | } | |
| 144 | 144 | ||
| @@ -146,11 +146,11 @@ type Repos_Delete_Call struct { | |||
| 146 | 146 | // - ctx context.Context | |
| 147 | 147 | // - p domain.Principal | |
| 148 | 148 | // - name domain.RepoName | |
| 149 | - | func (_e *Repos_Expecter) Delete(ctx any, p any, name any) *Repos_Delete_Call { | |
| 150 | - | return &Repos_Delete_Call{Call: _e.mock.On("Delete", ctx, p, name)} | |
| 149 | + | func (_e *RepoService_Expecter) Delete(ctx any, p any, name any) *RepoService_Delete_Call { | |
| 150 | + | return &RepoService_Delete_Call{Call: _e.mock.On("Delete", ctx, p, name)} | |
| 151 | 151 | } | |
| 152 | 152 | ||
| 153 | - | func (_c *Repos_Delete_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName)) *Repos_Delete_Call { | |
| 153 | + | func (_c *RepoService_Delete_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName)) *RepoService_Delete_Call { | |
| 154 | 154 | _c.Call.Run(func(args mock.Arguments) { | |
| 155 | 155 | var arg0 context.Context | |
| 156 | 156 | if args[0] != nil { | |
| @@ -173,18 +173,18 @@ func (_c *Repos_Delete_Call) Run(run func(ctx context.Context, p domain.Principa | |||
| 173 | 173 | return _c | |
| 174 | 174 | } | |
| 175 | 175 | ||
| 176 | - | func (_c *Repos_Delete_Call) Return(err error) *Repos_Delete_Call { | |
| 176 | + | func (_c *RepoService_Delete_Call) Return(err error) *RepoService_Delete_Call { | |
| 177 | 177 | _c.Call.Return(err) | |
| 178 | 178 | return _c | |
| 179 | 179 | } | |
| 180 | 180 | ||
| 181 | - | func (_c *Repos_Delete_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName) error) *Repos_Delete_Call { | |
| 181 | + | func (_c *RepoService_Delete_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName) error) *RepoService_Delete_Call { | |
| 182 | 182 | _c.Call.Return(run) | |
| 183 | 183 | return _c | |
| 184 | 184 | } | |
| 185 | 185 | ||
| 186 | - | // Get provides a mock function for the type Repos | |
| 187 | - | func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { | |
| 186 | + | // Get provides a mock function for the type RepoService | |
| 187 | + | func (_mock *RepoService) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { | |
| 188 | 188 | ret := _mock.Called(ctx, p, name) | |
| 189 | 189 | ||
| 190 | 190 | if len(ret) == 0 { | |
| @@ -209,8 +209,8 @@ func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.Rep | |||
| 209 | 209 | return r0, r1 | |
| 210 | 210 | } | |
| 211 | 211 | ||
| 212 | - | // Repos_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' | |
| 213 | - | type Repos_Get_Call struct { | |
| 212 | + | // RepoService_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' | |
| 213 | + | type RepoService_Get_Call struct { | |
| 214 | 214 | *mock.Call | |
| 215 | 215 | } | |
| 216 | 216 | ||
| @@ -218,11 +218,11 @@ type Repos_Get_Call struct { | |||
| 218 | 218 | // - ctx context.Context | |
| 219 | 219 | // - p domain.Principal | |
| 220 | 220 | // - name domain.RepoName | |
| 221 | - | func (_e *Repos_Expecter) Get(ctx any, p any, name any) *Repos_Get_Call { | |
| 222 | - | return &Repos_Get_Call{Call: _e.mock.On("Get", ctx, p, name)} | |
| 221 | + | func (_e *RepoService_Expecter) Get(ctx any, p any, name any) *RepoService_Get_Call { | |
| 222 | + | return &RepoService_Get_Call{Call: _e.mock.On("Get", ctx, p, name)} | |
| 223 | 223 | } | |
| 224 | 224 | ||
| 225 | - | func (_c *Repos_Get_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName)) *Repos_Get_Call { | |
| 225 | + | func (_c *RepoService_Get_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName)) *RepoService_Get_Call { | |
| 226 | 226 | _c.Call.Run(func(args mock.Arguments) { | |
| 227 | 227 | var arg0 context.Context | |
| 228 | 228 | if args[0] != nil { | |
| @@ -245,33 +245,33 @@ func (_c *Repos_Get_Call) Run(run func(ctx context.Context, p domain.Principal, | |||
| 245 | 245 | return _c | |
| 246 | 246 | } | |
| 247 | 247 | ||
| 248 | - | func (_c *Repos_Get_Call) Return(repo domain.Repo, err error) *Repos_Get_Call { | |
| 248 | + | func (_c *RepoService_Get_Call) Return(repo domain.Repo, err error) *RepoService_Get_Call { | |
| 249 | 249 | _c.Call.Return(repo, err) | |
| 250 | 250 | return _c | |
| 251 | 251 | } | |
| 252 | 252 | ||
| 253 | - | func (_c *Repos_Get_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error)) *Repos_Get_Call { | |
| 253 | + | func (_c *RepoService_Get_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error)) *RepoService_Get_Call { | |
| 254 | 254 | _c.Call.Return(run) | |
| 255 | 255 | return _c | |
| 256 | 256 | } | |
| 257 | 257 | ||
| 258 | - | // ListPage provides a mock function for the type Repos | |
| 259 | - | func (_mock *Repos) ListPage(ctx context.Context, p domain.Principal, size int, token string) (app.RepoPage, error) { | |
| 258 | + | // ListPage provides a mock function for the type RepoService | |
| 259 | + | func (_mock *RepoService) ListPage(ctx context.Context, p domain.Principal, size int, token string) (ports.RepoPage, error) { | |
| 260 | 260 | ret := _mock.Called(ctx, p, size, token) | |
| 261 | 261 | ||
| 262 | 262 | if len(ret) == 0 { | |
| 263 | 263 | panic("no return value specified for ListPage") | |
| 264 | 264 | } | |
| 265 | 265 | ||
| 266 | - | var r0 app.RepoPage | |
| 266 | + | var r0 ports.RepoPage | |
| 267 | 267 | var r1 error | |
| 268 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) (app.RepoPage, error)); ok { | |
| 268 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) (ports.RepoPage, error)); ok { | |
| 269 | 269 | return returnFunc(ctx, p, size, token) | |
| 270 | 270 | } | |
| 271 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) app.RepoPage); ok { | |
| 271 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) ports.RepoPage); ok { | |
| 272 | 272 | r0 = returnFunc(ctx, p, size, token) | |
| 273 | 273 | } else { | |
| 274 | - | r0 = ret.Get(0).(app.RepoPage) | |
| 274 | + | r0 = ret.Get(0).(ports.RepoPage) | |
| 275 | 275 | } | |
| 276 | 276 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, int, string) error); ok { | |
| 277 | 277 | r1 = returnFunc(ctx, p, size, token) | |
| @@ -281,8 +281,8 @@ func (_mock *Repos) ListPage(ctx context.Context, p domain.Principal, size int, | |||
| 281 | 281 | return r0, r1 | |
| 282 | 282 | } | |
| 283 | 283 | ||
| 284 | - | // Repos_ListPage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListPage' | |
| 285 | - | type Repos_ListPage_Call struct { | |
| 284 | + | // RepoService_ListPage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListPage' | |
| 285 | + | type RepoService_ListPage_Call struct { | |
| 286 | 286 | *mock.Call | |
| 287 | 287 | } | |
| 288 | 288 | ||
| @@ -291,11 +291,11 @@ type Repos_ListPage_Call struct { | |||
| 291 | 291 | // - p domain.Principal | |
| 292 | 292 | // - size int | |
| 293 | 293 | // - token string | |
| 294 | - | func (_e *Repos_Expecter) ListPage(ctx any, p any, size any, token any) *Repos_ListPage_Call { | |
| 295 | - | return &Repos_ListPage_Call{Call: _e.mock.On("ListPage", ctx, p, size, token)} | |
| 294 | + | func (_e *RepoService_Expecter) ListPage(ctx any, p any, size any, token any) *RepoService_ListPage_Call { | |
| 295 | + | return &RepoService_ListPage_Call{Call: _e.mock.On("ListPage", ctx, p, size, token)} | |
| 296 | 296 | } | |
| 297 | 297 | ||
| 298 | - | func (_c *Repos_ListPage_Call) Run(run func(ctx context.Context, p domain.Principal, size int, token string)) *Repos_ListPage_Call { | |
| 298 | + | func (_c *RepoService_ListPage_Call) Run(run func(ctx context.Context, p domain.Principal, size int, token string)) *RepoService_ListPage_Call { | |
| 299 | 299 | _c.Call.Run(func(args mock.Arguments) { | |
| 300 | 300 | var arg0 context.Context | |
| 301 | 301 | if args[0] != nil { | |
| @@ -323,18 +323,18 @@ func (_c *Repos_ListPage_Call) Run(run func(ctx context.Context, p domain.Princi | |||
| 323 | 323 | return _c | |
| 324 | 324 | } | |
| 325 | 325 | ||
| 326 | - | func (_c *Repos_ListPage_Call) Return(repoPage app.RepoPage, err error) *Repos_ListPage_Call { | |
| 326 | + | func (_c *RepoService_ListPage_Call) Return(repoPage ports.RepoPage, err error) *RepoService_ListPage_Call { | |
| 327 | 327 | _c.Call.Return(repoPage, err) | |
| 328 | 328 | return _c | |
| 329 | 329 | } | |
| 330 | 330 | ||
| 331 | - | func (_c *Repos_ListPage_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, size int, token string) (app.RepoPage, error)) *Repos_ListPage_Call { | |
| 331 | + | func (_c *RepoService_ListPage_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, size int, token string) (ports.RepoPage, error)) *RepoService_ListPage_Call { | |
| 332 | 332 | _c.Call.Return(run) | |
| 333 | 333 | return _c | |
| 334 | 334 | } | |
| 335 | 335 | ||
| 336 | - | // Update provides a mock function for the type Repos | |
| 337 | - | func (_mock *Repos) Update(ctx context.Context, p domain.Principal, name domain.RepoName, params app.UpdateParams) (domain.Repo, error) { | |
| 336 | + | // Update provides a mock function for the type RepoService | |
| 337 | + | func (_mock *RepoService) Update(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.UpdateRepoParams) (domain.Repo, error) { | |
| 338 | 338 | ret := _mock.Called(ctx, p, name, params) | |
| 339 | 339 | ||
| 340 | 340 | if len(ret) == 0 { | |
| @@ -343,15 +343,15 @@ func (_mock *Repos) Update(ctx context.Context, p domain.Principal, name domain. | |||
| 343 | 343 | ||
| 344 | 344 | var r0 domain.Repo | |
| 345 | 345 | var r1 error | |
| 346 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.UpdateParams) (domain.Repo, error)); ok { | |
| 346 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.UpdateRepoParams) (domain.Repo, error)); ok { | |
| 347 | 347 | return returnFunc(ctx, p, name, params) | |
| 348 | 348 | } | |
| 349 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, app.UpdateParams) domain.Repo); ok { | |
| 349 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, domain.RepoName, ports.UpdateRepoParams) domain.Repo); ok { | |
| 350 | 350 | r0 = returnFunc(ctx, p, name, params) | |
| 351 | 351 | } else { | |
| 352 | 352 | r0 = ret.Get(0).(domain.Repo) | |
| 353 | 353 | } | |
| 354 | - | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, app.UpdateParams) error); ok { | |
| 354 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, ports.UpdateRepoParams) error); ok { | |
| 355 | 355 | r1 = returnFunc(ctx, p, name, params) | |
| 356 | 356 | } else { | |
| 357 | 357 | r1 = ret.Error(1) | |
| @@ -359,8 +359,8 @@ func (_mock *Repos) Update(ctx context.Context, p domain.Principal, name domain. | |||
| 359 | 359 | return r0, r1 | |
| 360 | 360 | } | |
| 361 | 361 | ||
| 362 | - | // Repos_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' | |
| 363 | - | type Repos_Update_Call struct { | |
| 362 | + | // RepoService_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' | |
| 363 | + | type RepoService_Update_Call struct { | |
| 364 | 364 | *mock.Call | |
| 365 | 365 | } | |
| 366 | 366 | ||
| @@ -368,12 +368,12 @@ type Repos_Update_Call struct { | |||
| 368 | 368 | // - ctx context.Context | |
| 369 | 369 | // - p domain.Principal | |
| 370 | 370 | // - name domain.RepoName | |
| 371 | - | // - params app.UpdateParams | |
| 372 | - | func (_e *Repos_Expecter) Update(ctx any, p any, name any, params any) *Repos_Update_Call { | |
| 373 | - | return &Repos_Update_Call{Call: _e.mock.On("Update", ctx, p, name, params)} | |
| 371 | + | // - params ports.UpdateRepoParams | |
| 372 | + | func (_e *RepoService_Expecter) Update(ctx any, p any, name any, params any) *RepoService_Update_Call { | |
| 373 | + | return &RepoService_Update_Call{Call: _e.mock.On("Update", ctx, p, name, params)} | |
| 374 | 374 | } | |
| 375 | 375 | ||
| 376 | - | func (_c *Repos_Update_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params app.UpdateParams)) *Repos_Update_Call { | |
| 376 | + | func (_c *RepoService_Update_Call) Run(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.UpdateRepoParams)) *RepoService_Update_Call { | |
| 377 | 377 | _c.Call.Run(func(args mock.Arguments) { | |
| 378 | 378 | var arg0 context.Context | |
| 379 | 379 | if args[0] != nil { | |
| @@ -387,9 +387,9 @@ func (_c *Repos_Update_Call) Run(run func(ctx context.Context, p domain.Principa | |||
| 387 | 387 | if args[2] != nil { | |
| 388 | 388 | arg2 = args[2].(domain.RepoName) | |
| 389 | 389 | } | |
| 390 | - | var arg3 app.UpdateParams | |
| 390 | + | var arg3 ports.UpdateRepoParams | |
| 391 | 391 | if args[3] != nil { | |
| 392 | - | arg3 = args[3].(app.UpdateParams) | |
| 392 | + | arg3 = args[3].(ports.UpdateRepoParams) | |
| 393 | 393 | } | |
| 394 | 394 | run( | |
| 395 | 395 | arg0, | |
| @@ -401,33 +401,33 @@ func (_c *Repos_Update_Call) Run(run func(ctx context.Context, p domain.Principa | |||
| 401 | 401 | return _c | |
| 402 | 402 | } | |
| 403 | 403 | ||
| 404 | - | func (_c *Repos_Update_Call) Return(repo domain.Repo, err error) *Repos_Update_Call { | |
| 404 | + | func (_c *RepoService_Update_Call) Return(repo domain.Repo, err error) *RepoService_Update_Call { | |
| 405 | 405 | _c.Call.Return(repo, err) | |
| 406 | 406 | return _c | |
| 407 | 407 | } | |
| 408 | 408 | ||
| 409 | - | func (_c *Repos_Update_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params app.UpdateParams) (domain.Repo, error)) *Repos_Update_Call { | |
| 409 | + | func (_c *RepoService_Update_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.UpdateRepoParams) (domain.Repo, error)) *RepoService_Update_Call { | |
| 410 | 410 | _c.Call.Return(run) | |
| 411 | 411 | return _c | |
| 412 | 412 | } | |
| 413 | 413 | ||
| 414 | - | // View provides a mock function for the type Repos | |
| 415 | - | func (_mock *Repos) View(ctx context.Context, repo domain.Repo) (app.RepoView, error) { | |
| 414 | + | // View provides a mock function for the type RepoService | |
| 415 | + | func (_mock *RepoService) View(ctx context.Context, repo domain.Repo) (ports.RepoView, error) { | |
| 416 | 416 | ret := _mock.Called(ctx, repo) | |
| 417 | 417 | ||
| 418 | 418 | if len(ret) == 0 { | |
| 419 | 419 | panic("no return value specified for View") | |
| 420 | 420 | } | |
| 421 | 421 | ||
| 422 | - | var r0 app.RepoView | |
| 422 | + | var r0 ports.RepoView | |
| 423 | 423 | var r1 error | |
| 424 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Repo) (app.RepoView, error)); ok { | |
| 424 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Repo) (ports.RepoView, error)); ok { | |
| 425 | 425 | return returnFunc(ctx, repo) | |
| 426 | 426 | } | |
| 427 | - | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Repo) app.RepoView); ok { | |
| 427 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Repo) ports.RepoView); ok { | |
| 428 | 428 | r0 = returnFunc(ctx, repo) | |
| 429 | 429 | } else { | |
| 430 | - | r0 = ret.Get(0).(app.RepoView) | |
| 430 | + | r0 = ret.Get(0).(ports.RepoView) | |
| 431 | 431 | } | |
| 432 | 432 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Repo) error); ok { | |
| 433 | 433 | r1 = returnFunc(ctx, repo) | |
| @@ -437,19 +437,19 @@ func (_mock *Repos) View(ctx context.Context, repo domain.Repo) (app.RepoView, e | |||
| 437 | 437 | return r0, r1 | |
| 438 | 438 | } | |
| 439 | 439 | ||
| 440 | - | // Repos_View_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'View' | |
| 441 | - | type Repos_View_Call struct { | |
| 440 | + | // RepoService_View_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'View' | |
| 441 | + | type RepoService_View_Call struct { | |
| 442 | 442 | *mock.Call | |
| 443 | 443 | } | |
| 444 | 444 | ||
| 445 | 445 | // View is a helper method to define mock.On call | |
| 446 | 446 | // - ctx context.Context | |
| 447 | 447 | // - repo domain.Repo | |
| 448 | - | func (_e *Repos_Expecter) View(ctx any, repo any) *Repos_View_Call { | |
| 449 | - | return &Repos_View_Call{Call: _e.mock.On("View", ctx, repo)} | |
| 448 | + | func (_e *RepoService_Expecter) View(ctx any, repo any) *RepoService_View_Call { | |
| 449 | + | return &RepoService_View_Call{Call: _e.mock.On("View", ctx, repo)} | |
| 450 | 450 | } | |
| 451 | 451 | ||
| 452 | - | func (_c *Repos_View_Call) Run(run func(ctx context.Context, repo domain.Repo)) *Repos_View_Call { | |
| 452 | + | func (_c *RepoService_View_Call) Run(run func(ctx context.Context, repo domain.Repo)) *RepoService_View_Call { | |
| 453 | 453 | _c.Call.Run(func(args mock.Arguments) { | |
| 454 | 454 | var arg0 context.Context | |
| 455 | 455 | if args[0] != nil { | |
| @@ -467,12 +467,12 @@ func (_c *Repos_View_Call) Run(run func(ctx context.Context, repo domain.Repo)) | |||
| 467 | 467 | return _c | |
| 468 | 468 | } | |
| 469 | 469 | ||
| 470 | - | func (_c *Repos_View_Call) Return(repoView app.RepoView, err error) *Repos_View_Call { | |
| 470 | + | func (_c *RepoService_View_Call) Return(repoView ports.RepoView, err error) *RepoService_View_Call { | |
| 471 | 471 | _c.Call.Return(repoView, err) | |
| 472 | 472 | return _c | |
| 473 | 473 | } | |
| 474 | 474 | ||
| 475 | - | func (_c *Repos_View_Call) RunAndReturn(run func(ctx context.Context, repo domain.Repo) (app.RepoView, error)) *Repos_View_Call { | |
| 475 | + | func (_c *RepoService_View_Call) RunAndReturn(run func(ctx context.Context, repo domain.Repo) (ports.RepoView, error)) *RepoService_View_Call { | |
| 476 | 476 | _c.Call.Return(run) | |
| 477 | 477 | return _c | |
| 478 | 478 | } | |
R internal/app/mocks/Revalidator.go → internal/ports/mocks/Revalidator.go +0 -0 renamed, 100% similar
renamed, 100% similar
A internal/ports/mocks/SessionService.go +172 -0
| @@ -0,0 +1,172 @@ | |||
| 1 | + | // Code generated by mockery; DO NOT EDIT. | |
| 2 | + | // github.com/vektra/mockery | |
| 3 | + | // template: testify | |
| 4 | + | ||
| 5 | + | package mocks | |
| 6 | + | ||
| 7 | + | import ( | |
| 8 | + | "context" | |
| 9 | + | ||
| 10 | + | "bnema.dev/ermite/internal/domain" | |
| 11 | + | "bnema.dev/ermite/internal/ports" | |
| 12 | + | mock "github.com/stretchr/testify/mock" | |
| 13 | + | ) | |
| 14 | + | ||
| 15 | + | // NewSessionService creates a new instance of SessionService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | + | // The first argument is typically a *testing.T value. | |
| 17 | + | func NewSessionService(t interface { | |
| 18 | + | mock.TestingT | |
| 19 | + | Cleanup(func()) | |
| 20 | + | }) *SessionService { | |
| 21 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | + | helper.Helper() | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | mock := &SessionService{} | |
| 26 | + | mock.Mock.Test(t) | |
| 27 | + | ||
| 28 | + | t.Cleanup(func() { | |
| 29 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 30 | + | helper.Helper() | |
| 31 | + | } | |
| 32 | + | mock.AssertExpectations(t) | |
| 33 | + | }) | |
| 34 | + | ||
| 35 | + | return mock | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | // SessionService is an autogenerated mock type for the SessionService type | |
| 39 | + | type SessionService struct { | |
| 40 | + | mock.Mock | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | type SessionService_Expecter struct { | |
| 44 | + | mock *mock.Mock | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | func (_m *SessionService) EXPECT() *SessionService_Expecter { | |
| 48 | + | return &SessionService_Expecter{mock: &_m.Mock} | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // CreateLoginLink provides a mock function for the type SessionService | |
| 52 | + | func (_mock *SessionService) CreateLoginLink(ctx context.Context, p domain.Principal) (ports.LoginLink, error) { | |
| 53 | + | ret := _mock.Called(ctx, p) | |
| 54 | + | ||
| 55 | + | if len(ret) == 0 { | |
| 56 | + | panic("no return value specified for CreateLoginLink") | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | var r0 ports.LoginLink | |
| 60 | + | var r1 error | |
| 61 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal) (ports.LoginLink, error)); ok { | |
| 62 | + | return returnFunc(ctx, p) | |
| 63 | + | } | |
| 64 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal) ports.LoginLink); ok { | |
| 65 | + | r0 = returnFunc(ctx, p) | |
| 66 | + | } else { | |
| 67 | + | r0 = ret.Get(0).(ports.LoginLink) | |
| 68 | + | } | |
| 69 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal) error); ok { | |
| 70 | + | r1 = returnFunc(ctx, p) | |
| 71 | + | } else { | |
| 72 | + | r1 = ret.Error(1) | |
| 73 | + | } | |
| 74 | + | return r0, r1 | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // SessionService_CreateLoginLink_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateLoginLink' | |
| 78 | + | type SessionService_CreateLoginLink_Call struct { | |
| 79 | + | *mock.Call | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // CreateLoginLink is a helper method to define mock.On call | |
| 83 | + | // - ctx context.Context | |
| 84 | + | // - p domain.Principal | |
| 85 | + | func (_e *SessionService_Expecter) CreateLoginLink(ctx any, p any) *SessionService_CreateLoginLink_Call { | |
| 86 | + | return &SessionService_CreateLoginLink_Call{Call: _e.mock.On("CreateLoginLink", ctx, p)} | |
| 87 | + | } | |
| 88 | + | ||
| 89 | + | func (_c *SessionService_CreateLoginLink_Call) Run(run func(ctx context.Context, p domain.Principal)) *SessionService_CreateLoginLink_Call { | |
| 90 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 91 | + | var arg0 context.Context | |
| 92 | + | if args[0] != nil { | |
| 93 | + | arg0 = args[0].(context.Context) | |
| 94 | + | } | |
| 95 | + | var arg1 domain.Principal | |
| 96 | + | if args[1] != nil { | |
| 97 | + | arg1 = args[1].(domain.Principal) | |
| 98 | + | } | |
| 99 | + | run( | |
| 100 | + | arg0, | |
| 101 | + | arg1, | |
| 102 | + | ) | |
| 103 | + | }) | |
| 104 | + | return _c | |
| 105 | + | } | |
| 106 | + | ||
| 107 | + | func (_c *SessionService_CreateLoginLink_Call) Return(loginLink ports.LoginLink, err error) *SessionService_CreateLoginLink_Call { | |
| 108 | + | _c.Call.Return(loginLink, err) | |
| 109 | + | return _c | |
| 110 | + | } | |
| 111 | + | ||
| 112 | + | func (_c *SessionService_CreateLoginLink_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal) (ports.LoginLink, error)) *SessionService_CreateLoginLink_Call { | |
| 113 | + | _c.Call.Return(run) | |
| 114 | + | return _c | |
| 115 | + | } | |
| 116 | + | ||
| 117 | + | // SignOutEverywhere provides a mock function for the type SessionService | |
| 118 | + | func (_mock *SessionService) SignOutEverywhere(ctx context.Context, p domain.Principal) error { | |
| 119 | + | ret := _mock.Called(ctx, p) | |
| 120 | + | ||
| 121 | + | if len(ret) == 0 { | |
| 122 | + | panic("no return value specified for SignOutEverywhere") | |
| 123 | + | } | |
| 124 | + | ||
| 125 | + | var r0 error | |
| 126 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal) error); ok { | |
| 127 | + | r0 = returnFunc(ctx, p) | |
| 128 | + | } else { | |
| 129 | + | r0 = ret.Error(0) | |
| 130 | + | } | |
| 131 | + | return r0 | |
| 132 | + | } | |
| 133 | + | ||
| 134 | + | // SessionService_SignOutEverywhere_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SignOutEverywhere' | |
| 135 | + | type SessionService_SignOutEverywhere_Call struct { | |
| 136 | + | *mock.Call | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // SignOutEverywhere is a helper method to define mock.On call | |
| 140 | + | // - ctx context.Context | |
| 141 | + | // - p domain.Principal | |
| 142 | + | func (_e *SessionService_Expecter) SignOutEverywhere(ctx any, p any) *SessionService_SignOutEverywhere_Call { | |
| 143 | + | return &SessionService_SignOutEverywhere_Call{Call: _e.mock.On("SignOutEverywhere", ctx, p)} | |
| 144 | + | } | |
| 145 | + | ||
| 146 | + | func (_c *SessionService_SignOutEverywhere_Call) Run(run func(ctx context.Context, p domain.Principal)) *SessionService_SignOutEverywhere_Call { | |
| 147 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 148 | + | var arg0 context.Context | |
| 149 | + | if args[0] != nil { | |
| 150 | + | arg0 = args[0].(context.Context) | |
| 151 | + | } | |
| 152 | + | var arg1 domain.Principal | |
| 153 | + | if args[1] != nil { | |
| 154 | + | arg1 = args[1].(domain.Principal) | |
| 155 | + | } | |
| 156 | + | run( | |
| 157 | + | arg0, | |
| 158 | + | arg1, | |
| 159 | + | ) | |
| 160 | + | }) | |
| 161 | + | return _c | |
| 162 | + | } | |
| 163 | + | ||
| 164 | + | func (_c *SessionService_SignOutEverywhere_Call) Return(err error) *SessionService_SignOutEverywhere_Call { | |
| 165 | + | _c.Call.Return(err) | |
| 166 | + | return _c | |
| 167 | + | } | |
| 168 | + | ||
| 169 | + | func (_c *SessionService_SignOutEverywhere_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal) error) *SessionService_SignOutEverywhere_Call { | |
| 170 | + | _c.Call.Return(run) | |
| 171 | + | return _c | |
| 172 | + | } | |
A internal/ports/mocks/SigningKeyService.go +90 -0
| @@ -0,0 +1,90 @@ | |||
| 1 | + | // Code generated by mockery; DO NOT EDIT. | |
| 2 | + | // github.com/vektra/mockery | |
| 3 | + | // template: testify | |
| 4 | + | ||
| 5 | + | package mocks | |
| 6 | + | ||
| 7 | + | import ( | |
| 8 | + | "bnema.dev/ermite/internal/domain" | |
| 9 | + | mock "github.com/stretchr/testify/mock" | |
| 10 | + | ) | |
| 11 | + | ||
| 12 | + | // NewSigningKeyService creates a new instance of SigningKeyService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 13 | + | // The first argument is typically a *testing.T value. | |
| 14 | + | func NewSigningKeyService(t interface { | |
| 15 | + | mock.TestingT | |
| 16 | + | Cleanup(func()) | |
| 17 | + | }) *SigningKeyService { | |
| 18 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 19 | + | helper.Helper() | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | mock := &SigningKeyService{} | |
| 23 | + | mock.Mock.Test(t) | |
| 24 | + | ||
| 25 | + | t.Cleanup(func() { | |
| 26 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 27 | + | helper.Helper() | |
| 28 | + | } | |
| 29 | + | mock.AssertExpectations(t) | |
| 30 | + | }) | |
| 31 | + | ||
| 32 | + | return mock | |
| 33 | + | } | |
| 34 | + | ||
| 35 | + | // SigningKeyService is an autogenerated mock type for the SigningKeyService type | |
| 36 | + | type SigningKeyService struct { | |
| 37 | + | mock.Mock | |
| 38 | + | } | |
| 39 | + | ||
| 40 | + | type SigningKeyService_Expecter struct { | |
| 41 | + | mock *mock.Mock | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | func (_m *SigningKeyService) EXPECT() *SigningKeyService_Expecter { | |
| 45 | + | return &SigningKeyService_Expecter{mock: &_m.Mock} | |
| 46 | + | } | |
| 47 | + | ||
| 48 | + | // Info provides a mock function for the type SigningKeyService | |
| 49 | + | func (_mock *SigningKeyService) Info() domain.SigningKeyInfo { | |
| 50 | + | ret := _mock.Called() | |
| 51 | + | ||
| 52 | + | if len(ret) == 0 { | |
| 53 | + | panic("no return value specified for Info") | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | var r0 domain.SigningKeyInfo | |
| 57 | + | if returnFunc, ok := ret.Get(0).(func() domain.SigningKeyInfo); ok { | |
| 58 | + | r0 = returnFunc() | |
| 59 | + | } else { | |
| 60 | + | r0 = ret.Get(0).(domain.SigningKeyInfo) | |
| 61 | + | } | |
| 62 | + | return r0 | |
| 63 | + | } | |
| 64 | + | ||
| 65 | + | // SigningKeyService_Info_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Info' | |
| 66 | + | type SigningKeyService_Info_Call struct { | |
| 67 | + | *mock.Call | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | // Info is a helper method to define mock.On call | |
| 71 | + | func (_e *SigningKeyService_Expecter) Info() *SigningKeyService_Info_Call { | |
| 72 | + | return &SigningKeyService_Info_Call{Call: _e.mock.On("Info")} | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | func (_c *SigningKeyService_Info_Call) Run(run func()) *SigningKeyService_Info_Call { | |
| 76 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 77 | + | run() | |
| 78 | + | }) | |
| 79 | + | return _c | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | func (_c *SigningKeyService_Info_Call) Return(signingKeyInfo domain.SigningKeyInfo) *SigningKeyService_Info_Call { | |
| 83 | + | _c.Call.Return(signingKeyInfo) | |
| 84 | + | return _c | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | func (_c *SigningKeyService_Info_Call) RunAndReturn(run func() domain.SigningKeyInfo) *SigningKeyService_Info_Call { | |
| 88 | + | _c.Call.Return(run) | |
| 89 | + | return _c | |
| 90 | + | } | |
A internal/ports/mocks/TokenService.go +262 -0
| @@ -0,0 +1,262 @@ | |||
| 1 | + | // Code generated by mockery; DO NOT EDIT. | |
| 2 | + | // github.com/vektra/mockery | |
| 3 | + | // template: testify | |
| 4 | + | ||
| 5 | + | package mocks | |
| 6 | + | ||
| 7 | + | import ( | |
| 8 | + | "context" | |
| 9 | + | ||
| 10 | + | "bnema.dev/ermite/internal/domain" | |
| 11 | + | "bnema.dev/ermite/internal/ports" | |
| 12 | + | mock "github.com/stretchr/testify/mock" | |
| 13 | + | ) | |
| 14 | + | ||
| 15 | + | // NewTokenService creates a new instance of TokenService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 16 | + | // The first argument is typically a *testing.T value. | |
| 17 | + | func NewTokenService(t interface { | |
| 18 | + | mock.TestingT | |
| 19 | + | Cleanup(func()) | |
| 20 | + | }) *TokenService { | |
| 21 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 22 | + | helper.Helper() | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | mock := &TokenService{} | |
| 26 | + | mock.Mock.Test(t) | |
| 27 | + | ||
| 28 | + | t.Cleanup(func() { | |
| 29 | + | if helper, ok := t.(interface{ Helper() }); ok { | |
| 30 | + | helper.Helper() | |
| 31 | + | } | |
| 32 | + | mock.AssertExpectations(t) | |
| 33 | + | }) | |
| 34 | + | ||
| 35 | + | return mock | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | // TokenService is an autogenerated mock type for the TokenService type | |
| 39 | + | type TokenService struct { | |
| 40 | + | mock.Mock | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | type TokenService_Expecter struct { | |
| 44 | + | mock *mock.Mock | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | func (_m *TokenService) EXPECT() *TokenService_Expecter { | |
| 48 | + | return &TokenService_Expecter{mock: &_m.Mock} | |
| 49 | + | } | |
| 50 | + | ||
| 51 | + | // Create provides a mock function for the type TokenService | |
| 52 | + | func (_mock *TokenService) Create(ctx context.Context, p domain.Principal, params ports.CreateTokenParams) (ports.CreatedToken, error) { | |
| 53 | + | ret := _mock.Called(ctx, p, params) | |
| 54 | + | ||
| 55 | + | if len(ret) == 0 { | |
| 56 | + | panic("no return value specified for Create") | |
| 57 | + | } | |
| 58 | + | ||
| 59 | + | var r0 ports.CreatedToken | |
| 60 | + | var r1 error | |
| 61 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, ports.CreateTokenParams) (ports.CreatedToken, error)); ok { | |
| 62 | + | return returnFunc(ctx, p, params) | |
| 63 | + | } | |
| 64 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, ports.CreateTokenParams) ports.CreatedToken); ok { | |
| 65 | + | r0 = returnFunc(ctx, p, params) | |
| 66 | + | } else { | |
| 67 | + | r0 = ret.Get(0).(ports.CreatedToken) | |
| 68 | + | } | |
| 69 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, ports.CreateTokenParams) error); ok { | |
| 70 | + | r1 = returnFunc(ctx, p, params) | |
| 71 | + | } else { | |
| 72 | + | r1 = ret.Error(1) | |
| 73 | + | } | |
| 74 | + | return r0, r1 | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | // TokenService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' | |
| 78 | + | type TokenService_Create_Call struct { | |
| 79 | + | *mock.Call | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | // Create is a helper method to define mock.On call | |
| 83 | + | // - ctx context.Context | |
| 84 | + | // - p domain.Principal | |
| 85 | + | // - params ports.CreateTokenParams | |
| 86 | + | func (_e *TokenService_Expecter) Create(ctx any, p any, params any) *TokenService_Create_Call { | |
| 87 | + | return &TokenService_Create_Call{Call: _e.mock.On("Create", ctx, p, params)} | |
| 88 | + | } | |
| 89 | + | ||
| 90 | + | func (_c *TokenService_Create_Call) Run(run func(ctx context.Context, p domain.Principal, params ports.CreateTokenParams)) *TokenService_Create_Call { | |
| 91 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 92 | + | var arg0 context.Context | |
| 93 | + | if args[0] != nil { | |
| 94 | + | arg0 = args[0].(context.Context) | |
| 95 | + | } | |
| 96 | + | var arg1 domain.Principal | |
| 97 | + | if args[1] != nil { | |
| 98 | + | arg1 = args[1].(domain.Principal) | |
| 99 | + | } | |
| 100 | + | var arg2 ports.CreateTokenParams | |
| 101 | + | if args[2] != nil { | |
| 102 | + | arg2 = args[2].(ports.CreateTokenParams) | |
| 103 | + | } | |
| 104 | + | run( | |
| 105 | + | arg0, | |
| 106 | + | arg1, | |
| 107 | + | arg2, | |
| 108 | + | ) | |
| 109 | + | }) | |
| 110 | + | return _c | |
| 111 | + | } | |
| 112 | + | ||
| 113 | + | func (_c *TokenService_Create_Call) Return(createdToken ports.CreatedToken, err error) *TokenService_Create_Call { | |
| 114 | + | _c.Call.Return(createdToken, err) | |
| 115 | + | return _c | |
| 116 | + | } | |
| 117 | + | ||
| 118 | + | func (_c *TokenService_Create_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, params ports.CreateTokenParams) (ports.CreatedToken, error)) *TokenService_Create_Call { | |
| 119 | + | _c.Call.Return(run) | |
| 120 | + | return _c | |
| 121 | + | } | |
| 122 | + | ||
| 123 | + | // ListPage provides a mock function for the type TokenService | |
| 124 | + | func (_mock *TokenService) ListPage(ctx context.Context, p domain.Principal, size int, token string) (ports.TokenPage, error) { | |
| 125 | + | ret := _mock.Called(ctx, p, size, token) | |
| 126 | + | ||
| 127 | + | if len(ret) == 0 { | |
| 128 | + | panic("no return value specified for ListPage") | |
| 129 | + | } | |
| 130 | + | ||
| 131 | + | var r0 ports.TokenPage | |
| 132 | + | var r1 error | |
| 133 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) (ports.TokenPage, error)); ok { | |
| 134 | + | return returnFunc(ctx, p, size, token) | |
| 135 | + | } | |
| 136 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, int, string) ports.TokenPage); ok { | |
| 137 | + | r0 = returnFunc(ctx, p, size, token) | |
| 138 | + | } else { | |
| 139 | + | r0 = ret.Get(0).(ports.TokenPage) | |
| 140 | + | } | |
| 141 | + | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, int, string) error); ok { | |
| 142 | + | r1 = returnFunc(ctx, p, size, token) | |
| 143 | + | } else { | |
| 144 | + | r1 = ret.Error(1) | |
| 145 | + | } | |
| 146 | + | return r0, r1 | |
| 147 | + | } | |
| 148 | + | ||
| 149 | + | // TokenService_ListPage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListPage' | |
| 150 | + | type TokenService_ListPage_Call struct { | |
| 151 | + | *mock.Call | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | // ListPage is a helper method to define mock.On call | |
| 155 | + | // - ctx context.Context | |
| 156 | + | // - p domain.Principal | |
| 157 | + | // - size int | |
| 158 | + | // - token string | |
| 159 | + | func (_e *TokenService_Expecter) ListPage(ctx any, p any, size any, token any) *TokenService_ListPage_Call { | |
| 160 | + | return &TokenService_ListPage_Call{Call: _e.mock.On("ListPage", ctx, p, size, token)} | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | func (_c *TokenService_ListPage_Call) Run(run func(ctx context.Context, p domain.Principal, size int, token string)) *TokenService_ListPage_Call { | |
| 164 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 165 | + | var arg0 context.Context | |
| 166 | + | if args[0] != nil { | |
| 167 | + | arg0 = args[0].(context.Context) | |
| 168 | + | } | |
| 169 | + | var arg1 domain.Principal | |
| 170 | + | if args[1] != nil { | |
| 171 | + | arg1 = args[1].(domain.Principal) | |
| 172 | + | } | |
| 173 | + | var arg2 int | |
| 174 | + | if args[2] != nil { | |
| 175 | + | arg2 = args[2].(int) | |
| 176 | + | } | |
| 177 | + | var arg3 string | |
| 178 | + | if args[3] != nil { | |
| 179 | + | arg3 = args[3].(string) | |
| 180 | + | } | |
| 181 | + | run( | |
| 182 | + | arg0, | |
| 183 | + | arg1, | |
| 184 | + | arg2, | |
| 185 | + | arg3, | |
| 186 | + | ) | |
| 187 | + | }) | |
| 188 | + | return _c | |
| 189 | + | } | |
| 190 | + | ||
| 191 | + | func (_c *TokenService_ListPage_Call) Return(tokenPage ports.TokenPage, err error) *TokenService_ListPage_Call { | |
| 192 | + | _c.Call.Return(tokenPage, err) | |
| 193 | + | return _c | |
| 194 | + | } | |
| 195 | + | ||
| 196 | + | func (_c *TokenService_ListPage_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, size int, token string) (ports.TokenPage, error)) *TokenService_ListPage_Call { | |
| 197 | + | _c.Call.Return(run) | |
| 198 | + | return _c | |
| 199 | + | } | |
| 200 | + | ||
| 201 | + | // Revoke provides a mock function for the type TokenService | |
| 202 | + | func (_mock *TokenService) Revoke(ctx context.Context, p domain.Principal, id string) error { | |
| 203 | + | ret := _mock.Called(ctx, p, id) | |
| 204 | + | ||
| 205 | + | if len(ret) == 0 { | |
| 206 | + | panic("no return value specified for Revoke") | |
| 207 | + | } | |
| 208 | + | ||
| 209 | + | var r0 error | |
| 210 | + | if returnFunc, ok := ret.Get(0).(func(context.Context, domain.Principal, string) error); ok { | |
| 211 | + | r0 = returnFunc(ctx, p, id) | |
| 212 | + | } else { | |
| 213 | + | r0 = ret.Error(0) | |
| 214 | + | } | |
| 215 | + | return r0 | |
| 216 | + | } | |
| 217 | + | ||
| 218 | + | // TokenService_Revoke_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Revoke' | |
| 219 | + | type TokenService_Revoke_Call struct { | |
| 220 | + | *mock.Call | |
| 221 | + | } | |
| 222 | + | ||
| 223 | + | // Revoke is a helper method to define mock.On call | |
| 224 | + | // - ctx context.Context | |
| 225 | + | // - p domain.Principal | |
| 226 | + | // - id string | |
| 227 | + | func (_e *TokenService_Expecter) Revoke(ctx any, p any, id any) *TokenService_Revoke_Call { | |
| 228 | + | return &TokenService_Revoke_Call{Call: _e.mock.On("Revoke", ctx, p, id)} | |
| 229 | + | } | |
| 230 | + | ||
| 231 | + | func (_c *TokenService_Revoke_Call) Run(run func(ctx context.Context, p domain.Principal, id string)) *TokenService_Revoke_Call { | |
| 232 | + | _c.Call.Run(func(args mock.Arguments) { | |
| 233 | + | var arg0 context.Context | |
| 234 | + | if args[0] != nil { | |
| 235 | + | arg0 = args[0].(context.Context) | |
| 236 | + | } | |
| 237 | + | var arg1 domain.Principal | |
| 238 | + | if args[1] != nil { | |
| 239 | + | arg1 = args[1].(domain.Principal) | |
| 240 | + | } | |
| 241 | + | var arg2 string | |
| 242 | + | if args[2] != nil { | |
| 243 | + | arg2 = args[2].(string) | |
| 244 | + | } | |
| 245 | + | run( | |
| 246 | + | arg0, | |
| 247 | + | arg1, | |
| 248 | + | arg2, | |
| 249 | + | ) | |
| 250 | + | }) | |
| 251 | + | return _c | |
| 252 | + | } | |
| 253 | + | ||
| 254 | + | func (_c *TokenService_Revoke_Call) Return(err error) *TokenService_Revoke_Call { | |
| 255 | + | _c.Call.Return(err) | |
| 256 | + | return _c | |
| 257 | + | } | |
| 258 | + | ||
| 259 | + | func (_c *TokenService_Revoke_Call) RunAndReturn(run func(ctx context.Context, p domain.Principal, id string) error) *TokenService_Revoke_Call { | |
| 260 | + | _c.Call.Return(run) | |
| 261 | + | return _c | |
| 262 | + | } | |
R internal/adapters/web/mocks/SessionAuth.go → internal/ports/mocks/WebSessionService.go +36 -36 renamed, 52% similar
| @@ -11,17 +11,17 @@ import ( | |||
| 11 | 11 | mock "github.com/stretchr/testify/mock" | |
| 12 | 12 | ) | |
| 13 | 13 | ||
| 14 | - | // NewSessionAuth creates a new instance of SessionAuth. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 14 | + | // NewWebSessionService creates a new instance of WebSessionService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. | |
| 15 | 15 | // The first argument is typically a *testing.T value. | |
| 16 | - | func NewSessionAuth(t interface { | |
| 16 | + | func NewWebSessionService(t interface { | |
| 17 | 17 | mock.TestingT | |
| 18 | 18 | Cleanup(func()) | |
| 19 | - | }) *SessionAuth { | |
| 19 | + | }) *WebSessionService { | |
| 20 | 20 | if helper, ok := t.(interface{ Helper() }); ok { | |
| 21 | 21 | helper.Helper() | |
| 22 | 22 | } | |
| 23 | 23 | ||
| 24 | - | mock := &SessionAuth{} | |
| 24 | + | mock := &WebSessionService{} | |
| 25 | 25 | mock.Mock.Test(t) | |
| 26 | 26 | ||
| 27 | 27 | t.Cleanup(func() { | |
| @@ -34,21 +34,21 @@ func NewSessionAuth(t interface { | |||
| 34 | 34 | return mock | |
| 35 | 35 | } | |
| 36 | 36 | ||
| 37 | - | // SessionAuth is an autogenerated mock type for the SessionAuth type | |
| 38 | - | type SessionAuth struct { | |
| 37 | + | // WebSessionService is an autogenerated mock type for the WebSessionService type | |
| 38 | + | type WebSessionService struct { | |
| 39 | 39 | mock.Mock | |
| 40 | 40 | } | |
| 41 | 41 | ||
| 42 | - | type SessionAuth_Expecter struct { | |
| 42 | + | type WebSessionService_Expecter struct { | |
| 43 | 43 | mock *mock.Mock | |
| 44 | 44 | } | |
| 45 | 45 | ||
| 46 | - | func (_m *SessionAuth) EXPECT() *SessionAuth_Expecter { | |
| 47 | - | return &SessionAuth_Expecter{mock: &_m.Mock} | |
| 46 | + | func (_m *WebSessionService) EXPECT() *WebSessionService_Expecter { | |
| 47 | + | return &WebSessionService_Expecter{mock: &_m.Mock} | |
| 48 | 48 | } | |
| 49 | 49 | ||
| 50 | - | // Login provides a mock function for the type SessionAuth | |
| 51 | - | func (_mock *SessionAuth) Login(ctx context.Context, nonce string) (string, time.Duration, error) { | |
| 50 | + | // Login provides a mock function for the type WebSessionService | |
| 51 | + | func (_mock *WebSessionService) Login(ctx context.Context, nonce string) (string, time.Duration, error) { | |
| 52 | 52 | ret := _mock.Called(ctx, nonce) | |
| 53 | 53 | ||
| 54 | 54 | if len(ret) == 0 { | |
| @@ -79,19 +79,19 @@ func (_mock *SessionAuth) Login(ctx context.Context, nonce string) (string, time | |||
| 79 | 79 | return r0, r1, r2 | |
| 80 | 80 | } | |
| 81 | 81 | ||
| 82 | - | // SessionAuth_Login_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Login' | |
| 83 | - | type SessionAuth_Login_Call struct { | |
| 82 | + | // WebSessionService_Login_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Login' | |
| 83 | + | type WebSessionService_Login_Call struct { | |
| 84 | 84 | *mock.Call | |
| 85 | 85 | } | |
| 86 | 86 | ||
| 87 | 87 | // Login is a helper method to define mock.On call | |
| 88 | 88 | // - ctx context.Context | |
| 89 | 89 | // - nonce string | |
| 90 | - | func (_e *SessionAuth_Expecter) Login(ctx any, nonce any) *SessionAuth_Login_Call { | |
| 91 | - | return &SessionAuth_Login_Call{Call: _e.mock.On("Login", ctx, nonce)} | |
| 90 | + | func (_e *WebSessionService_Expecter) Login(ctx any, nonce any) *WebSessionService_Login_Call { | |
| 91 | + | return &WebSessionService_Login_Call{Call: _e.mock.On("Login", ctx, nonce)} | |
| 92 | 92 | } | |
| 93 | 93 | ||
| 94 | - | func (_c *SessionAuth_Login_Call) Run(run func(ctx context.Context, nonce string)) *SessionAuth_Login_Call { | |
| 94 | + | func (_c *WebSessionService_Login_Call) Run(run func(ctx context.Context, nonce string)) *WebSessionService_Login_Call { | |
| 95 | 95 | _c.Call.Run(func(args mock.Arguments) { | |
| 96 | 96 | var arg0 context.Context | |
| 97 | 97 | if args[0] != nil { | |
| @@ -109,18 +109,18 @@ func (_c *SessionAuth_Login_Call) Run(run func(ctx context.Context, nonce string | |||
| 109 | 109 | return _c | |
| 110 | 110 | } | |
| 111 | 111 | ||
| 112 | - | func (_c *SessionAuth_Login_Call) Return(token string, lifetime time.Duration, err error) *SessionAuth_Login_Call { | |
| 112 | + | func (_c *WebSessionService_Login_Call) Return(token string, lifetime time.Duration, err error) *WebSessionService_Login_Call { | |
| 113 | 113 | _c.Call.Return(token, lifetime, err) | |
| 114 | 114 | return _c | |
| 115 | 115 | } | |
| 116 | 116 | ||
| 117 | - | func (_c *SessionAuth_Login_Call) RunAndReturn(run func(ctx context.Context, nonce string) (string, time.Duration, error)) *SessionAuth_Login_Call { | |
| 117 | + | func (_c *WebSessionService_Login_Call) RunAndReturn(run func(ctx context.Context, nonce string) (string, time.Duration, error)) *WebSessionService_Login_Call { | |
| 118 | 118 | _c.Call.Return(run) | |
| 119 | 119 | return _c | |
| 120 | 120 | } | |
| 121 | 121 | ||
| 122 | - | // LoginLinkValid provides a mock function for the type SessionAuth | |
| 123 | - | func (_mock *SessionAuth) LoginLinkValid(nonce string) bool { | |
| 122 | + | // LoginLinkValid provides a mock function for the type WebSessionService | |
| 123 | + | func (_mock *WebSessionService) LoginLinkValid(nonce string) bool { | |
| 124 | 124 | ret := _mock.Called(nonce) | |
| 125 | 125 | ||
| 126 | 126 | if len(ret) == 0 { | |
| @@ -136,18 +136,18 @@ func (_mock *SessionAuth) LoginLinkValid(nonce string) bool { | |||
| 136 | 136 | return r0 | |
| 137 | 137 | } | |
| 138 | 138 | ||
| 139 | - | // SessionAuth_LoginLinkValid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoginLinkValid' | |
| 140 | - | type SessionAuth_LoginLinkValid_Call struct { | |
| 139 | + | // WebSessionService_LoginLinkValid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoginLinkValid' | |
| 140 | + | type WebSessionService_LoginLinkValid_Call struct { | |
| 141 | 141 | *mock.Call | |
| 142 | 142 | } | |
| 143 | 143 | ||
| 144 | 144 | // LoginLinkValid is a helper method to define mock.On call | |
| 145 | 145 | // - nonce string | |
| 146 | - | func (_e *SessionAuth_Expecter) LoginLinkValid(nonce any) *SessionAuth_LoginLinkValid_Call { | |
| 147 | - | return &SessionAuth_LoginLinkValid_Call{Call: _e.mock.On("LoginLinkValid", nonce)} | |
| 146 | + | func (_e *WebSessionService_Expecter) LoginLinkValid(nonce any) *WebSessionService_LoginLinkValid_Call { | |
| 147 | + | return &WebSessionService_LoginLinkValid_Call{Call: _e.mock.On("LoginLinkValid", nonce)} | |
| 148 | 148 | } | |
| 149 | 149 | ||
| 150 | - | func (_c *SessionAuth_LoginLinkValid_Call) Run(run func(nonce string)) *SessionAuth_LoginLinkValid_Call { | |
| 150 | + | func (_c *WebSessionService_LoginLinkValid_Call) Run(run func(nonce string)) *WebSessionService_LoginLinkValid_Call { | |
| 151 | 151 | _c.Call.Run(func(args mock.Arguments) { | |
| 152 | 152 | var arg0 string | |
| 153 | 153 | if args[0] != nil { | |
| @@ -160,18 +160,18 @@ func (_c *SessionAuth_LoginLinkValid_Call) Run(run func(nonce string)) *SessionA | |||
| 160 | 160 | return _c | |
| 161 | 161 | } | |
| 162 | 162 | ||
| 163 | - | func (_c *SessionAuth_LoginLinkValid_Call) Return(b bool) *SessionAuth_LoginLinkValid_Call { | |
| 163 | + | func (_c *WebSessionService_LoginLinkValid_Call) Return(b bool) *WebSessionService_LoginLinkValid_Call { | |
| 164 | 164 | _c.Call.Return(b) | |
| 165 | 165 | return _c | |
| 166 | 166 | } | |
| 167 | 167 | ||
| 168 | - | func (_c *SessionAuth_LoginLinkValid_Call) RunAndReturn(run func(nonce string) bool) *SessionAuth_LoginLinkValid_Call { | |
| 168 | + | func (_c *WebSessionService_LoginLinkValid_Call) RunAndReturn(run func(nonce string) bool) *WebSessionService_LoginLinkValid_Call { | |
| 169 | 169 | _c.Call.Return(run) | |
| 170 | 170 | return _c | |
| 171 | 171 | } | |
| 172 | 172 | ||
| 173 | - | // Verify provides a mock function for the type SessionAuth | |
| 174 | - | func (_mock *SessionAuth) Verify(ctx context.Context, token string) (context.Context, bool, error) { | |
| 173 | + | // Verify provides a mock function for the type WebSessionService | |
| 174 | + | func (_mock *WebSessionService) Verify(ctx context.Context, token string) (context.Context, bool, error) { | |
| 175 | 175 | ret := _mock.Called(ctx, token) | |
| 176 | 176 | ||
| 177 | 177 | if len(ret) == 0 { | |
| @@ -204,19 +204,19 @@ func (_mock *SessionAuth) Verify(ctx context.Context, token string) (context.Con | |||
| 204 | 204 | return r0, r1, r2 | |
| 205 | 205 | } | |
| 206 | 206 | ||
| 207 | - | // SessionAuth_Verify_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Verify' | |
| 208 | - | type SessionAuth_Verify_Call struct { | |
| 207 | + | // WebSessionService_Verify_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Verify' | |
| 208 | + | type WebSessionService_Verify_Call struct { | |
| 209 | 209 | *mock.Call | |
| 210 | 210 | } | |
| 211 | 211 | ||
| 212 | 212 | // Verify is a helper method to define mock.On call | |
| 213 | 213 | // - ctx context.Context | |
| 214 | 214 | // - token string | |
| 215 | - | func (_e *SessionAuth_Expecter) Verify(ctx any, token any) *SessionAuth_Verify_Call { | |
| 216 | - | return &SessionAuth_Verify_Call{Call: _e.mock.On("Verify", ctx, token)} | |
| 215 | + | func (_e *WebSessionService_Expecter) Verify(ctx any, token any) *WebSessionService_Verify_Call { | |
| 216 | + | return &WebSessionService_Verify_Call{Call: _e.mock.On("Verify", ctx, token)} | |
| 217 | 217 | } | |
| 218 | 218 | ||
| 219 | - | func (_c *SessionAuth_Verify_Call) Run(run func(ctx context.Context, token string)) *SessionAuth_Verify_Call { | |
| 219 | + | func (_c *WebSessionService_Verify_Call) Run(run func(ctx context.Context, token string)) *WebSessionService_Verify_Call { | |
| 220 | 220 | _c.Call.Run(func(args mock.Arguments) { | |
| 221 | 221 | var arg0 context.Context | |
| 222 | 222 | if args[0] != nil { | |
| @@ -234,12 +234,12 @@ func (_c *SessionAuth_Verify_Call) Run(run func(ctx context.Context, token strin | |||
| 234 | 234 | return _c | |
| 235 | 235 | } | |
| 236 | 236 | ||
| 237 | - | func (_c *SessionAuth_Verify_Call) Return(owner context.Context, ok bool, err error) *SessionAuth_Verify_Call { | |
| 237 | + | func (_c *WebSessionService_Verify_Call) Return(owner context.Context, ok bool, err error) *WebSessionService_Verify_Call { | |
| 238 | 238 | _c.Call.Return(owner, ok, err) | |
| 239 | 239 | return _c | |
| 240 | 240 | } | |
| 241 | 241 | ||
| 242 | - | func (_c *SessionAuth_Verify_Call) RunAndReturn(run func(ctx context.Context, token string) (context.Context, bool, error)) *SessionAuth_Verify_Call { | |
| 242 | + | func (_c *WebSessionService_Verify_Call) RunAndReturn(run func(ctx context.Context, token string) (context.Context, bool, error)) *WebSessionService_Verify_Call { | |
| 243 | 243 | _c.Call.Return(run) | |
| 244 | 244 | return _c | |
| 245 | 245 | } | |
M internal/ports/ports.go +9 -2
| @@ -1,7 +1,14 @@ | |||
| 1 | 1 | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | 2 | ||
| 3 | - | // Package ports declares the interfaces the use cases need from the outside | |
| 4 | - | // world. Adapters implement them; cmd wires them. | |
| 3 | + | // Package ports declares every interface that crosses a layer, and the | |
| 4 | + | // parameter and result types of the use case interfaces. | |
| 5 | + | // | |
| 6 | + | // Outbound ports (ports.go) are what the use cases need from the outside | |
| 7 | + | // world: adapters implement them. Inbound ports (services.go) are the use | |
| 8 | + | // cases as the adapters that serve requests see them: the types of package app | |
| 9 | + | // implement them. Adapters and app depend on this package and on domain, never | |
| 10 | + | // on each other; cmd wires the implementations. All the mocks are generated in | |
| 11 | + | // ports/mocks. | |
| 5 | 12 | package ports | |
| 6 | 13 | ||
| 7 | 14 | import ( | |
A internal/ports/services.go +162 -0
| @@ -0,0 +1,162 @@ | |||
| 1 | + | // SPDX-License-Identifier: AGPL-3.0-or-later | |
| 2 | + | ||
| 3 | + | package ports | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "context" | |
| 7 | + | "errors" | |
| 8 | + | "io" | |
| 9 | + | "time" | |
| 10 | + | ||
| 11 | + | "bnema.dev/ermite/internal/domain" | |
| 12 | + | ) | |
| 13 | + | ||
| 14 | + | // The interfaces below are the use cases as the inbound adapters (the API, | |
| 15 | + | // Git over HTTP, the web) and the entrypoint see them. The types of package | |
| 16 | + | // app implement them, each assertion being made in app; the mocks in | |
| 17 | + | // ports/mocks stand in for them in the tests of the adapters. | |
| 18 | + | ||
| 19 | + | // AuthService turns the secret of a request into a principal. It returns | |
| 20 | + | // domain.ErrUnauthenticated for a secret that is not valid. *app.Auth | |
| 21 | + | // implements it. | |
| 22 | + | type AuthService interface { | |
| 23 | + | Authenticate(ctx context.Context, secret string) (domain.Principal, error) | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | // Revalidator confirms that a principal obtained earlier is still | |
| 27 | + | // authorized. *app.Auth implements it. | |
| 28 | + | type Revalidator interface { | |
| 29 | + | Revalidate(ctx context.Context, p domain.Principal) error | |
| 30 | + | } | |
| 31 | + | ||
| 32 | + | // RepoLookup is the read side of a single repository. A repository the | |
| 33 | + | // principal may not read is domain.ErrNotFound. *app.Repos implements it, as | |
| 34 | + | // part of RepoService. | |
| 35 | + | type RepoLookup interface { | |
| 36 | + | Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) | |
| 37 | + | } | |
| 38 | + | ||
| 39 | + | // RepoService is the repository use cases the API serves. *app.Repos | |
| 40 | + | // implements it. | |
| 41 | + | type RepoService interface { | |
| 42 | + | RepoLookup | |
| 43 | + | ListPage(ctx context.Context, p domain.Principal, size int, token string) (RepoPage, error) | |
| 44 | + | View(ctx context.Context, repo domain.Repo) (RepoView, error) | |
| 45 | + | Create(ctx context.Context, p domain.Principal, params CreateRepoParams) (domain.Repo, error) | |
| 46 | + | Update(ctx context.Context, p domain.Principal, name domain.RepoName, params UpdateRepoParams) (domain.Repo, error) | |
| 47 | + | Delete(ctx context.Context, p domain.Principal, name domain.RepoName) error | |
| 48 | + | } | |
| 49 | + | ||
| 50 | + | // TokenService is the access token use cases the API serves. *app.Tokens | |
| 51 | + | // implements it. | |
| 52 | + | type TokenService interface { | |
| 53 | + | Create(ctx context.Context, p domain.Principal, params CreateTokenParams) (CreatedToken, error) | |
| 54 | + | ListPage(ctx context.Context, p domain.Principal, size int, token string) (TokenPage, error) | |
| 55 | + | Revoke(ctx context.Context, p domain.Principal, id string) error | |
| 56 | + | } | |
| 57 | + | ||
| 58 | + | // BrowseService is the read side of a repository's content. *app.Browse | |
| 59 | + | // implements it. | |
| 60 | + | type BrowseService interface { | |
| 61 | + | ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params ListRefsParams) (RefPage, error) | |
| 62 | + | ResolveRevision(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) | |
| 63 | + | GetTree(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath, includeLastCommit bool) (domain.Tree, error) | |
| 64 | + | OpenBlob(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision, path domain.TreePath) (domain.BlobInfo, io.ReadCloser, error) | |
| 65 | + | ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params ListCommitsParams) (HistoryPage, error) | |
| 66 | + | GetCommit(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error) | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | // EventService streams the events of the forge. *app.Events implements it. | |
| 70 | + | type EventService interface { | |
| 71 | + | Watch(ctx context.Context, p domain.Principal, params WatchParams, send func(WatchEvent) error) error | |
| 72 | + | } | |
| 73 | + | ||
| 74 | + | // MergeRequestService is the merge request use cases. *app.MergeRequests | |
| 75 | + | // implements it. | |
| 76 | + | type MergeRequestService interface { | |
| 77 | + | Create(ctx context.Context, p domain.Principal, name domain.RepoName, params CreateMergeRequestParams) (domain.MergeRequest, error) | |
| 78 | + | List(ctx context.Context, p domain.Principal, name domain.RepoName, params ListMergeRequestsParams) (MergeRequestPage, error) | |
| 79 | + | Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (MergeRequestDetail, error) | |
| 80 | + | AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params AddCommentParams) (domain.Comment, error) | |
| 81 | + | ResolveComment(ctx context.Context, p domain.Principal, name domain.RepoName, number, commentID int64, resolved bool) (domain.Comment, error) | |
| 82 | + | Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) | |
| 83 | + | MarkRead(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error) | |
| 84 | + | Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params MergeParams) (MergeResult, error) | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | // SigningKeyService tells which key signs the commits of the forge. | |
| 88 | + | // *app.SigningKey implements it. | |
| 89 | + | type SigningKeyService interface { | |
| 90 | + | Info() domain.SigningKeyInfo | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | // SessionService is the owner's web session use cases the API serves. | |
| 94 | + | // *app.Sessions implements it. | |
| 95 | + | type SessionService interface { | |
| 96 | + | CreateLoginLink(ctx context.Context, p domain.Principal) (LoginLink, error) | |
| 97 | + | SignOutEverywhere(ctx context.Context, p domain.Principal) error | |
| 98 | + | } | |
| 99 | + | ||
| 100 | + | // ErrLinkRejected is what WebSessionService.Login returns for a link that is | |
| 101 | + | // unknown, expired or already used. | |
| 102 | + | var ErrLinkRejected = errors.New("login link rejected") | |
| 103 | + | ||
| 104 | + | // WebSessionService is the session side of the use cases, as the web needs | |
| 105 | + | // it. The entrypoint implements it over *app.Sessions. | |
| 106 | + | type WebSessionService interface { | |
| 107 | + | // LoginLinkValid reports whether the link is pending, without using it. | |
| 108 | + | LoginLinkValid(nonce string) bool | |
| 109 | + | // Login uses the link and returns the session token and how long it | |
| 110 | + | // lasts, or ErrLinkRejected. | |
| 111 | + | Login(ctx context.Context, nonce string) (token string, lifetime time.Duration, err error) | |
| 112 | + | // Verify checks a session token. When it is valid it returns the context | |
| 113 | + | // to serve the request with, which carries the owner as the caller of the | |
| 114 | + | // API; when it is not, ok is false and err nil. An error means the check | |
| 115 | + | // could not be made (the request then runs as anonymous). | |
| 116 | + | Verify(ctx context.Context, token string) (owner context.Context, ok bool, err error) | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | // PushService opens a repository for a push: it is domain.ErrUnauthenticated | |
| 120 | + | // for an anonymous caller, domain.ErrNotFound for a repository the caller may | |
| 121 | + | // not write and cannot see (or that is missing and may not be created), | |
| 122 | + | // domain.ErrForbidden for one it can see but not write. With create, a | |
| 123 | + | // missing repository the principal may write is created. *app.Pushes | |
| 124 | + | // implements it. | |
| 125 | + | type PushService interface { | |
| 126 | + | Open(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | // PushHookService is what the hook socket asks of the use cases. | |
| 130 | + | // *app.Pushes implements it. | |
| 131 | + | type PushHookService interface { | |
| 132 | + | // Check decides a push before Git applies it; an error matching | |
| 133 | + | // domain.ErrRejected refuses it, any other error refuses it as a failure. | |
| 134 | + | Check(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error | |
| 135 | + | // Record handles an accepted push. | |
| 136 | + | Record(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error | |
| 137 | + | } | |
| 138 | + | ||
| 139 | + | // MaintenanceScheduler queues repository maintenance. *app.Maintainer | |
| 140 | + | // implements it. | |
| 141 | + | type MaintenanceScheduler interface { | |
| 142 | + | Schedule(ctx context.Context, name domain.RepoName) | |
| 143 | + | } | |
| 144 | + | ||
| 145 | + | // HookTokens hands out the per-request tokens the hooks of a push present | |
| 146 | + | // back to ermite, and the socket they present them on. The Git HTTP adapter | |
| 147 | + | // implements it. | |
| 148 | + | type HookTokens interface { | |
| 149 | + | // Register binds a new token to the repository and principal of a push. | |
| 150 | + | // release revokes it and must be called when the request ends. | |
| 151 | + | Register(ctx context.Context, repo domain.RepoName, p domain.Principal) (token string, release func()) | |
| 152 | + | // Socket is the path of the hook socket. | |
| 153 | + | Socket() string | |
| 154 | + | } | |
| 155 | + | ||
| 156 | + | // FailureLimiter counts the failed authentications per client. The adapters | |
| 157 | + | // that authenticate share one, so that a client has one budget of failures. | |
| 158 | + | // *clientlimit.Limiter implements it. | |
| 159 | + | type FailureLimiter interface { | |
| 160 | + | Blocked(ctx context.Context, addr string) (bool, time.Duration) | |
| 161 | + | Fail(ctx context.Context, addr string) | |
| 162 | + | } | |