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 | role: ignore | 40 | role: ignore | ||
| 41 | paths: | 41 | paths: | ||
| 42 | - internal/readertest/** | 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 | rules: | 46 | rules: | ||
| 44 | no-adapter-imports-in-core: error | 47 | no-adapter-imports-in-core: error | ||
| 45 | no-infra-imports-in-usecase: error | 48 | no-infra-imports-in-usecase: error | ||
| @@ -53,8 +56,7 @@ rules: | |||||
| 53 | mocking: | 56 | mocking: | ||
| 54 | generatedMockPaths: | 57 | generatedMockPaths: | ||
| 55 | - internal/ports/mocks/** | 58 | - internal/ports/mocks/** | ||
| 56 | - | - internal/app/mocks/** | 59 | + | - internal/adapters/web/mocks/** |
| 57 | - | - internal/adapters/*/mocks/** | |||
| 58 | generatedMockNamePatterns: | 60 | generatedMockNamePatterns: | ||
| 59 | - '{{Interface}}' | 61 | - '{{Interface}}' | ||
| 60 | allow: | 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 | 1 | + | # Mocks of the ports, generated in internal/ports/mocks, and of the generated |
| 2 | - | # the use cases. Regenerate with: go generate ./internal/ports | 2 | + | # Connect clients the web adapter calls. Regenerate with: |
| 3 | + | # go generate ./internal/ports | |||
| 3 | template: testify | 4 | template: testify | ||
| 4 | _anchors: | 5 | _anchors: | ||
| 5 | mocks: &mocks | 6 | mocks: &mocks | ||
| @@ -11,14 +12,6 @@ _anchors: | |||||
| 11 | packages: | 12 | packages: | ||
| 12 | bnema.dev/ermite/internal/ports: | 13 | bnema.dev/ermite/internal/ports: | ||
| 13 | config: *mocks | 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 | bnema.dev/ermite-api/gen/ermite/ermiteconnect: | 15 | bnema.dev/ermite-api/gen/ermite/ermiteconnect: | ||
| 23 | config: | 16 | config: | ||
| 24 | include-auto-generated: true | 17 | include-auto-generated: true | ||
M cmd/ermite/api_helpers_test.go +2 -2
| @@ -19,8 +19,8 @@ import ( | |||||
| 19 | 19 | ||||
| 20 | pb "bnema.dev/ermite-api/gen/ermite" | 20 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 21 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | 21 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | ||
| 22 | - | "bnema.dev/ermite/internal/app" | |||
| 23 | "bnema.dev/ermite/internal/domain" | 22 | "bnema.dev/ermite/internal/domain" | ||
| 23 | + | "bnema.dev/ermite/internal/ports" | |||
| 24 | ) | 24 | ) | ||
| 25 | 25 | ||||
| 26 | // clients are the generated Connect clients of one caller. | 26 | // clients are the generated Connect clients of one caller. | ||
| @@ -105,7 +105,7 @@ func codeName(err error) string { | |||||
| 105 | // commit per file to its main branch with git. | 105 | // commit per file to its main branch with git. | ||
| 106 | func (h *harness) seed(name string, vis domain.Visibility, files ...string) { | 106 | func (h *harness) seed(name string, vis domain.Visibility, files ...string) { | ||
| 107 | h.t.Helper() | 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 | require.NoError(h.t, err) | 109 | require.NoError(h.t, err) | ||
| 110 | if len(files) == 0 { | 110 | if len(files) == 0 { | ||
| 111 | return | 111 | return | ||
M cmd/ermite/api_test.go +3 -3
| @@ -24,9 +24,9 @@ import ( | |||||
| 24 | 24 | ||||
| 25 | pb "bnema.dev/ermite-api/gen/ermite" | 25 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 26 | "bnema.dev/ermite/internal/adapters/rpc" | 26 | "bnema.dev/ermite/internal/adapters/rpc" | ||
| 27 | - | "bnema.dev/ermite/internal/app" | |||
| 28 | "bnema.dev/ermite/internal/clientlimit" | 27 | "bnema.dev/ermite/internal/clientlimit" | ||
| 29 | "bnema.dev/ermite/internal/domain" | 28 | "bnema.dev/ermite/internal/domain" | ||
| 29 | + | "bnema.dev/ermite/internal/ports" | |||
| 30 | ) | 30 | ) | ||
| 31 | 31 | ||||
| 32 | // principals of the access tables. | 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 { | 655 | + | func createParams(h *harness, name string, vis domain.Visibility) ports.CreateRepoParams { |
| 656 | - | return app.CreateParams{Name: h.name(name), Visibility: vis} | 656 | + | return ports.CreateRepoParams{Name: h.name(name), Visibility: vis} |
| 657 | } | 657 | } | ||
| 658 | 658 | ||||
| 659 | // TestUpdateRepoDefaultBranch: HEAD moves with git symbolic-ref once the | 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 | "github.com/bnema/zerowrap" | 18 | "github.com/bnema/zerowrap" | ||
| 19 | "github.com/stretchr/testify/require" | 19 | "github.com/stretchr/testify/require" | ||
| 20 | 20 | ||||
| 21 | - | "bnema.dev/ermite/internal/app" | |||
| 22 | "bnema.dev/ermite/internal/config" | 21 | "bnema.dev/ermite/internal/config" | ||
| 23 | "bnema.dev/ermite/internal/domain" | 22 | "bnema.dev/ermite/internal/domain" | ||
| 23 | + | "bnema.dev/ermite/internal/ports" | |||
| 24 | ) | 24 | ) | ||
| 25 | 25 | ||||
| 26 | // harness is a forge wired like `ermite serve`, behind an httptest server, | 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 | // token creates a stored token through the use case, as root. | 186 | // token creates a stored token through the use case, as root. | ||
| 187 | func (h *harness) token(scopes []domain.Scope, repos ...string) string { | 187 | func (h *harness) token(scopes []domain.Scope, repos ...string) string { | ||
| 188 | h.t.Helper() | 188 | h.t.Helper() | ||
| 189 | - | p := app.CreateTokenParams{Label: "e2e", Scopes: scopes} | 189 | + | p := ports.CreateTokenParams{Label: "e2e", Scopes: scopes} |
| 190 | for _, r := range repos { | 190 | for _, r := range repos { | ||
| 191 | p.Repos = append(p.Repos, h.name(r)) | 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 | "github.com/stretchr/testify/assert" | 20 | "github.com/stretchr/testify/assert" | ||
| 21 | "github.com/stretchr/testify/require" | 21 | "github.com/stretchr/testify/require" | ||
| 22 | 22 | ||||
| 23 | - | "bnema.dev/ermite/internal/app" | |||
| 24 | "bnema.dev/ermite/internal/domain" | 23 | "bnema.dev/ermite/internal/domain" | ||
| 24 | + | "bnema.dev/ermite/internal/ports" | |||
| 25 | ) | 25 | ) | ||
| 26 | 26 | ||||
| 27 | func scopes(s ...domain.Scope) []domain.Scope { return s } | 27 | func scopes(s ...domain.Scope) []domain.Scope { return s } | ||
| @@ -29,7 +29,7 @@ func scopes(s ...domain.Scope) []domain.Scope { return s } | |||||
| 29 | // publicRepo creates a public repository with one commit pushed by root. | 29 | // publicRepo creates a public repository with one commit pushed by root. | ||
| 30 | func (h *harness) publicRepo(name string, files ...string) { | 30 | func (h *harness) publicRepo(name string, files ...string) { | ||
| 31 | h.t.Helper() | 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 | require.NoError(h.t, err) | 33 | require.NoError(h.t, err) | ||
| 34 | wt := h.workTree("main", files...) | 34 | wt := h.workTree("main", files...) | ||
| 35 | h.mustGit(wt, "push", "-q", h.urlAuth(adminToken, "/"+name+".git"), "main") | 35 | h.mustGit(wt, "push", "-q", h.urlAuth(adminToken, "/"+name+".git"), "main") | ||
| @@ -189,7 +189,7 @@ func TestAC2PushAuthorization(t *testing.T) { | |||||
| 189 | assert.Contains(t, out, "Authentication failed") | 189 | assert.Contains(t, out, "Authentication failed") | ||
| 190 | 190 | ||||
| 191 | // Revoked token. | 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 | require.NoError(t, err) | 193 | require.NoError(t, err) | ||
| 194 | next("before-revoke") | 194 | next("before-revoke") | ||
| 195 | out, err = h.git(wt, "push", "-q", h.urlAuth(created.Secret, "/proj.git"), "main") | 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 | h := newHarness(t, harnessOpts{}) | 570 | h := newHarness(t, harnessOpts{}) | ||
| 571 | ctx := context.Background() | 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 | Label: "limited admin", Scopes: scopes(domain.ScopeTokenAdmin, domain.ScopeRepoWrite), Repos: []domain.RepoName{h.name("a")}, | 574 | Label: "limited admin", Scopes: scopes(domain.ScopeTokenAdmin, domain.ScopeRepoWrite), Repos: []domain.RepoName{h.name("a")}, | ||
| 575 | }) | 575 | }) | ||
| 576 | require.NoError(t, err) | 576 | require.NoError(t, err) | ||
| 577 | p, err := h.forge.Auth.Authenticate(ctx, admin.Secret) | 577 | p, err := h.forge.Auth.Authenticate(ctx, admin.Secret) | ||
| 578 | require.NoError(t, err) | 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 | assert.ErrorIs(t, err, domain.ErrForbidden, "scope escalation") | 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 | assert.ErrorIs(t, err, domain.ErrForbidden, "repository list escalation") | 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 | assert.ErrorIs(t, err, domain.ErrForbidden, "another repository") | 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 | require.NoError(t, err) | 587 | require.NoError(t, err) | ||
| 588 | 588 | ||||
| 589 | // The child works on its repository, and revoking the index entry kills it at once. | 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 | "bnema.dev/ermite/internal/adapters/rpc" | 21 | "bnema.dev/ermite/internal/adapters/rpc" | ||
| 22 | "bnema.dev/ermite/internal/app" | 22 | "bnema.dev/ermite/internal/app" | ||
| 23 | "bnema.dev/ermite/internal/domain" | 23 | "bnema.dev/ermite/internal/domain" | ||
| 24 | + | "bnema.dev/ermite/internal/ports" | |||
| 24 | ) | 25 | ) | ||
| 25 | 26 | ||||
| 26 | // watchWait is how long a test waits for an event that must arrive. Only | 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 | assert.Equal(t, "pub", ev.GetPushed().GetRepo(), name) | 223 | assert.Equal(t, "pub", ev.GetPushed().GetRepo(), name) | ||
| 223 | } | 224 | } | ||
| 224 | // Nothing about priv came before the sentinel, for either of them. | 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 | require.NoError(t, err) | 227 | require.NoError(t, err) | ||
| 227 | for name, w := range map[string]*stream{"anonymous": anon, "scoped": scoped} { | 228 | for name, w := range map[string]*stream{"anonymous": anon, "scoped": scoped} { | ||
| 228 | assert.Equal(t, "sentinel", w.next(t, watchWait).GetRepoCreated().GetRepo().GetName(), name) | 229 | assert.Equal(t, "sentinel", w.next(t, watchWait).GetRepoCreated().GetRepo().GetName(), name) | ||
| @@ -340,7 +341,7 @@ func TestServeShutdownEndsWatchStreams(t *testing.T) { | |||||
| 340 | func TestWatchEndsWhenTheTokenIsRevoked(t *testing.T) { | 341 | func TestWatchEndsWhenTheTokenIsRevoked(t *testing.T) { | ||
| 341 | h := newHarness(t, harnessOpts{revalidateEvery: 20 * time.Millisecond}) | 342 | h := newHarness(t, harnessOpts{revalidateEvery: 20 * time.Millisecond}) | ||
| 342 | h.seed("priv", domain.VisibilityPrivate) | 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 | Label: "watcher", Scopes: scopes(domain.ScopeRepoRead), | 345 | Label: "watcher", Scopes: scopes(domain.ScopeRepoRead), | ||
| 345 | }) | 346 | }) | ||
| 346 | require.NoError(t, err) | 347 | require.NoError(t, err) | ||
| @@ -396,7 +397,7 @@ func TestWatchLimits(t *testing.T) { | |||||
| 396 | // order they were published. | 397 | // order they were published. | ||
| 397 | func (h *harness) sentinel(t *testing.T, s *stream, name string) { | 398 | func (h *harness) sentinel(t *testing.T, s *stream, name string) { | ||
| 398 | t.Helper() | 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 | require.NoError(t, err) | 401 | require.NoError(t, err) | ||
| 401 | ev := s.next(t, watchWait) | 402 | ev := s.next(t, watchWait) | ||
| 402 | assert.Equal(t, name, ev.GetRepoCreated().GetRepo().GetName(), "an event came before the sentinel: %v", ev) | 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 | "github.com/stretchr/testify/assert" | 10 | "github.com/stretchr/testify/assert" | ||
| 11 | "github.com/stretchr/testify/require" | 11 | "github.com/stretchr/testify/require" | ||
| 12 | 12 | ||||
| 13 | - | "bnema.dev/ermite/internal/app" | |||
| 14 | "bnema.dev/ermite/internal/config" | 13 | "bnema.dev/ermite/internal/config" | ||
| 15 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 16 | ) | 16 | ) | ||
| 17 | 17 | ||||
| 18 | // The suite runs with the reader of ERMITE_GIT_READER (ermite-git by default). | 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 | assert.Equal(t, want, h.forge.cfg.GitReader) | 28 | assert.Equal(t, want, h.forge.cfg.GitReader) | ||
| 29 | assert.Equal(t, want == config.GitReaderErmiteGit, h.forge.reader != nil, "the ermite-git adapter exists only for ermite-git") | 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 | Name: h.name("fresh"), Visibility: domain.VisibilityPublic, | 32 | Name: h.name("fresh"), Visibility: domain.VisibilityPublic, | ||
| 33 | }) | 33 | }) | ||
| 34 | require.NoError(t, err) | 34 | require.NoError(t, err) | ||
M cmd/ermite/web.go +8 -5
| @@ -21,6 +21,7 @@ import ( | |||||
| 21 | "bnema.dev/ermite/internal/clientlimit" | 21 | "bnema.dev/ermite/internal/clientlimit" | ||
| 22 | "bnema.dev/ermite/internal/config" | 22 | "bnema.dev/ermite/internal/config" | ||
| 23 | "bnema.dev/ermite/internal/domain" | 23 | "bnema.dev/ermite/internal/domain" | ||
| 24 | + | "bnema.dev/ermite/internal/ports" | |||
| 24 | ) | 25 | ) | ||
| 25 | 26 | ||||
| 26 | // newWeb builds the web pages on the API of this process: the generated | 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 | "requests and one budget of failed authentications; set it to the proxy networks") | 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 | + | // webSessions adapts the session use cases to ports.WebSessionService: a valid |
| 100 | - | // gives the context of the owner, whose principal the API calls of the page | 101 | + | // token gives the context of the owner, whose principal the API calls of the |
| 101 | - | // carry (rpc.API.InProcessClient). | 102 | + | // page carry (rpc.API.InProcessClient). |
| 102 | type webSessions struct{ *app.Sessions } | 103 | type webSessions struct{ *app.Sessions } | ||
| 103 | 104 | ||||
| 105 | + | var _ ports.WebSessionService = webSessions{} | |||
| 106 | + | ||||
| 104 | func (s webSessions) Login(ctx context.Context, nonce string) (string, time.Duration, error) { | 107 | func (s webSessions) Login(ctx context.Context, nonce string) (string, time.Duration, error) { | ||
| 105 | token, expiresAt, err := s.Sessions.Login(ctx, nonce) | 108 | token, expiresAt, err := s.Sessions.Login(ctx, nonce) | ||
| 106 | if errors.Is(err, domain.ErrUnauthenticated) { | 109 | if errors.Is(err, domain.ErrUnauthenticated) { | ||
| 107 | - | return "", 0, web.ErrLinkRejected | 110 | + | return "", 0, ports.ErrLinkRejected |
| 108 | } | 111 | } | ||
| 109 | if err != nil { | 112 | if err != nil { | ||
| 110 | return "", 0, err | 113 | return "", 0, err | ||
| @@ -118,7 +121,7 @@ func (s webSessions) Login(ctx context.Context, nonce string) (string, time.Dura | |||||
| 118 | lifetime = d.Round(time.Second) | 121 | lifetime = d.Round(time.Second) | ||
| 119 | } | 122 | } | ||
| 120 | if lifetime < time.Second { | 123 | if lifetime < time.Second { | ||
| 121 | - | return "", 0, web.ErrLinkRejected | 124 | + | return "", 0, ports.ErrLinkRejected |
| 122 | } | 125 | } | ||
| 123 | return token, lifetime, nil | 126 | return token, lifetime, nil | ||
| 124 | } | 127 | } | ||
M cmd/ermite/web_commits_test.go +2 -2
| @@ -14,8 +14,8 @@ import ( | |||||
| 14 | "github.com/stretchr/testify/assert" | 14 | "github.com/stretchr/testify/assert" | ||
| 15 | "github.com/stretchr/testify/require" | 15 | "github.com/stretchr/testify/require" | ||
| 16 | 16 | ||||
| 17 | - | "bnema.dev/ermite/internal/app" | |||
| 18 | "bnema.dev/ermite/internal/domain" | 17 | "bnema.dev/ermite/internal/domain" | ||
| 18 | + | "bnema.dev/ermite/internal/ports" | |||
| 19 | ) | 19 | ) | ||
| 20 | 20 | ||||
| 21 | // diffFixture is the repository of the commit pages: one commit for each | 21 | // diffFixture is the repository of the commit pages: one commit for each | ||
| @@ -27,7 +27,7 @@ type diffFixture struct { | |||||
| 27 | // createRepo creates a public repository for the pages. | 27 | // createRepo creates a public repository for the pages. | ||
| 28 | func (h *harness) createRepo(name string, vis domain.Visibility) { | 28 | func (h *harness) createRepo(name string, vis domain.Visibility) { | ||
| 29 | h.t.Helper() | 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 | require.NoError(h.t, err) | 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 | "bnema.dev/ermite/internal/app" | 18 | "bnema.dev/ermite/internal/app" | ||
| 19 | "bnema.dev/ermite/internal/domain" | 19 | "bnema.dev/ermite/internal/domain" | ||
| 20 | + | "bnema.dev/ermite/internal/ports" | |||
| 20 | ) | 21 | ) | ||
| 21 | 22 | ||||
| 22 | // sseEvent is one event read from /-/events. | 23 | // sseEvent is one event read from /-/events. | ||
| @@ -126,7 +127,7 @@ func TestWebEventsHome(t *testing.T) { | |||||
| 126 | assert.Contains(t, ev.data, `href="/pub"`) | 127 | assert.Contains(t, ev.data, `href="/pub"`) | ||
| 127 | 128 | ||||
| 128 | // A new repository is a row; so is a repository created by a push. | 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 | require.NoError(t, err) | 131 | require.NoError(t, err) | ||
| 131 | ev = s.next(t, watchWait) | 132 | ev = s.next(t, watchWait) | ||
| 132 | assert.Equal(t, "home-list", ev.name) | 133 | assert.Equal(t, "home-list", ev.name) | ||
| @@ -136,7 +137,7 @@ func TestWebEventsHome(t *testing.T) { | |||||
| 136 | 137 | ||||
| 137 | // A repository that turns private is removed from the anonymous list. | 138 | // A repository that turns private is removed from the anonymous list. | ||
| 138 | priv := domain.VisibilityPrivate | 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 | require.NoError(t, err) | 141 | require.NoError(t, err) | ||
| 141 | ev = s.next(t, watchWait) | 142 | ev = s.next(t, watchWait) | ||
| 142 | assert.Equal(t, "home-list", ev.name) | 143 | assert.Equal(t, "home-list", ev.name) | ||
| @@ -286,7 +287,7 @@ func TestWebEventsPrivate(t *testing.T) { | |||||
| 286 | wt := h.workTree("main", "a.txt") | 287 | wt := h.workTree("main", "a.txt") | ||
| 287 | h.mustGit(wt, "push", "-q", h.urlAuth(adminToken, "/priv.git"), "main") | 288 | h.mustGit(wt, "push", "-q", h.urlAuth(adminToken, "/priv.git"), "main") | ||
| 288 | desc := "secret change" | 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 | require.NoError(t, err) | 291 | require.NoError(t, err) | ||
| 291 | // Made public later, it does not reveal what happened while it was | 292 | // Made public later, it does not reveal what happened while it was | ||
| 292 | // private; the update that makes it public is shown. | 293 | // private; the update that makes it public is shown. | ||
| @@ -303,7 +304,7 @@ func TestWebEventsPrivate(t *testing.T) { | |||||
| 303 | // public repository and requires its row to be the next event. | 304 | // public repository and requires its row to be the next event. | ||
| 304 | func (h *harness) sentinelSSE(t *testing.T, s *sseStream, name string) { | 305 | func (h *harness) sentinelSSE(t *testing.T, s *sseStream, name string) { | ||
| 305 | t.Helper() | 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 | require.NoError(t, err) | 308 | require.NoError(t, err) | ||
| 308 | ev := s.next(t, watchWait) | 309 | ev := s.next(t, watchWait) | ||
| 309 | assert.Contains(t, ev.data, `id="repo-`+name+`"`, "an event came before the sentinel: %s", ev.data) | 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 | "github.com/stretchr/testify/assert" | 16 | "github.com/stretchr/testify/assert" | ||
| 17 | "github.com/stretchr/testify/require" | 17 | "github.com/stretchr/testify/require" | ||
| 18 | 18 | ||||
| 19 | - | "bnema.dev/ermite/internal/app" | |||
| 20 | "bnema.dev/ermite/internal/domain" | 19 | "bnema.dev/ermite/internal/domain" | ||
| 20 | + | "bnema.dev/ermite/internal/ports" | |||
| 21 | ) | 21 | ) | ||
| 22 | 22 | ||||
| 23 | // Trojan Source: a right-to-left override and an isolate around code. | 23 | // Trojan Source: a right-to-left override and an isolate around code. | ||
| @@ -37,7 +37,7 @@ func tinyPNG(t *testing.T) []byte { | |||||
| 37 | // tag with a slash. | 37 | // tag with a slash. | ||
| 38 | func (h *harness) webFilesRepo(name string) { | 38 | func (h *harness) webFilesRepo(name string) { | ||
| 39 | h.t.Helper() | 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 | Name: h.name(name), Description: "Files of every kind", Visibility: domain.VisibilityPublic, | 41 | Name: h.name(name), Description: "Files of every kind", Visibility: domain.VisibilityPublic, | ||
| 42 | }) | 42 | }) | ||
| 43 | require.NoError(h.t, err) | 43 | require.NoError(h.t, err) | ||
M cmd/ermite/web_mr_test.go +2 -2
| @@ -13,8 +13,8 @@ import ( | |||||
| 13 | "github.com/stretchr/testify/assert" | 13 | "github.com/stretchr/testify/assert" | ||
| 14 | "github.com/stretchr/testify/require" | 14 | "github.com/stretchr/testify/require" | ||
| 15 | 15 | ||||
| 16 | - | "bnema.dev/ermite/internal/app" | |||
| 17 | "bnema.dev/ermite/internal/domain" | 16 | "bnema.dev/ermite/internal/domain" | ||
| 17 | + | "bnema.dev/ermite/internal/ports" | |||
| 18 | ) | 18 | ) | ||
| 19 | 19 | ||||
| 20 | // mrRepo is a public repository "proj" with README.md on main and a branch | 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 | token := r.signIn(t) | 466 | token := r.signIn(t) | ||
| 467 | r.cli(t, adminToken, "mr", "create", "proj", "--source", "feat/search", "--title", "t").ok(t) | 467 | r.cli(t, adminToken, "mr", "create", "proj", "--source", "feat/search", "--title", "t").ok(t) | ||
| 468 | for i := 0; i < 1000; i++ { | 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 | require.NoError(t, err) | 470 | require.NoError(t, err) | ||
| 471 | } | 471 | } | ||
| 472 | full := b.form("/proj/merge-requests/1/comments", token, url.Values{"text": {"one more"}}) | 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 | "github.com/stretchr/testify/require" | 19 | "github.com/stretchr/testify/require" | ||
| 20 | 20 | ||||
| 21 | pb "bnema.dev/ermite-api/gen/ermite" | 21 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 22 | - | "bnema.dev/ermite/internal/app" | |||
| 23 | "bnema.dev/ermite/internal/domain" | 22 | "bnema.dev/ermite/internal/domain" | ||
| 23 | + | "bnema.dev/ermite/internal/ports" | |||
| 24 | ) | 24 | ) | ||
| 25 | 25 | ||||
| 26 | const ( | 26 | const ( | ||
| @@ -311,7 +311,7 @@ func TestWebRevokingAnOwnerTokenSignsEveryoneOut(t *testing.T) { | |||||
| 311 | 311 | ||||
| 312 | // The cap: a link made by a token that expires in an hour gives a cookie, | 312 | // The cap: a link made by a token that expires in an hour gives a cookie, | ||
| 313 | // and a session, of an hour. | 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 | Label: "soon", Scopes: domain.AllScopes(), ExpiresAt: time.Now().Add(time.Hour), | 315 | Label: "soon", Scopes: domain.AllScopes(), ExpiresAt: time.Now().Add(time.Hour), | ||
| 316 | }) | 316 | }) | ||
| 317 | require.NoError(t, err) | 317 | require.NoError(t, err) | ||
M cmd/ermite/web_test.go +3 -3
| @@ -16,8 +16,8 @@ import ( | |||||
| 16 | "github.com/stretchr/testify/assert" | 16 | "github.com/stretchr/testify/assert" | ||
| 17 | "github.com/stretchr/testify/require" | 17 | "github.com/stretchr/testify/require" | ||
| 18 | 18 | ||||
| 19 | - | "bnema.dev/ermite/internal/app" | |||
| 20 | "bnema.dev/ermite/internal/domain" | 19 | "bnema.dev/ermite/internal/domain" | ||
| 20 | + | "bnema.dev/ermite/internal/ports" | |||
| 21 | ) | 21 | ) | ||
| 22 | 22 | ||||
| 23 | var updateGolden = flag.Bool("update", false, "rewrite the golden files of the web tests") | 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 | // branches (one with a slash), two tags and a description. | 30 | // branches (one with a slash), two tags and a description. | ||
| 31 | func (h *harness) webRepo(name string) { | 31 | func (h *harness) webRepo(name string) { | ||
| 32 | h.t.Helper() | 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 | Name: h.name(name), Description: "A demo repository", Visibility: domain.VisibilityPublic, | 34 | Name: h.name(name), Description: "A demo repository", Visibility: domain.VisibilityPublic, | ||
| 35 | }) | 35 | }) | ||
| 36 | require.NoError(h.t, err) | 36 | require.NoError(h.t, err) | ||
| @@ -162,7 +162,7 @@ func TestWebPrivateRepoIsInvisible(t *testing.T) { | |||||
| 162 | // AC4, end to end: a README that attacks the page is neutralised. | 162 | // AC4, end to end: a README that attacks the page is neutralised. | ||
| 163 | func TestWebReadmeIsNeutralised(t *testing.T) { | 163 | func TestWebReadmeIsNeutralised(t *testing.T) { | ||
| 164 | h := newHarness(t, harnessOpts{}) | 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 | require.NoError(t, err) | 166 | require.NoError(t, err) | ||
| 167 | wt := h.t.TempDir() | 167 | wt := h.t.TempDir() | ||
| 168 | h.mustGit(wt, "init", "-q", "--initial-branch=main") | 168 | h.mustGit(wt, "init", "-q", "--initial-branch=main") | ||
M internal/adapters/githttp/handler.go +8 -44
| @@ -61,56 +61,18 @@ const ( | |||||
| 61 | serviceReceive = "git-receive-pack" | 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 | // Config configures a Handler. | 64 | // Config configures a Handler. | ||
| 103 | type Config struct { | 65 | type Config struct { | ||
| 104 | - | Auth Authenticator | 66 | + | Auth ports.AuthService |
| 105 | - | Repos Repos | 67 | + | Repos ports.RepoLookup |
| 106 | - | Pushes Pushes | 68 | + | Pushes ports.PushService |
| 107 | Backend ports.GitBackend | 69 | Backend ports.GitBackend | ||
| 108 | // Hooks provides hook tokens for pushes. It is required. | 70 | // Hooks provides hook tokens for pushes. It is required. | ||
| 109 | - | Hooks HookTokens | 71 | + | Hooks ports.HookTokens |
| 110 | // TrustedProxies are the networks allowed to set X-Forwarded-For. | 72 | // TrustedProxies are the networks allowed to set X-Forwarded-For. | ||
| 111 | TrustedProxies []netip.Prefix | 73 | TrustedProxies []netip.Prefix | ||
| 112 | // Limiter counts failed authentications; nil builds a default one. | 74 | // Limiter counts failed authentications; nil builds a default one. | ||
| 113 | - | Limiter FailureLimiter | 75 | + | Limiter ports.FailureLimiter |
| 114 | // MaxBodyBytes bounds the body of a push; 0 means DefaultMaxBodyBytes. | 76 | // MaxBodyBytes bounds the body of a push; 0 means DefaultMaxBodyBytes. | ||
| 115 | // The body of a fetch is bounded by 64 MiB at most. | 77 | // The body of a fetch is bounded by 64 MiB at most. | ||
| 116 | MaxBodyBytes int64 | 78 | MaxBodyBytes int64 | ||
| @@ -148,7 +110,7 @@ const ( | |||||
| 148 | // Handler serves the smart HTTP routes of Patterns. | 110 | // Handler serves the smart HTTP routes of Patterns. | ||
| 149 | type Handler struct { | 111 | type Handler struct { | ||
| 150 | cfg Config | 112 | cfg Config | ||
| 151 | - | limiter FailureLimiter | 113 | + | limiter ports.FailureLimiter |
| 152 | maxBody int64 | 114 | maxBody int64 | ||
| 153 | 115 | ||||
| 154 | upload, receive chan struct{} // slots of the backends, per service | 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 | // ServeHTTP implements http.Handler. | 184 | // ServeHTTP implements http.Handler. | ||
| 185 | + | //hexcheck:ignore suspicious-business-logic-in-adapter transport orchestration: the authorization decisions are the use cases' | |||
| 223 | func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | 186 | func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
| 224 | var rt route | 187 | var rt route | ||
| 225 | var name domain.RepoName | 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 | // serveBackend runs git http-backend for an authorized request. | 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 | func (h *Handler) serveBackend(w http.ResponseWriter, r *http.Request, rt route, name domain.RepoName, p domain.Principal, client string) { | 378 | func (h *Handler) serveBackend(w http.ResponseWriter, r *http.Request, rt route, name domain.RepoName, p domain.Principal, client string) { | ||
| 415 | ctx := r.Context() | 379 | ctx := r.Context() | ||
| 416 | logger := zerowrap.FromCtx(ctx) | 380 | logger := zerowrap.FromCtx(ctx) | ||
M internal/adapters/githttp/handler_test.go +10 -11
| @@ -21,7 +21,6 @@ import ( | |||||
| 21 | "github.com/stretchr/testify/require" | 21 | "github.com/stretchr/testify/require" | ||
| 22 | 22 | ||||
| 23 | "bnema.dev/ermite/internal/adapters/githttp" | 23 | "bnema.dev/ermite/internal/adapters/githttp" | ||
| 24 | - | ghmocks "bnema.dev/ermite/internal/adapters/githttp/mocks" | |||
| 25 | "bnema.dev/ermite/internal/clientlimit" | 24 | "bnema.dev/ermite/internal/clientlimit" | ||
| 26 | "bnema.dev/ermite/internal/domain" | 25 | "bnema.dev/ermite/internal/domain" | ||
| 27 | "bnema.dev/ermite/internal/ports" | 26 | "bnema.dev/ermite/internal/ports" | ||
| @@ -43,10 +42,10 @@ func cgiScript(t *testing.T) string { | |||||
| 43 | type rig struct { | 42 | type rig struct { | ||
| 44 | h *githttp.Handler | 43 | h *githttp.Handler | ||
| 45 | srv *httptest.Server | 44 | srv *httptest.Server | ||
| 46 | - | pushes *ghmocks.Pushes | 45 | + | pushes *mocks.PushService |
| 47 | backend *mocks.GitBackend | 46 | backend *mocks.GitBackend | ||
| 48 | - | hooks *ghmocks.HookTokens | 47 | + | hooks *mocks.HookTokens |
| 49 | - | auth *ghmocks.Authenticator | 48 | + | auth *mocks.AuthService |
| 50 | 49 | ||||
| 51 | pushFlags []bool | 50 | pushFlags []bool | ||
| 52 | backendErr error | 51 | backendErr error | ||
| @@ -93,7 +92,7 @@ func (r *rig) hookedRepo() domain.RepoName { | |||||
| 93 | 92 | ||||
| 94 | // stubUseCases answers like the use cases behind the handler: a root and a | 93 | // stubUseCases answers like the use cases behind the handler: a root and a | ||
| 95 | // reader token, a public repository "pub" and a private one "priv". | 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 | r.auth.EXPECT().Authenticate(mock.Anything, mock.Anything).RunAndReturn( | 96 | r.auth.EXPECT().Authenticate(mock.Anything, mock.Anything).RunAndReturn( | ||
| 98 | func(_ context.Context, secret string) (domain.Principal, error) { | 97 | func(_ context.Context, secret string) (domain.Principal, error) { | ||
| 99 | r.mu.Lock() | 98 | r.mu.Lock() | ||
| @@ -145,10 +144,10 @@ func (r *rig) stubUseCases(repos *ghmocks.Repos) { | |||||
| 145 | func newRig(t *testing.T, mut func(*githttp.Config)) *rig { | 144 | func newRig(t *testing.T, mut func(*githttp.Config)) *rig { | ||
| 146 | t.Helper() | 145 | t.Helper() | ||
| 147 | r := &rig{ | 146 | r := &rig{ | ||
| 148 | - | pushes: ghmocks.NewPushes(t), backend: mocks.NewGitBackend(t), | 147 | + | pushes: mocks.NewPushService(t), backend: mocks.NewGitBackend(t), |
| 149 | - | hooks: ghmocks.NewHookTokens(t), auth: ghmocks.NewAuthenticator(t), | 148 | + | hooks: mocks.NewHookTokens(t), auth: mocks.NewAuthService(t), |
| 150 | } | 149 | } | ||
| 151 | - | repos := ghmocks.NewRepos(t) | 150 | + | repos := mocks.NewRepoLookup(t) |
| 152 | r.stubUseCases(repos) | 151 | r.stubUseCases(repos) | ||
| 153 | cfg := githttp.Config{ | 152 | cfg := githttp.Config{ | ||
| 154 | Auth: r.auth, Repos: repos, Pushes: r.pushes, Backend: r.backend, Hooks: r.hooks, | 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 | path := "/pub.git/info/refs?service=git-upload-pack" | 510 | path := "/pub.git/info/refs?service=git-upload-pack" | ||
| 512 | t.Run("a blocked client is refused before authentication", func(t *testing.T) { | 511 | t.Run("a blocked client is refused before authentication", func(t *testing.T) { | ||
| 513 | t.Parallel() | 512 | t.Parallel() | ||
| 514 | - | limiter := ghmocks.NewFailureLimiter(t) | 513 | + | limiter := mocks.NewFailureLimiter(t) |
| 515 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(true, 3*time.Second).Once() | 514 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(true, 3*time.Second).Once() | ||
| 516 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | 515 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | ||
| 517 | code, _, hdr := r.do(t, "GET", path, "u", "root-secret", nil, nil) | 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 | t.Run("an invalid secret is recorded as a failure", func(t *testing.T) { | 521 | t.Run("an invalid secret is recorded as a failure", func(t *testing.T) { | ||
| 523 | t.Parallel() | 522 | t.Parallel() | ||
| 524 | - | limiter := ghmocks.NewFailureLimiter(t) | 523 | + | limiter := mocks.NewFailureLimiter(t) |
| 525 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(false, time.Duration(0)).Once() | 524 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(false, time.Duration(0)).Once() | ||
| 526 | limiter.EXPECT().Fail(mock.Anything, "127.0.0.1").Once() | 525 | limiter.EXPECT().Fail(mock.Anything, "127.0.0.1").Once() | ||
| 527 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | 526 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | ||
| @@ -530,7 +529,7 @@ func TestHandlerUsesTheFailureLimiter(t *testing.T) { | |||||
| 530 | }) | 529 | }) | ||
| 531 | t.Run("a valid secret is not a failure", func(t *testing.T) { | 530 | t.Run("a valid secret is not a failure", func(t *testing.T) { | ||
| 532 | t.Parallel() | 531 | t.Parallel() | ||
| 533 | - | limiter := ghmocks.NewFailureLimiter(t) | 532 | + | limiter := mocks.NewFailureLimiter(t) |
| 534 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(false, time.Duration(0)).Once() | 533 | limiter.EXPECT().Blocked(mock.Anything, "127.0.0.1").Return(false, time.Duration(0)).Once() | ||
| 535 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | 534 | r := newRig(t, func(c *githttp.Config) { c.Limiter = limiter }) | ||
| 536 | code, _, _ := r.do(t, "GET", path, "u", "root-secret", nil, nil) | 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 | "github.com/bnema/zerowrap" | 19 | "github.com/bnema/zerowrap" | ||
| 20 | 20 | ||||
| 21 | "bnema.dev/ermite/internal/domain" | 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 | // readTimeout bounds how long a connection may take to send its request line. | 25 | // readTimeout bounds how long a connection may take to send its request line. | ||
| 34 | const readTimeout = 30 * time.Second | 26 | const readTimeout = 30 * time.Second | ||
| 35 | 27 | ||||
| @@ -46,7 +38,7 @@ type hookEntry struct { | |||||
| 46 | // socket the hooks call back on. It implements HookTokens. | 38 | // socket the hooks call back on. It implements HookTokens. | ||
| 47 | type HookServer struct { | 39 | type HookServer struct { | ||
| 48 | path string | 40 | path string | ||
| 49 | - | hooks PushHooks | 41 | + | hooks ports.PushHookService |
| 50 | 42 | ||||
| 51 | mu sync.RWMutex | 43 | mu sync.RWMutex | ||
| 52 | tokens map[string]hookEntry | 44 | tokens map[string]hookEntry | ||
| @@ -57,10 +49,10 @@ type HookServer struct { | |||||
| 57 | wg sync.WaitGroup | 49 | wg sync.WaitGroup | ||
| 58 | } | 50 | } | ||
| 59 | 51 | ||||
| 60 | - | var _ HookTokens = (*HookServer)(nil) | 52 | + | var _ ports.HookTokens = (*HookServer)(nil) |
| 61 | 53 | ||||
| 62 | // NewHookServer builds a server for the socket at path. Call Serve to listen. | 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 | return &HookServer{path: path, hooks: hooks, tokens: make(map[string]hookEntry), conns: make(map[net.Conn]struct{})} | 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 | // handle serves one connection: one request line, one reply line. | 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 | func (s *HookServer) handle(ctx context.Context, conn net.Conn) { | 179 | func (s *HookServer) handle(ctx context.Context, conn net.Conn) { | ||
| 187 | log := zerowrap.FromCtx(ctx) | 180 | log := zerowrap.FromCtx(ctx) | ||
| 188 | _ = conn.SetReadDeadline(time.Now().Add(readTimeout)) | 181 | _ = conn.SetReadDeadline(time.Now().Add(readTimeout)) | ||
M internal/adapters/githttp/hooks_test.go +10 -9
| @@ -22,8 +22,9 @@ import ( | |||||
| 22 | "github.com/stretchr/testify/require" | 22 | "github.com/stretchr/testify/require" | ||
| 23 | 23 | ||||
| 24 | "bnema.dev/ermite/internal/adapters/githttp" | 24 | "bnema.dev/ermite/internal/adapters/githttp" | ||
| 25 | - | ghmocks "bnema.dev/ermite/internal/adapters/githttp/mocks" | |||
| 26 | "bnema.dev/ermite/internal/domain" | 25 | "bnema.dev/ermite/internal/domain" | ||
| 26 | + | "bnema.dev/ermite/internal/ports" | |||
| 27 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 27 | ) | 28 | ) | ||
| 28 | 29 | ||||
| 29 | const ( | 30 | const ( | ||
| @@ -39,7 +40,7 @@ func repoName(t *testing.T, s string) domain.RepoName { | |||||
| 39 | } | 40 | } | ||
| 40 | 41 | ||||
| 41 | // startHooks serves a hook socket in a short temporary directory. | 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 | t.Helper() | 44 | t.Helper() | ||
| 44 | dir, err := os.MkdirTemp("", "hk") | 45 | dir, err := os.MkdirTemp("", "hk") | ||
| 45 | require.NoError(t, err) | 46 | require.NoError(t, err) | ||
| @@ -80,7 +81,7 @@ func raw(t *testing.T, sock, line string) githttp.HookReply { | |||||
| 80 | 81 | ||||
| 81 | func TestHookSocketMode(t *testing.T) { | 82 | func TestHookSocketMode(t *testing.T) { | ||
| 82 | t.Parallel() | 83 | t.Parallel() | ||
| 83 | - | _, sock := startHooks(t, ghmocks.NewPushHooks(t)) | 84 | + | _, sock := startHooks(t, mocks.NewPushHookService(t)) |
| 84 | fi, err := os.Stat(sock) | 85 | fi, err := os.Stat(sock) | ||
| 85 | require.NoError(t, err) | 86 | require.NoError(t, err) | ||
| 86 | assert.Equal(t, os.FileMode(0o600), fi.Mode().Perm()) | 87 | assert.Equal(t, os.FileMode(0o600), fi.Mode().Perm()) | ||
| @@ -94,21 +95,21 @@ func TestHookServerReplacesStaleSocketFile(t *testing.T) { | |||||
| 94 | defer func() { _ = os.RemoveAll(dir) }() | 95 | defer func() { _ = os.RemoveAll(dir) }() | ||
| 95 | sock := filepath.Join(dir, "hook.sock") | 96 | sock := filepath.Join(dir, "hook.sock") | ||
| 96 | require.NoError(t, os.WriteFile(sock, []byte("stale"), 0o600)) | 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 | require.NoError(t, s.Listen(context.Background())) | 99 | require.NoError(t, s.Listen(context.Background())) | ||
| 99 | s.Close(context.Background()) | 100 | s.Close(context.Background()) | ||
| 100 | } | 101 | } | ||
| 101 | 102 | ||||
| 102 | func TestHookServerRejectsTooLongSocketPath(t *testing.T) { | 103 | func TestHookServerRejectsTooLongSocketPath(t *testing.T) { | ||
| 103 | t.Parallel() | 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 | err := s.Listen(context.Background()) | 106 | err := s.Listen(context.Background()) | ||
| 106 | require.Error(t, err) | 107 | require.Error(t, err) | ||
| 107 | assert.Contains(t, err.Error(), "too long") | 108 | assert.Contains(t, err.Error(), "too long") | ||
| 108 | } | 109 | } | ||
| 109 | 110 | ||||
| 110 | func TestHookProtocol(t *testing.T) { | 111 | func TestHookProtocol(t *testing.T) { | ||
| 111 | - | hooks := ghmocks.NewPushHooks(t) | 112 | + | hooks := mocks.NewPushHookService(t) |
| 112 | srv, sock := startHooks(t, hooks) | 113 | srv, sock := startHooks(t, hooks) | ||
| 113 | p := domain.TokenPrincipal(domain.Token{ID: "tok1", Scopes: []domain.Scope{domain.ScopeRepoWrite}}) | 114 | p := domain.TokenPrincipal(domain.Token{ID: "tok1", Scopes: []domain.Scope{domain.ScopeRepoWrite}}) | ||
| 114 | tokenA, releaseA := srv.Register(context.Background(), repoName(t, "alpha"), p) | 115 | tokenA, releaseA := srv.Register(context.Background(), repoName(t, "alpha"), p) | ||
| @@ -202,7 +203,7 @@ func TestHookProtocol(t *testing.T) { | |||||
| 202 | // push is already in the repository. | 203 | // push is already in the repository. | ||
| 203 | func TestHookRecordSurvivesShutdown(t *testing.T) { | 204 | func TestHookRecordSurvivesShutdown(t *testing.T) { | ||
| 204 | t.Parallel() | 205 | t.Parallel() | ||
| 205 | - | hooks := ghmocks.NewPushHooks(t) | 206 | + | hooks := mocks.NewPushHookService(t) |
| 206 | started, proceed := make(chan struct{}), make(chan struct{}) | 207 | started, proceed := make(chan struct{}), make(chan struct{}) | ||
| 207 | var cancelled, hasDeadline bool | 208 | var cancelled, hasDeadline bool | ||
| 208 | var ctxMu sync.Mutex | 209 | var ctxMu sync.Mutex | ||
| @@ -257,7 +258,7 @@ func TestHookRecordSurvivesShutdown(t *testing.T) { | |||||
| 257 | 258 | ||||
| 258 | func TestHookConcurrentTokens(t *testing.T) { | 259 | func TestHookConcurrentTokens(t *testing.T) { | ||
| 259 | t.Parallel() | 260 | t.Parallel() | ||
| 260 | - | hooks := ghmocks.NewPushHooks(t) | 261 | + | hooks := mocks.NewPushHookService(t) |
| 261 | srv, sock := startHooks(t, hooks) | 262 | srv, sock := startHooks(t, hooks) | ||
| 262 | var wg sync.WaitGroup | 263 | var wg sync.WaitGroup | ||
| 263 | // Each of the 16 tokens reaches the use case for its own repository, once. | 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 | func TestRunHook(t *testing.T) { | 282 | func TestRunHook(t *testing.T) { | ||
| 282 | ctx := context.Background() | 283 | ctx := context.Background() | ||
| 283 | - | hooks := ghmocks.NewPushHooks(t) | 284 | + | hooks := mocks.NewPushHookService(t) |
| 284 | srv, sock := startHooks(t, hooks) | 285 | srv, sock := startHooks(t, hooks) | ||
| 285 | tok, rel := srv.Register(context.Background(), repoName(t, "alpha"), domain.Root()) | 286 | tok, rel := srv.Register(context.Background(), repoName(t, "alpha"), domain.Root()) | ||
| 286 | defer rel() | 287 | defer rel() | ||
M internal/adapters/rpc/api.go +10 -15
| @@ -18,6 +18,7 @@ import ( | |||||
| 18 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | 18 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | ||
| 19 | "bnema.dev/ermite/internal/clientlimit" | 19 | "bnema.dev/ermite/internal/clientlimit" | ||
| 20 | "bnema.dev/ermite/internal/domain" | 20 | "bnema.dev/ermite/internal/domain" | ||
| 21 | + | "bnema.dev/ermite/internal/ports" | |||
| 21 | ) | 22 | ) | ||
| 22 | 23 | ||||
| 23 | // MaxRequestBytes bounds the size of a request message. Responses are not | 24 | // MaxRequestBytes bounds the size of a request message. Responses are not | ||
| @@ -28,22 +29,16 @@ const MaxRequestBytes = 1 << 20 | |||||
| 28 | // implements, as GetVersion lists them. | 29 | // implements, as GetVersion lists them. | ||
| 29 | var Features = []string{"repo.update", "events.resume", "merge_requests", "merge_requests.delete_branch", "signing_key", "session"} | 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 | // Config configures the API. | 32 | // Config configures the API. | ||
| 38 | type Config struct { | 33 | type Config struct { | ||
| 39 | - | Auth Authenticator | 34 | + | Auth ports.AuthService |
| 40 | - | Repos Repos | 35 | + | Repos ports.RepoService |
| 41 | - | Tokens Tokens | 36 | + | Tokens ports.TokenService |
| 42 | - | Browse Browse | 37 | + | Browse ports.BrowseService |
| 43 | - | Events Events | 38 | + | Events ports.EventService |
| 44 | // MergeRequests serves MergeRequestService, SigningKey GetSigningKey. | 39 | // MergeRequests serves MergeRequestService, SigningKey GetSigningKey. | ||
| 45 | - | MergeRequests MergeRequests | 40 | + | MergeRequests ports.MergeRequestService |
| 46 | - | SigningKey SigningKey | 41 | + | SigningKey ports.SigningKeyService |
| 47 | Version string | 42 | Version string | ||
| 48 | // TrustedProxies are the networks allowed to set X-Forwarded-For. | 43 | // TrustedProxies are the networks allowed to set X-Forwarded-For. | ||
| 49 | TrustedProxies []netip.Prefix | 44 | TrustedProxies []netip.Prefix | ||
| @@ -51,11 +46,11 @@ type Config struct { | |||||
| 51 | // it with the other adapters that authenticate, so that a client has one | 46 | // it with the other adapters that authenticate, so that a client has one | ||
| 52 | // budget of failures. Leave it unset rather than assigning a typed nil | 47 | // budget of failures. Leave it unset rather than assigning a typed nil | ||
| 53 | // pointer (a nil *T in the interface is not nil, and would be called). | 48 | // pointer (a nil *T in the interface is not nil, and would be called). | ||
| 54 | - | Limiter FailureLimiter | 49 | + | Limiter ports.FailureLimiter |
| 55 | // Sessions are the owner's web sessions; nil serves no SessionService. | 50 | // Sessions are the owner's web sessions; nil serves no SessionService. | ||
| 56 | // Leave it unset rather than assigning a typed nil pointer (a nil *T in | 51 | // Leave it unset rather than assigning a typed nil pointer (a nil *T in | ||
| 57 | // the interface is not nil, and the service would be served and called). | 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 | // API is the set of Connect handlers of the contract. | 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 | "google.golang.org/protobuf/types/known/timestamppb" | 9 | "google.golang.org/protobuf/types/known/timestamppb" | ||
| 10 | 10 | ||||
| 11 | pb "bnema.dev/ermite-api/gen/ermite" | 11 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 12 | - | "bnema.dev/ermite/internal/app" | |||
| 13 | "bnema.dev/ermite/internal/domain" | 12 | "bnema.dev/ermite/internal/domain" | ||
| 13 | + | "bnema.dev/ermite/internal/ports" | |||
| 14 | ) | 14 | ) | ||
| 15 | 15 | ||||
| 16 | // This file maps domain values to the messages of the contract and back. | 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 | return "", fmt.Errorf("%w: %v", domain.ErrInvalidVisibility, v) | 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 | settings := v.Settings | 59 | settings := v.Settings | ||
| 60 | if settings.IsZero() { | 60 | if settings.IsZero() { | ||
| 61 | settings = domain.DefaultRepoSettings() | 61 | settings = domain.DefaultRepoSettings() | ||
| @@ -361,7 +361,7 @@ func refUpdatesToPB(updates []domain.RefUpdate) []*pb.RefUpdate { | |||||
| 361 | 361 | ||||
| 362 | // watchEventToPB maps one item of a watch; nil when the event has no | 362 | // watchEventToPB maps one item of a watch; nil when the event has no | ||
| 363 | // representation in the contract. | 363 | // representation in the contract. | ||
| 364 | - | func watchEventToPB(we app.WatchEvent) *pb.Event { | 364 | + | func watchEventToPB(we ports.WatchEvent) *pb.Event { |
| 365 | if we.Gap { | 365 | if we.Gap { | ||
| 366 | return &pb.Event{Kind: &pb.Event_Gap{Gap: &pb.Gap{}}} | 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 | return out | 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 | if we.Repo != nil { | 401 | if we.Repo != nil { | ||
| 402 | return repoToPB(*we.Repo) | 402 | return repoToPB(*we.Repo) | ||
| 403 | } | 403 | } | ||
M internal/adapters/rpc/convert_test.go +5 -5
| @@ -15,8 +15,8 @@ import ( | |||||
| 15 | "google.golang.org/protobuf/types/known/fieldmaskpb" | 15 | "google.golang.org/protobuf/types/known/fieldmaskpb" | ||
| 16 | 16 | ||||
| 17 | pb "bnema.dev/ermite-api/gen/ermite" | 17 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 18 | - | "bnema.dev/ermite/internal/app" | |||
| 19 | "bnema.dev/ermite/internal/domain" | 18 | "bnema.dev/ermite/internal/domain" | ||
| 19 | + | "bnema.dev/ermite/internal/ports" | |||
| 20 | ) | 20 | ) | ||
| 21 | 21 | ||||
| 22 | // Every value of the domain maps to a real value of the contract, never to | 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 | func TestRepoToPBAlwaysHasSettings(t *testing.T) { | 212 | func TestRepoToPBAlwaysHasSettings(t *testing.T) { | ||
| 213 | t.Parallel() | 213 | t.Parallel() | ||
| 214 | // A repository value without settings (never stored with them) reads as the defaults. | 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 | assert.Equal(t, []pb.MergeMode{pb.MergeMode_MERGE_MODE_FAST_FORWARD, pb.MergeMode_MERGE_MODE_SQUASH}, r.GetSettings().GetAllowedMergeModes()) | 216 | assert.Equal(t, []pb.MergeMode{pb.MergeMode_MERGE_MODE_FAST_FORWARD, pb.MergeMode_MERGE_MODE_SQUASH}, r.GetSettings().GetAllowedMergeModes()) | ||
| 217 | assert.True(t, r.GetSettings().GetFailingChecksBlock()) | 217 | assert.True(t, r.GetSettings().GetFailingChecksBlock()) | ||
| 218 | 218 | ||||
| 219 | custom := domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}} | 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 | assert.Equal(t, []pb.MergeMode{pb.MergeMode_MERGE_MODE_SQUASH}, r.GetSettings().GetAllowedMergeModes()) | 221 | assert.Equal(t, []pb.MergeMode{pb.MergeMode_MERGE_MODE_SQUASH}, r.GetSettings().GetAllowedMergeModes()) | ||
| 222 | assert.False(t, r.GetSettings().GetFailingChecksBlock()) | 222 | assert.False(t, r.GetSettings().GetFailingChecksBlock()) | ||
| 223 | } | 223 | } | ||
| @@ -313,7 +313,7 @@ func TestWatchEventToPBMergeRequestEvents(t *testing.T) { | |||||
| 313 | } { | 313 | } { | ||
| 314 | t.Run(name, func(t *testing.T) { | 314 | t.Run(name, func(t *testing.T) { | ||
| 315 | t.Parallel() | 315 | t.Parallel() | ||
| 316 | - | got := watchEventToPB(app.WatchEvent{ID: "e1", Event: tc.ev}) | 316 | + | got := watchEventToPB(ports.WatchEvent{ID: "e1", Event: tc.ev}) |
| 317 | require.NotNil(t, got) | 317 | require.NotNil(t, got) | ||
| 318 | assert.Equal(t, "e1", got.GetId()) | 318 | assert.Equal(t, "e1", got.GetId()) | ||
| 319 | assert.Equal(t, at, got.GetTime().AsTime()) | 319 | assert.Equal(t, at, got.GetTime().AsTime()) | ||
| @@ -327,7 +327,7 @@ func TestWatchEventToPBMergeRequestEvents(t *testing.T) { | |||||
| 327 | } | 327 | } | ||
| 328 | 328 | ||||
| 329 | c := domain.Comment{ID: 9, Author: "root", Path: "a.txt", Line: 3, Side: domain.SideOld, CreatedAt: at} | 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 | added := got.GetCommentAdded() | 331 | added := got.GetCommentAdded() | ||
| 332 | require.NotNil(t, added) | 332 | require.NotNil(t, added) | ||
| 333 | assert.Equal(t, "proj", added.GetRepo()) | 333 | assert.Equal(t, "proj", added.GetRepo()) | ||
M internal/adapters/rpc/event.go +4 -4
| @@ -8,11 +8,11 @@ import ( | |||||
| 8 | "connectrpc.com/connect" | 8 | "connectrpc.com/connect" | ||
| 9 | 9 | ||||
| 10 | pb "bnema.dev/ermite-api/gen/ermite" | 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 | // eventService implements ermiteconnect.EventServiceHandler. | 14 | // eventService implements ermiteconnect.EventServiceHandler. | ||
| 15 | - | type eventService struct{ events Events } | 15 | + | type eventService struct{ events ports.EventService } |
| 16 | 16 | ||||
| 17 | // Watch streams events until the client goes away or the server stops. The | 17 | // Watch streams events until the client goes away or the server stops. The | ||
| 18 | // stream ends with success in both cases: the contract has no error for | 18 | // stream ends with success in both cases: the contract has no error for | ||
| @@ -20,7 +20,7 @@ type eventService struct{ events Events } | |||||
| 20 | // the caller is revoked or expires, and a caller that has too many streams | 20 | // the caller is revoked or expires, and a caller that has too many streams | ||
| 21 | // open gets resource_exhausted. | 21 | // open gets resource_exhausted. | ||
| 22 | func (s *eventService) Watch(ctx context.Context, req *connect.Request[pb.WatchRequest], stream *connect.ServerStream[pb.WatchResponse]) error { | 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 | Topics: req.Msg.GetTopics(), ResumeAfter: req.Msg.GetResumeAfter(), | 24 | Topics: req.Msg.GetTopics(), ResumeAfter: req.Msg.GetResumeAfter(), | ||
| 25 | Client: clientFromContext(ctx), | 25 | Client: clientFromContext(ctx), | ||
| 26 | // A client's call returns when the response begins: send the headers | 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 | // them for a nil message. A failure shows on the first real send. | 28 | // them for a nil message. A failure shows on the first real send. | ||
| 29 | Ready: func() { _ = stream.Send(nil) }, | 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 | ev := watchEventToPB(we) | 32 | ev := watchEventToPB(we) | ||
| 33 | if ev == nil { | 33 | if ev == nil { | ||
| 34 | return nil | 34 | return nil | ||
M internal/adapters/rpc/git.go +4 -4
| @@ -11,15 +11,15 @@ import ( | |||||
| 11 | "connectrpc.com/connect" | 11 | "connectrpc.com/connect" | ||
| 12 | 12 | ||||
| 13 | pb "bnema.dev/ermite-api/gen/ermite" | 13 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 14 | - | "bnema.dev/ermite/internal/app" | |||
| 15 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 16 | ) | 16 | ) | ||
| 17 | 17 | ||||
| 18 | // BlobChunkSize is the largest chunk of a GetBlob stream. | 18 | // BlobChunkSize is the largest chunk of a GetBlob stream. | ||
| 19 | const BlobChunkSize = 64 << 10 | 19 | const BlobChunkSize = 64 << 10 | ||
| 20 | 20 | ||||
| 21 | // gitService implements ermiteconnect.GitServiceHandler. | 21 | // gitService implements ermiteconnect.GitServiceHandler. | ||
| 22 | - | type gitService struct{ browse Browse } | 22 | + | type gitService struct{ browse ports.BrowseService } |
| 23 | 23 | ||||
| 24 | // target is the repository and revision most requests start with. | 24 | // target is the repository and revision most requests start with. | ||
| 25 | func target(repo, revision string) (domain.RepoName, domain.Revision, error) { | 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 | if err != nil { | 39 | if err != nil { | ||
| 40 | return nil, connectError(ctx, err) | 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 | for _, k := range req.Msg.GetKinds() { | 43 | for _, k := range req.Msg.GetKinds() { | ||
| 44 | kind, err := refKindFromPB(k) | 44 | kind, err := refKindFromPB(k) | ||
| 45 | if err != nil { | 45 | if err != nil { | ||
| @@ -144,7 +144,7 @@ func (s *gitService) ListCommits(ctx context.Context, req *connect.Request[pb.Li | |||||
| 144 | if err != nil { | 144 | if err != nil { | ||
| 145 | return nil, connectError(ctx, err) | 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 | Revision: rev, Path: path, PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken(), | 148 | Revision: rev, Path: path, PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken(), | ||
| 149 | }) | 149 | }) | ||
| 150 | if err != nil { | 150 | if err != nil { | ||
M internal/adapters/rpc/git_test.go +12 -12
| @@ -11,9 +11,9 @@ import ( | |||||
| 11 | "github.com/stretchr/testify/require" | 11 | "github.com/stretchr/testify/require" | ||
| 12 | 12 | ||||
| 13 | pb "bnema.dev/ermite-api/gen/ermite" | 13 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |||
| 15 | - | "bnema.dev/ermite/internal/app" | |||
| 16 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 16 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 17 | ) | 17 | ) | ||
| 18 | 18 | ||||
| 19 | func TestGitServiceGetTree(t *testing.T) { | 19 | func TestGitServiceGetTree(t *testing.T) { | ||
| @@ -34,7 +34,7 @@ func TestGitServiceGetTree(t *testing.T) { | |||||
| 34 | for _, tt := range tests { | 34 | for _, tt := range tests { | ||
| 35 | t.Run(tt.name, func(t *testing.T) { | 35 | t.Run(tt.name, func(t *testing.T) { | ||
| 36 | t.Parallel() | 36 | t.Parallel() | ||
| 37 | - | browse := mocks.NewBrowse(t) | 37 | + | browse := mocks.NewBrowseService(t) |
| 38 | if tt.wantCall { | 38 | if tt.wantCall { | ||
| 39 | browse.EXPECT().GetTree(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything, mock.Anything, false). | 39 | browse.EXPECT().GetTree(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything, mock.Anything, false). | ||
| 40 | Return(domain.Tree{}, tt.usecase).Once() | 40 | Return(domain.Tree{}, tt.usecase).Once() | ||
| @@ -68,10 +68,10 @@ func TestGitServiceListRefs(t *testing.T) { | |||||
| 68 | for _, tt := range tests { | 68 | for _, tt := range tests { | ||
| 69 | t.Run(tt.name, func(t *testing.T) { | 69 | t.Run(tt.name, func(t *testing.T) { | ||
| 70 | t.Parallel() | 70 | t.Parallel() | ||
| 71 | - | browse := mocks.NewBrowse(t) | 71 | + | browse := mocks.NewBrowseService(t) |
| 72 | if tt.wantCall { | 72 | if tt.wantCall { | ||
| 73 | browse.EXPECT().ListRefs(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything). | 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 | resp, err := (&gitService{browse}).ListRefs(ownerCtx(), connect.NewRequest(tt.req)) | 76 | resp, err := (&gitService{browse}).ListRefs(ownerCtx(), connect.NewRequest(tt.req)) | ||
| 77 | if tt.wantCode != 0 { | 77 | if tt.wantCode != 0 { | ||
| @@ -93,26 +93,26 @@ func TestGitServiceGetCommitAndResolveRevision(t *testing.T) { | |||||
| 93 | for _, tt := range invalid { | 93 | for _, tt := range invalid { | ||
| 94 | t.Run("GetCommit "+tt.name, func(t *testing.T) { | 94 | t.Run("GetCommit "+tt.name, func(t *testing.T) { | ||
| 95 | t.Parallel() | 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 | requireCode(t, connect.CodeInvalidArgument, err) | 97 | requireCode(t, connect.CodeInvalidArgument, err) | ||
| 98 | }) | 98 | }) | ||
| 99 | t.Run("ResolveRevision "+tt.name, func(t *testing.T) { | 99 | t.Run("ResolveRevision "+tt.name, func(t *testing.T) { | ||
| 100 | t.Parallel() | 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 | requireCode(t, connect.CodeInvalidArgument, err) | 102 | requireCode(t, connect.CodeInvalidArgument, err) | ||
| 103 | }) | 103 | }) | ||
| 104 | } | 104 | } | ||
| 105 | 105 | ||||
| 106 | t.Run("GetCommit not found", func(t *testing.T) { | 106 | t.Run("GetCommit not found", func(t *testing.T) { | ||
| 107 | t.Parallel() | 107 | t.Parallel() | ||
| 108 | - | browse := mocks.NewBrowse(t) | 108 | + | browse := mocks.NewBrowseService(t) |
| 109 | browse.EXPECT().GetCommit(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything).Return(domain.CommitDetail{}, domain.ErrNotFound).Once() | 109 | browse.EXPECT().GetCommit(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything).Return(domain.CommitDetail{}, domain.ErrNotFound).Once() | ||
| 110 | _, err := (&gitService{browse}).GetCommit(ownerCtx(), connect.NewRequest(&pb.GetCommitRequest{Repo: "demo", Revision: "main"})) | 110 | _, err := (&gitService{browse}).GetCommit(ownerCtx(), connect.NewRequest(&pb.GetCommitRequest{Repo: "demo", Revision: "main"})) | ||
| 111 | requireCode(t, connect.CodeNotFound, err) | 111 | requireCode(t, connect.CodeNotFound, err) | ||
| 112 | }) | 112 | }) | ||
| 113 | t.Run("ResolveRevision ok", func(t *testing.T) { | 113 | t.Run("ResolveRevision ok", func(t *testing.T) { | ||
| 114 | t.Parallel() | 114 | t.Parallel() | ||
| 115 | - | browse := mocks.NewBrowse(t) | 115 | + | browse := mocks.NewBrowseService(t) |
| 116 | browse.EXPECT().ResolveRevision(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything). | 116 | browse.EXPECT().ResolveRevision(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything). | ||
| 117 | Return(domain.ResolvedRevision{Ref: "refs/heads/main"}, nil).Once() | 117 | Return(domain.ResolvedRevision{Ref: "refs/heads/main"}, nil).Once() | ||
| 118 | resp, err := (&gitService{browse}).ResolveRevision(ownerCtx(), connect.NewRequest(&pb.ResolveRevisionRequest{Repo: "demo", Revision: "main"})) | 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 | for _, tt := range tests { | 138 | for _, tt := range tests { | ||
| 139 | t.Run(tt.name, func(t *testing.T) { | 139 | t.Run(tt.name, func(t *testing.T) { | ||
| 140 | t.Parallel() | 140 | t.Parallel() | ||
| 141 | - | browse := mocks.NewBrowse(t) | 141 | + | browse := mocks.NewBrowseService(t) |
| 142 | if tt.wantCall { | 142 | if tt.wantCall { | ||
| 143 | browse.EXPECT().ListCommits(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), mock.Anything). | 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 | _, err := (&gitService{browse}).ListCommits(ownerCtx(), connect.NewRequest(tt.req)) | 146 | _, err := (&gitService{browse}).ListCommits(ownerCtx(), connect.NewRequest(tt.req)) | ||
| 147 | if tt.wantCode != 0 { | 147 | if tt.wantCode != 0 { | ||
| @@ -167,7 +167,7 @@ func TestGitServiceGetBlobRejectsBadInput(t *testing.T) { | |||||
| 167 | for _, tt := range tests { | 167 | for _, tt := range tests { | ||
| 168 | t.Run(tt.name, func(t *testing.T) { | 168 | t.Run(tt.name, func(t *testing.T) { | ||
| 169 | t.Parallel() | 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 | requireCode(t, connect.CodeInvalidArgument, err) | 171 | requireCode(t, connect.CodeInvalidArgument, err) | ||
| 172 | }) | 172 | }) | ||
| 173 | } | 173 | } | ||
M internal/adapters/rpc/interceptor.go +3 -2
| @@ -18,6 +18,7 @@ import ( | |||||
| 18 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | 18 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | ||
| 19 | "bnema.dev/ermite/internal/clientlimit" | 19 | "bnema.dev/ermite/internal/clientlimit" | ||
| 20 | "bnema.dev/ermite/internal/domain" | 20 | "bnema.dev/ermite/internal/domain" | ||
| 21 | + | "bnema.dev/ermite/internal/ports" | |||
| 21 | ) | 22 | ) | ||
| 22 | 23 | ||||
| 23 | var errInternal = errors.New("internal error") | 24 | var errInternal = errors.New("internal error") | ||
| @@ -37,8 +38,8 @@ var errInternal = errors.New("internal error") | |||||
| 37 | // put there by a server's base context, is ignored and the request is | 38 | // put there by a server's base context, is ignored and the request is | ||
| 38 | // authenticated from its headers. | 39 | // authenticated from its headers. | ||
| 39 | type interceptor struct { | 40 | type interceptor struct { | ||
| 40 | - | auth Authenticator | 41 | + | auth ports.AuthService |
| 41 | - | limiter FailureLimiter | 42 | + | limiter ports.FailureLimiter |
| 42 | trusted []netip.Prefix | 43 | trusted []netip.Prefix | ||
| 43 | } | 44 | } | ||
| 44 | 45 | ||||
M internal/adapters/rpc/interceptor_test.go +3 -3
| @@ -15,8 +15,8 @@ import ( | |||||
| 15 | "github.com/stretchr/testify/require" | 15 | "github.com/stretchr/testify/require" | ||
| 16 | 16 | ||||
| 17 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | 17 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | ||
| 18 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |||
| 19 | "bnema.dev/ermite/internal/domain" | 18 | "bnema.dev/ermite/internal/domain" | ||
| 19 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 20 | ) | 20 | ) | ||
| 21 | 21 | ||||
| 22 | const peer = "203.0.113.7:4242" | 22 | const peer = "203.0.113.7:4242" | ||
| @@ -69,7 +69,7 @@ func TestInterceptorAuthenticate(t *testing.T) { | |||||
| 69 | for _, tt := range tests { | 69 | for _, tt := range tests { | ||
| 70 | t.Run(tt.name, func(t *testing.T) { | 70 | t.Run(tt.name, func(t *testing.T) { | ||
| 71 | t.Parallel() | 71 | t.Parallel() | ||
| 72 | - | auth := mocks.NewAuthenticator(t) | 72 | + | auth := mocks.NewAuthService(t) |
| 73 | limiter := mocks.NewFailureLimiter(t) | 73 | limiter := mocks.NewFailureLimiter(t) | ||
| 74 | if tt.wantLimit { | 74 | if tt.wantLimit { | ||
| 75 | wait := time.Duration(0) | 75 | wait := time.Duration(0) | ||
| @@ -117,7 +117,7 @@ func TestInterceptorIgnoresForwardedForFromUntrustedPeer(t *testing.T) { | |||||
| 117 | limiter.EXPECT().Blocked(mock.Anything, "203.0.113.7").Return(false, time.Duration(0)).Once() | 117 | limiter.EXPECT().Blocked(mock.Anything, "203.0.113.7").Return(false, time.Duration(0)).Once() | ||
| 118 | h := bearerHeader("") | 118 | h := bearerHeader("") | ||
| 119 | h.Set("X-Forwarded-For", "198.51.100.1") | 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 | _, err := i.authenticate(context.Background(), ermiteconnect.RepoServiceListReposProcedure, peer, h) | 121 | _, err := i.authenticate(context.Background(), ermiteconnect.RepoServiceListReposProcedure, peer, h) | ||
| 122 | require.NoError(t, err) | 122 | require.NoError(t, err) | ||
| 123 | } | 123 | } | ||
M internal/adapters/rpc/mergerequest.go +6 -6
| @@ -10,12 +10,12 @@ import ( | |||||
| 10 | "connectrpc.com/connect" | 10 | "connectrpc.com/connect" | ||
| 11 | 11 | ||||
| 12 | pb "bnema.dev/ermite-api/gen/ermite" | 12 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 13 | - | "bnema.dev/ermite/internal/app" | |||
| 14 | "bnema.dev/ermite/internal/domain" | 13 | "bnema.dev/ermite/internal/domain" | ||
| 14 | + | "bnema.dev/ermite/internal/ports" | |||
| 15 | ) | 15 | ) | ||
| 16 | 16 | ||||
| 17 | // mergeRequestService implements ermiteconnect.MergeRequestServiceHandler. | 17 | // mergeRequestService implements ermiteconnect.MergeRequestServiceHandler. | ||
| 18 | - | type mergeRequestService struct{ mrs MergeRequests } | 18 | + | type mergeRequestService struct{ mrs ports.MergeRequestService } |
| 19 | 19 | ||||
| 20 | func mergeRequestStateToPB(s domain.MRState) pb.MergeRequestState { | 20 | func mergeRequestStateToPB(s domain.MRState) pb.MergeRequestState { | ||
| 21 | switch s { | 21 | switch s { | ||
| @@ -129,7 +129,7 @@ func (s *mergeRequestService) CreateMergeRequest(ctx context.Context, req *conne | |||||
| 129 | if err != nil { | 129 | if err != nil { | ||
| 130 | return nil, connectError(ctx, err) | 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 | Title: req.Msg.GetTitle(), Description: req.Msg.GetDescription(), | 133 | Title: req.Msg.GetTitle(), Description: req.Msg.GetDescription(), | ||
| 134 | Source: req.Msg.GetSourceBranch(), Target: req.Msg.GetTargetBranch(), | 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 | if err != nil { | 148 | if err != nil { | ||
| 149 | return nil, connectError(ctx, err) | 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 | State: state, PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken(), | 152 | State: state, PageSize: int(req.Msg.GetPageSize()), PageToken: req.Msg.GetPageToken(), | ||
| 153 | }) | 153 | }) | ||
| 154 | if err != nil { | 154 | if err != nil { | ||
| @@ -197,7 +197,7 @@ func (s *mergeRequestService) AddComment(ctx context.Context, req *connect.Reque | |||||
| 197 | if err != nil { | 197 | if err != nil { | ||
| 198 | return nil, connectError(ctx, err) | 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 | Path: req.Msg.GetPath(), Line: int(req.Msg.GetLine()), Side: side, Text: req.Msg.GetText(), | 201 | Path: req.Msg.GetPath(), Line: int(req.Msg.GetLine()), Side: side, Text: req.Msg.GetText(), | ||
| 202 | }) | 202 | }) | ||
| 203 | if err != nil { | 203 | if err != nil { | ||
| @@ -245,7 +245,7 @@ func (s *mergeRequestService) MergeMergeRequest(ctx context.Context, req *connec | |||||
| 245 | if err != nil { | 245 | if err != nil { | ||
| 246 | return nil, connectError(ctx, err) | 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 | Mode: mode, HeadID: head, DeleteSource: req.Msg.GetDeleteSourceBranch(), | 249 | Mode: mode, HeadID: head, DeleteSource: req.Msg.GetDeleteSourceBranch(), | ||
| 250 | }) | 250 | }) | ||
| 251 | if err != nil { | 251 | if err != nil { | ||
M internal/adapters/rpc/mergerequest_test.go +19 -19
| @@ -11,9 +11,9 @@ import ( | |||||
| 11 | "github.com/stretchr/testify/require" | 11 | "github.com/stretchr/testify/require" | ||
| 12 | 12 | ||||
| 13 | pb "bnema.dev/ermite-api/gen/ermite" | 13 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |||
| 15 | - | "bnema.dev/ermite/internal/app" | |||
| 16 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 16 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 17 | ) | 17 | ) | ||
| 18 | 18 | ||||
| 19 | func TestMergeRequestServiceCreate(t *testing.T) { | 19 | func TestMergeRequestServiceCreate(t *testing.T) { | ||
| @@ -35,9 +35,9 @@ func TestMergeRequestServiceCreate(t *testing.T) { | |||||
| 35 | for _, tt := range tests { | 35 | for _, tt := range tests { | ||
| 36 | t.Run(tt.name, func(t *testing.T) { | 36 | t.Run(tt.name, func(t *testing.T) { | ||
| 37 | t.Parallel() | 37 | t.Parallel() | ||
| 38 | - | mrs := mocks.NewMergeRequests(t) | 38 | + | mrs := mocks.NewMergeRequestService(t) |
| 39 | if tt.wantCall { | 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 | Title: "t", Description: "d", Source: "feat", Target: "main", | 41 | Title: "t", Description: "d", Source: "feat", Target: "main", | ||
| 42 | }).Return(domain.MergeRequest{Number: 7, Source: "feat", Target: "main", State: domain.MRStateOpen}, tt.usecase).Once() | 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 | func TestMergeRequestServiceListRejectsUnknownState(t *testing.T) { | 58 | func TestMergeRequestServiceListRejectsUnknownState(t *testing.T) { | ||
| 59 | t.Parallel() | 59 | t.Parallel() | ||
| 60 | - | _, err := (&mergeRequestService{mocks.NewMergeRequests(t)}).ListMergeRequests(ownerCtx(), | 60 | + | _, err := (&mergeRequestService{mocks.NewMergeRequestService(t)}).ListMergeRequests(ownerCtx(), |
| 61 | connect.NewRequest(&pb.ListMergeRequestsRequest{Repo: "demo", State: pb.MergeRequestState(99)})) | 61 | connect.NewRequest(&pb.ListMergeRequestsRequest{Repo: "demo", State: pb.MergeRequestState(99)})) | ||
| 62 | requireCode(t, connect.CodeInvalidArgument, err) | 62 | requireCode(t, connect.CodeInvalidArgument, err) | ||
| 63 | } | 63 | } | ||
| 64 | 64 | ||||
| 65 | func TestMergeRequestServiceListFiltersByState(t *testing.T) { | 65 | func TestMergeRequestServiceListFiltersByState(t *testing.T) { | ||
| 66 | t.Parallel() | 66 | t.Parallel() | ||
| 67 | - | mrs := mocks.NewMergeRequests(t) | 67 | + | mrs := mocks.NewMergeRequestService(t) |
| 68 | - | mrs.EXPECT().List(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), app.ListMergeRequestsParams{ | 68 | + | mrs.EXPECT().List(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), ports.ListMergeRequestsParams{ |
| 69 | State: domain.MRStateMerged, PageSize: 3, PageToken: "tok", | 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 | resp, err := (&mergeRequestService{mrs}).ListMergeRequests(ownerCtx(), connect.NewRequest(&pb.ListMergeRequestsRequest{ | 71 | resp, err := (&mergeRequestService{mrs}).ListMergeRequests(ownerCtx(), connect.NewRequest(&pb.ListMergeRequestsRequest{ | ||
| 72 | Repo: "demo", State: pb.MergeRequestState_MERGE_REQUEST_STATE_MERGED, PageSize: 3, PageToken: "tok", | 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 | for _, tt := range tests { | 94 | for _, tt := range tests { | ||
| 95 | t.Run(tt.name, func(t *testing.T) { | 95 | t.Run(tt.name, func(t *testing.T) { | ||
| 96 | t.Parallel() | 96 | t.Parallel() | ||
| 97 | - | mrs := mocks.NewMergeRequests(t) | 97 | + | mrs := mocks.NewMergeRequestService(t) |
| 98 | if tt.wantCall { | 98 | if tt.wantCall { | ||
| 99 | mrs.EXPECT().AddComment(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(2), mock.Anything). | 99 | mrs.EXPECT().AddComment(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(2), mock.Anything). | ||
| 100 | Return(domain.Comment{ID: 5}, tt.usecase).Once() | 100 | Return(domain.Comment{ID: 5}, tt.usecase).Once() | ||
| @@ -117,7 +117,7 @@ func TestMergeRequestServiceResolveCommentMapsUnissuedIDsToZero(t *testing.T) { | |||||
| 117 | for _, id := range []string{"", "abc", "-1", "0", "007", "99999999999999999999"} { | 117 | for _, id := range []string{"", "abc", "-1", "0", "007", "99999999999999999999"} { | ||
| 118 | t.Run(id, func(t *testing.T) { | 118 | t.Run(id, func(t *testing.T) { | ||
| 119 | t.Parallel() | 119 | t.Parallel() | ||
| 120 | - | mrs := mocks.NewMergeRequests(t) | 120 | + | mrs := mocks.NewMergeRequestService(t) |
| 121 | mrs.EXPECT().ResolveComment(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), int64(0), true). | 121 | mrs.EXPECT().ResolveComment(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), int64(0), true). | ||
| 122 | Return(domain.Comment{}, domain.ErrNotFound).Once() | 122 | Return(domain.Comment{}, domain.ErrNotFound).Once() | ||
| 123 | _, err := (&mergeRequestService{mrs}).ResolveComment(ownerCtx(), connect.NewRequest(&pb.ResolveCommentRequest{ | 123 | _, err := (&mergeRequestService{mrs}).ResolveComment(ownerCtx(), connect.NewRequest(&pb.ResolveCommentRequest{ | ||
| @@ -148,11 +148,11 @@ func TestMergeRequestServiceMerge(t *testing.T) { | |||||
| 148 | for _, tt := range tests { | 148 | for _, tt := range tests { | ||
| 149 | t.Run(tt.name, func(t *testing.T) { | 149 | t.Run(tt.name, func(t *testing.T) { | ||
| 150 | t.Parallel() | 150 | t.Parallel() | ||
| 151 | - | mrs := mocks.NewMergeRequests(t) | 151 | + | mrs := mocks.NewMergeRequestService(t) |
| 152 | if tt.wantCall { | 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 | return p.DeleteSource == tt.req.GetDeleteSourceBranch() && (tt.req.GetHeadId() == "") == p.HeadID.IsZero() | 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 | resp, err := (&mergeRequestService{mrs}).MergeMergeRequest(ownerCtx(), connect.NewRequest(tt.req)) | 157 | resp, err := (&mergeRequestService{mrs}).MergeMergeRequest(ownerCtx(), connect.NewRequest(tt.req)) | ||
| 158 | if tt.wantCode != 0 { | 158 | if tt.wantCode != 0 { | ||
| @@ -169,14 +169,14 @@ func TestMergeRequestServiceCloseAndMarkRead(t *testing.T) { | |||||
| 169 | t.Parallel() | 169 | t.Parallel() | ||
| 170 | t.Run("close not found", func(t *testing.T) { | 170 | t.Run("close not found", func(t *testing.T) { | ||
| 171 | t.Parallel() | 171 | t.Parallel() | ||
| 172 | - | mrs := mocks.NewMergeRequests(t) | 172 | + | mrs := mocks.NewMergeRequestService(t) |
| 173 | mrs.EXPECT().Close(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(9)).Return(domain.MergeRequest{}, domain.ErrNotFound).Once() | 173 | mrs.EXPECT().Close(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(9)).Return(domain.MergeRequest{}, domain.ErrNotFound).Once() | ||
| 174 | _, err := (&mergeRequestService{mrs}).CloseMergeRequest(ownerCtx(), connect.NewRequest(&pb.CloseMergeRequestRequest{Repo: "demo", Number: 9})) | 174 | _, err := (&mergeRequestService{mrs}).CloseMergeRequest(ownerCtx(), connect.NewRequest(&pb.CloseMergeRequestRequest{Repo: "demo", Number: 9})) | ||
| 175 | requireCode(t, connect.CodeNotFound, err) | 175 | requireCode(t, connect.CodeNotFound, err) | ||
| 176 | }) | 176 | }) | ||
| 177 | t.Run("close ok", func(t *testing.T) { | 177 | t.Run("close ok", func(t *testing.T) { | ||
| 178 | t.Parallel() | 178 | t.Parallel() | ||
| 179 | - | mrs := mocks.NewMergeRequests(t) | 179 | + | mrs := mocks.NewMergeRequestService(t) |
| 180 | mrs.EXPECT().Close(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(9)).Return(domain.MergeRequest{Number: 9, State: domain.MRStateClosed}, nil).Once() | 180 | mrs.EXPECT().Close(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(9)).Return(domain.MergeRequest{Number: 9, State: domain.MRStateClosed}, nil).Once() | ||
| 181 | resp, err := (&mergeRequestService{mrs}).CloseMergeRequest(ownerCtx(), connect.NewRequest(&pb.CloseMergeRequestRequest{Repo: "demo", Number: 9})) | 181 | resp, err := (&mergeRequestService{mrs}).CloseMergeRequest(ownerCtx(), connect.NewRequest(&pb.CloseMergeRequestRequest{Repo: "demo", Number: 9})) | ||
| 182 | require.NoError(t, err) | 182 | require.NoError(t, err) | ||
| @@ -184,13 +184,13 @@ func TestMergeRequestServiceCloseAndMarkRead(t *testing.T) { | |||||
| 184 | }) | 184 | }) | ||
| 185 | t.Run("mark read rejects a short head", func(t *testing.T) { | 185 | t.Run("mark read rejects a short head", func(t *testing.T) { | ||
| 186 | t.Parallel() | 186 | t.Parallel() | ||
| 187 | - | _, err := (&mergeRequestService{mocks.NewMergeRequests(t)}).MarkRead(ownerCtx(), | 187 | + | _, err := (&mergeRequestService{mocks.NewMergeRequestService(t)}).MarkRead(ownerCtx(), |
| 188 | connect.NewRequest(&pb.MarkReadRequest{Repo: "demo", Number: 1, HeadId: "abc"})) | 188 | connect.NewRequest(&pb.MarkReadRequest{Repo: "demo", Number: 1, HeadId: "abc"})) | ||
| 189 | requireCode(t, connect.CodeInvalidArgument, err) | 189 | requireCode(t, connect.CodeInvalidArgument, err) | ||
| 190 | }) | 190 | }) | ||
| 191 | t.Run("mark read unauthenticated", func(t *testing.T) { | 191 | t.Run("mark read unauthenticated", func(t *testing.T) { | ||
| 192 | t.Parallel() | 192 | t.Parallel() | ||
| 193 | - | mrs := mocks.NewMergeRequests(t) | 193 | + | mrs := mocks.NewMergeRequestService(t) |
| 194 | mrs.EXPECT().MarkRead(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), domain.ObjectID{}).Return(domain.ObjectID{}, domain.ErrUnauthenticated).Once() | 194 | mrs.EXPECT().MarkRead(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(1), domain.ObjectID{}).Return(domain.ObjectID{}, domain.ErrUnauthenticated).Once() | ||
| 195 | _, err := (&mergeRequestService{mrs}).MarkRead(ownerCtx(), connect.NewRequest(&pb.MarkReadRequest{Repo: "demo", Number: 1})) | 195 | _, err := (&mergeRequestService{mrs}).MarkRead(ownerCtx(), connect.NewRequest(&pb.MarkReadRequest{Repo: "demo", Number: 1})) | ||
| 196 | requireCode(t, connect.CodeUnauthenticated, err) | 196 | requireCode(t, connect.CodeUnauthenticated, err) | ||
| @@ -211,9 +211,9 @@ func TestMergeRequestServiceGet(t *testing.T) { | |||||
| 211 | for _, tt := range tests { | 211 | for _, tt := range tests { | ||
| 212 | t.Run(tt.name, func(t *testing.T) { | 212 | t.Run(tt.name, func(t *testing.T) { | ||
| 213 | t.Parallel() | 213 | t.Parallel() | ||
| 214 | - | mrs := mocks.NewMergeRequests(t) | 214 | + | mrs := mocks.NewMergeRequestService(t) |
| 215 | mrs.EXPECT().Get(mock.Anything, domain.Owner(), mustRepoName(t, "demo"), int64(4), true). | 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 | resp, err := (&mergeRequestService{mrs}).GetMergeRequest(ownerCtx(), connect.NewRequest(&pb.GetMergeRequestRequest{Repo: "demo", Number: 4, SinceLastRead: true})) | 217 | resp, err := (&mergeRequestService{mrs}).GetMergeRequest(ownerCtx(), connect.NewRequest(&pb.GetMergeRequestRequest{Repo: "demo", Number: 4, SinceLastRead: true})) | ||
| 218 | if tt.wantCode != 0 { | 218 | if tt.wantCode != 0 { | ||
| 219 | requireCode(t, tt.wantCode, err) | 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 | "connectrpc.com/connect" | 9 | "connectrpc.com/connect" | ||
| 10 | 10 | ||||
| 11 | pb "bnema.dev/ermite-api/gen/ermite" | 11 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 12 | - | "bnema.dev/ermite/internal/app" | |||
| 13 | "bnema.dev/ermite/internal/domain" | 12 | "bnema.dev/ermite/internal/domain" | ||
| 13 | + | "bnema.dev/ermite/internal/ports" | |||
| 14 | ) | 14 | ) | ||
| 15 | 15 | ||||
| 16 | // repoService implements ermiteconnect.RepoServiceHandler. | 16 | // repoService implements ermiteconnect.RepoServiceHandler. | ||
| 17 | - | type repoService struct{ repos Repos } | 17 | + | type repoService struct{ repos ports.RepoService } |
| 18 | 18 | ||||
| 19 | func (s *repoService) ListRepos(ctx context.Context, req *connect.Request[pb.ListReposRequest]) (*connect.Response[pb.ListReposResponse], error) { | 19 | func (s *repoService) ListRepos(ctx context.Context, req *connect.Request[pb.ListReposRequest]) (*connect.Response[pb.ListReposResponse], error) { | ||
| 20 | page, err := s.repos.ListPage(ctx, caller(ctx), int(req.Msg.GetPageSize()), req.Msg.GetPageToken()) | 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 | if err != nil { | 53 | if err != nil { | ||
| 54 | return nil, connectError(ctx, err) | 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 | Name: name, Description: req.Msg.GetDescription(), Visibility: vis, | 57 | Name: name, Description: req.Msg.GetDescription(), Visibility: vis, | ||
| 58 | }) | 58 | }) | ||
| 59 | if err != nil { | 59 | if err != nil { | ||
| @@ -84,8 +84,8 @@ func (s *repoService) UpdateRepo(ctx context.Context, req *connect.Request[pb.Up | |||||
| 84 | // nothing else. | 84 | // nothing else. | ||
| 85 | // | 85 | // | ||
| 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 | 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) { | 87 | + | func updateParams(msg *pb.UpdateRepoRequest) (ports.UpdateRepoParams, error) { |
| 88 | - | var params app.UpdateParams | 88 | + | var params ports.UpdateRepoParams |
| 89 | paths := msg.GetUpdateMask().GetPaths() | 89 | paths := msg.GetUpdateMask().GetPaths() | ||
| 90 | if len(paths) == 0 { | 90 | if len(paths) == 0 { | ||
| 91 | return params, fmt.Errorf("%w: update_mask is empty", domain.ErrInvalid) | 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 | // respondRepo adds the default branch to repo and wraps it in a response. | 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 | view, err := repos.View(ctx, repo) | 139 | view, err := repos.View(ctx, repo) | ||
| 140 | if err != nil { | 140 | if err != nil { | ||
| 141 | return nil, connectError(ctx, err) | 141 | return nil, connectError(ctx, err) | ||
M internal/adapters/rpc/repo_test.go +16 -16
| @@ -14,9 +14,9 @@ import ( | |||||
| 14 | "google.golang.org/protobuf/types/known/fieldmaskpb" | 14 | "google.golang.org/protobuf/types/known/fieldmaskpb" | ||
| 15 | 15 | ||||
| 16 | pb "bnema.dev/ermite-api/gen/ermite" | 16 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 17 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |||
| 18 | - | "bnema.dev/ermite/internal/app" | |||
| 19 | "bnema.dev/ermite/internal/domain" | 17 | "bnema.dev/ermite/internal/domain" | ||
| 18 | + | "bnema.dev/ermite/internal/ports" | |||
| 19 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 20 | ) | 20 | ) | ||
| 21 | 21 | ||||
| 22 | // ownerCtx is the context of a call made by the owner, as the interceptor | 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 | for _, tt := range tests { | 60 | for _, tt := range tests { | ||
| 61 | t.Run(tt.name, func(t *testing.T) { | 61 | t.Run(tt.name, func(t *testing.T) { | ||
| 62 | t.Parallel() | 62 | t.Parallel() | ||
| 63 | - | repos := mocks.NewRepos(t) | 63 | + | repos := mocks.NewRepoService(t) |
| 64 | if tt.wantCall { | 64 | if tt.wantCall { | ||
| 65 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Description: "d", Visibility: domain.VisibilityPublic} | 65 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Description: "d", Visibility: domain.VisibilityPublic} | ||
| 66 | repos.EXPECT().Get(mock.Anything, domain.Owner(), repo.Name).Return(repo, tt.usecase).Once() | 66 | repos.EXPECT().Get(mock.Anything, domain.Owner(), repo.Name).Return(repo, tt.usecase).Once() | ||
| 67 | if tt.usecase == nil { | 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 | svc := &repoService{repos} | 71 | svc := &repoService{repos} | ||
| @@ -102,14 +102,14 @@ func TestRepoServiceCreateRepo(t *testing.T) { | |||||
| 102 | for _, tt := range tests { | 102 | for _, tt := range tests { | ||
| 103 | t.Run(tt.name, func(t *testing.T) { | 103 | t.Run(tt.name, func(t *testing.T) { | ||
| 104 | t.Parallel() | 104 | t.Parallel() | ||
| 105 | - | repos := mocks.NewRepos(t) | 105 | + | repos := mocks.NewRepoService(t) |
| 106 | if tt.wantCall { | 106 | if tt.wantCall { | ||
| 107 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Visibility: domain.VisibilityPrivate} | 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 | return p.Name.String() == "demo" | 109 | return p.Name.String() == "demo" | ||
| 110 | })).Return(repo, tt.usecase).Once() | 110 | })).Return(repo, tt.usecase).Once() | ||
| 111 | if tt.usecase == nil { | 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 | resp, err := (&repoService{repos}).CreateRepo(ownerCtx(), connect.NewRequest(tt.req)) | 115 | resp, err := (&repoService{repos}).CreateRepo(ownerCtx(), connect.NewRequest(tt.req)) | ||
| @@ -170,12 +170,12 @@ func TestRepoServiceUpdateRepoValidatesMask(t *testing.T) { | |||||
| 170 | for _, tt := range tests { | 170 | for _, tt := range tests { | ||
| 171 | t.Run(tt.name, func(t *testing.T) { | 171 | t.Run(tt.name, func(t *testing.T) { | ||
| 172 | t.Parallel() | 172 | t.Parallel() | ||
| 173 | - | repos := mocks.NewRepos(t) | 173 | + | repos := mocks.NewRepoService(t) |
| 174 | if tt.wantCall { | 174 | if tt.wantCall { | ||
| 175 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Description: "new"} | 175 | repo := domain.Repo{Name: mustRepoName(t, "demo"), Description: "new"} | ||
| 176 | repos.EXPECT().Update(mock.Anything, domain.Owner(), repo.Name, mock.Anything).Return(repo, tt.usecase).Once() | 176 | repos.EXPECT().Update(mock.Anything, domain.Owner(), repo.Name, mock.Anything).Return(repo, tt.usecase).Once() | ||
| 177 | if tt.usecase == nil { | 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 | resp, err := (&repoService{repos}).UpdateRepo(ownerCtx(), connect.NewRequest(tt.req)) | 181 | resp, err := (&repoService{repos}).UpdateRepo(ownerCtx(), connect.NewRequest(tt.req)) | ||
| @@ -206,7 +206,7 @@ func TestRepoServiceDeleteRepo(t *testing.T) { | |||||
| 206 | for _, tt := range tests { | 206 | for _, tt := range tests { | ||
| 207 | t.Run(tt.name, func(t *testing.T) { | 207 | t.Run(tt.name, func(t *testing.T) { | ||
| 208 | t.Parallel() | 208 | t.Parallel() | ||
| 209 | - | repos := mocks.NewRepos(t) | 209 | + | repos := mocks.NewRepoService(t) |
| 210 | if tt.wantCall { | 210 | if tt.wantCall { | ||
| 211 | repos.EXPECT().Delete(mock.Anything, domain.Owner(), mustRepoName(t, tt.repo)).Return(tt.usecase).Once() | 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 | t.Parallel() | 224 | t.Parallel() | ||
| 225 | t.Run("pages and views every repo", func(t *testing.T) { | 225 | t.Run("pages and views every repo", func(t *testing.T) { | ||
| 226 | t.Parallel() | 226 | t.Parallel() | ||
| 227 | - | repos := mocks.NewRepos(t) | 227 | + | repos := mocks.NewRepoService(t) |
| 228 | a := domain.Repo{Name: mustRepoName(t, "a")} | 228 | a := domain.Repo{Name: mustRepoName(t, "a")} | ||
| 229 | b := domain.Repo{Name: mustRepoName(t, "b")} | 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() | 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(app.RepoView{Repo: a}, nil).Once() | 231 | + | repos.EXPECT().View(mock.Anything, a).Return(ports.RepoView{Repo: a}, nil).Once() |
| 232 | - | repos.EXPECT().View(mock.Anything, b).Return(app.RepoView{Repo: b}, nil).Once() | 232 | + | repos.EXPECT().View(mock.Anything, b).Return(ports.RepoView{Repo: b}, nil).Once() |
| 233 | resp, err := (&repoService{repos}).ListRepos(ownerCtx(), connect.NewRequest(&pb.ListReposRequest{PageSize: 2, PageToken: "tok"})) | 233 | resp, err := (&repoService{repos}).ListRepos(ownerCtx(), connect.NewRequest(&pb.ListReposRequest{PageSize: 2, PageToken: "tok"})) | ||
| 234 | require.NoError(t, err) | 234 | require.NoError(t, err) | ||
| 235 | require.Len(t, resp.Msg.GetRepos(), 2) | 235 | require.Len(t, resp.Msg.GetRepos(), 2) | ||
| @@ -245,8 +245,8 @@ func TestRepoServiceListRepos(t *testing.T) { | |||||
| 245 | } { | 245 | } { | ||
| 246 | t.Run(name, func(t *testing.T) { | 246 | t.Run(name, func(t *testing.T) { | ||
| 247 | t.Parallel() | 247 | t.Parallel() | ||
| 248 | - | repos := mocks.NewRepos(t) | 248 | + | repos := mocks.NewRepoService(t) |
| 249 | - | repos.EXPECT().ListPage(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(app.RepoPage{}, tc.err).Once() | 249 | + | repos.EXPECT().ListPage(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(ports.RepoPage{}, tc.err).Once() |
| 250 | _, err := (&repoService{repos}).ListRepos(ownerCtx(), connect.NewRequest(&pb.ListReposRequest{})) | 250 | _, err := (&repoService{repos}).ListRepos(ownerCtx(), connect.NewRequest(&pb.ListReposRequest{})) | ||
| 251 | requireCode(t, tc.code, err) | 251 | requireCode(t, tc.code, err) | ||
| 252 | }) | 252 | }) | ||
M internal/adapters/rpc/server.go +2 -1
| @@ -9,12 +9,13 @@ import ( | |||||
| 9 | "connectrpc.com/connect" | 9 | "connectrpc.com/connect" | ||
| 10 | 10 | ||||
| 11 | pb "bnema.dev/ermite-api/gen/ermite" | 11 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 12 | + | "bnema.dev/ermite/internal/ports" | |||
| 12 | ) | 13 | ) | ||
| 13 | 14 | ||||
| 14 | // serverService implements ermiteconnect.ServerServiceHandler. | 15 | // serverService implements ermiteconnect.ServerServiceHandler. | ||
| 15 | type serverService struct { | 16 | type serverService struct { | ||
| 16 | version string | 17 | version string | ||
| 17 | - | key SigningKey | 18 | + | key ports.SigningKeyService |
| 18 | } | 19 | } | ||
| 19 | 20 | ||||
| 20 | func (s *serverService) GetVersion(context.Context, *connect.Request[pb.GetVersionRequest]) (*connect.Response[pb.GetVersionResponse], error) { | 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 | "github.com/stretchr/testify/require" | 11 | "github.com/stretchr/testify/require" | ||
| 12 | 12 | ||||
| 13 | pb "bnema.dev/ermite-api/gen/ermite" | 13 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |||
| 15 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 16 | ) | 16 | ) | ||
| 17 | 17 | ||||
| 18 | func TestServerServiceGetVersion(t *testing.T) { | 18 | func TestServerServiceGetVersion(t *testing.T) { | ||
| 19 | t.Parallel() | 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 | resp, err := svc.GetVersion(context.Background(), connect.NewRequest(&pb.GetVersionRequest{})) | 21 | resp, err := svc.GetVersion(context.Background(), connect.NewRequest(&pb.GetVersionRequest{})) | ||
| 22 | require.NoError(t, err) | 22 | require.NoError(t, err) | ||
| 23 | assert.Equal(t, "v1.2.3", resp.Msg.GetVersion()) | 23 | assert.Equal(t, "v1.2.3", resp.Msg.GetVersion()) | ||
| @@ -30,7 +30,7 @@ func TestServerServiceGetVersion(t *testing.T) { | |||||
| 30 | 30 | ||||
| 31 | func TestServerServiceGetSigningKey(t *testing.T) { | 31 | func TestServerServiceGetSigningKey(t *testing.T) { | ||
| 32 | t.Parallel() | 32 | t.Parallel() | ||
| 33 | - | key := mocks.NewSigningKey(t) | 33 | + | key := mocks.NewSigningKeyService(t) |
| 34 | key.EXPECT().Info().Return(domain.SigningKeyInfo{ | 34 | key.EXPECT().Info().Return(domain.SigningKeyInfo{ | ||
| 35 | Key: domain.SigningPublicKey{AuthorizedKey: "ssh-ed25519 AAAA", Fingerprint: "SHA256:xyz"}, | 35 | Key: domain.SigningPublicKey{AuthorizedKey: "ssh-ed25519 AAAA", Fingerprint: "SHA256:xyz"}, | ||
| 36 | Committer: domain.Identity{Name: "ermite", Email: "ermite@example.com"}, | 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 | "connectrpc.com/connect" | 8 | "connectrpc.com/connect" | ||
| 9 | 9 | ||||
| 10 | pb "bnema.dev/ermite-api/gen/ermite" | 10 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 11 | + | "bnema.dev/ermite/internal/ports" | |||
| 11 | ) | 12 | ) | ||
| 12 | 13 | ||||
| 13 | // sessionService implements ermiteconnect.SessionServiceHandler. The browser | 14 | // sessionService implements ermiteconnect.SessionServiceHandler. The browser | ||
| 14 | // never calls it: sessions come from the link, and the API ignores cookies. | 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 | func (s *sessionService) CreateLoginLink(ctx context.Context, _ *connect.Request[pb.CreateLoginLinkRequest]) (*connect.Response[pb.CreateLoginLinkResponse], error) { | 18 | func (s *sessionService) CreateLoginLink(ctx context.Context, _ *connect.Request[pb.CreateLoginLinkRequest]) (*connect.Response[pb.CreateLoginLinkResponse], error) { | ||
| 18 | link, err := s.sessions.CreateLoginLink(ctx, caller(ctx)) | 19 | link, err := s.sessions.CreateLoginLink(ctx, caller(ctx)) | ||
M internal/adapters/rpc/session_test.go +5 -5
| @@ -12,9 +12,9 @@ import ( | |||||
| 12 | "github.com/stretchr/testify/require" | 12 | "github.com/stretchr/testify/require" | ||
| 13 | 13 | ||||
| 14 | pb "bnema.dev/ermite-api/gen/ermite" | 14 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 15 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |||
| 16 | - | "bnema.dev/ermite/internal/app" | |||
| 17 | "bnema.dev/ermite/internal/domain" | 15 | "bnema.dev/ermite/internal/domain" | ||
| 16 | + | "bnema.dev/ermite/internal/ports" | |||
| 17 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 18 | ) | 18 | ) | ||
| 19 | 19 | ||||
| 20 | func TestSessionServiceCreateLoginLink(t *testing.T) { | 20 | func TestSessionServiceCreateLoginLink(t *testing.T) { | ||
| @@ -32,9 +32,9 @@ func TestSessionServiceCreateLoginLink(t *testing.T) { | |||||
| 32 | for _, tt := range tests { | 32 | for _, tt := range tests { | ||
| 33 | t.Run(tt.name, func(t *testing.T) { | 33 | t.Run(tt.name, func(t *testing.T) { | ||
| 34 | t.Parallel() | 34 | t.Parallel() | ||
| 35 | - | sessions := mocks.NewSessions(t) | 35 | + | sessions := mocks.NewSessionService(t) |
| 36 | sessions.EXPECT().CreateLoginLink(mock.Anything, domain.Owner()). | 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 | resp, err := (&sessionService{sessions}).CreateLoginLink(ownerCtx(), connect.NewRequest(&pb.CreateLoginLinkRequest{})) | 38 | resp, err := (&sessionService{sessions}).CreateLoginLink(ownerCtx(), connect.NewRequest(&pb.CreateLoginLinkRequest{})) | ||
| 39 | if tt.wantCode != 0 { | 39 | if tt.wantCode != 0 { | ||
| 40 | requireCode(t, tt.wantCode, err) | 40 | requireCode(t, tt.wantCode, err) | ||
| @@ -60,7 +60,7 @@ func TestSessionServiceSignOutEverywhere(t *testing.T) { | |||||
| 60 | for _, tt := range tests { | 60 | for _, tt := range tests { | ||
| 61 | t.Run(tt.name, func(t *testing.T) { | 61 | t.Run(tt.name, func(t *testing.T) { | ||
| 62 | t.Parallel() | 62 | t.Parallel() | ||
| 63 | - | sessions := mocks.NewSessions(t) | 63 | + | sessions := mocks.NewSessionService(t) |
| 64 | sessions.EXPECT().SignOutEverywhere(mock.Anything, domain.Owner()).Return(tt.usecase).Once() | 64 | sessions.EXPECT().SignOutEverywhere(mock.Anything, domain.Owner()).Return(tt.usecase).Once() | ||
| 65 | _, err := (&sessionService{sessions}).SignOutEverywhere(ownerCtx(), connect.NewRequest(&pb.SignOutEverywhereRequest{})) | 65 | _, err := (&sessionService{sessions}).SignOutEverywhere(ownerCtx(), connect.NewRequest(&pb.SignOutEverywhereRequest{})) | ||
| 66 | if tt.wantCode != 0 { | 66 | if tt.wantCode != 0 { | ||
M internal/adapters/rpc/token.go +3 -3
| @@ -8,15 +8,15 @@ import ( | |||||
| 8 | "connectrpc.com/connect" | 8 | "connectrpc.com/connect" | ||
| 9 | 9 | ||||
| 10 | pb "bnema.dev/ermite-api/gen/ermite" | 10 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 11 | - | "bnema.dev/ermite/internal/app" | |||
| 12 | "bnema.dev/ermite/internal/domain" | 11 | "bnema.dev/ermite/internal/domain" | ||
| 12 | + | "bnema.dev/ermite/internal/ports" | |||
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | // tokenService implements ermiteconnect.TokenServiceHandler. | 15 | // tokenService implements ermiteconnect.TokenServiceHandler. | ||
| 16 | - | type tokenService struct{ tokens Tokens } | 16 | + | type tokenService struct{ tokens ports.TokenService } |
| 17 | 17 | ||||
| 18 | func (s *tokenService) CreateToken(ctx context.Context, req *connect.Request[pb.CreateTokenRequest]) (*connect.Response[pb.CreateTokenResponse], error) { | 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 | Label: req.Msg.GetLabel(), | 20 | Label: req.Msg.GetLabel(), | ||
| 21 | ExpiresAt: goTime(req.Msg.GetExpiresAt()), | 21 | ExpiresAt: goTime(req.Msg.GetExpiresAt()), | ||
| 22 | } | 22 | } | ||
M internal/adapters/rpc/token_test.go +11 -11
| @@ -11,9 +11,9 @@ import ( | |||||
| 11 | "github.com/stretchr/testify/require" | 11 | "github.com/stretchr/testify/require" | ||
| 12 | 12 | ||||
| 13 | pb "bnema.dev/ermite-api/gen/ermite" | 13 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 14 | - | "bnema.dev/ermite/internal/adapters/rpc/mocks" | |||
| 15 | - | "bnema.dev/ermite/internal/app" | |||
| 16 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 16 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 17 | ) | 17 | ) | ||
| 18 | 18 | ||||
| 19 | func TestTokenServiceCreateToken(t *testing.T) { | 19 | func TestTokenServiceCreateToken(t *testing.T) { | ||
| @@ -35,10 +35,10 @@ func TestTokenServiceCreateToken(t *testing.T) { | |||||
| 35 | for _, tt := range tests { | 35 | for _, tt := range tests { | ||
| 36 | t.Run(tt.name, func(t *testing.T) { | 36 | t.Run(tt.name, func(t *testing.T) { | ||
| 37 | t.Parallel() | 37 | t.Parallel() | ||
| 38 | - | tokens := mocks.NewTokens(t) | 38 | + | tokens := mocks.NewTokenService(t) |
| 39 | if tt.wantCall { | 39 | if tt.wantCall { | ||
| 40 | tokens.EXPECT().Create(mock.Anything, domain.Owner(), mock.Anything). | 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 | resp, err := (&tokenService{tokens}).CreateToken(ownerCtx(), connect.NewRequest(tt.req)) | 43 | resp, err := (&tokenService{tokens}).CreateToken(ownerCtx(), connect.NewRequest(tt.req)) | ||
| 44 | if tt.wantCode != 0 { | 44 | if tt.wantCode != 0 { | ||
| @@ -54,10 +54,10 @@ func TestTokenServiceCreateToken(t *testing.T) { | |||||
| 54 | 54 | ||||
| 55 | func TestTokenServiceCreateTokenPassesParams(t *testing.T) { | 55 | func TestTokenServiceCreateTokenPassesParams(t *testing.T) { | ||
| 56 | t.Parallel() | 56 | t.Parallel() | ||
| 57 | - | tokens := mocks.NewTokens(t) | 57 | + | tokens := mocks.NewTokenService(t) |
| 58 | - | tokens.EXPECT().Create(mock.Anything, domain.Owner(), mock.MatchedBy(func(p app.CreateTokenParams) bool { | 58 | + | tokens.EXPECT().Create(mock.Anything, domain.Owner(), mock.MatchedBy(func(p ports.CreateTokenParams) bool { |
| 59 | return p.Label == "ci" && len(p.Scopes) == 1 && len(p.Repos) == 1 && p.Repos[0].String() == "demo" | 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 | _, err := (&tokenService{tokens}).CreateToken(ownerCtx(), connect.NewRequest(&pb.CreateTokenRequest{ | 61 | _, err := (&tokenService{tokens}).CreateToken(ownerCtx(), connect.NewRequest(&pb.CreateTokenRequest{ | ||
| 62 | Label: "ci", Scopes: []pb.Scope{pb.Scope_SCOPE_REPO_READ}, Repos: []string{"demo"}, | 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 | for _, tt := range tests { | 78 | for _, tt := range tests { | ||
| 79 | t.Run(tt.name, func(t *testing.T) { | 79 | t.Run(tt.name, func(t *testing.T) { | ||
| 80 | t.Parallel() | 80 | t.Parallel() | ||
| 81 | - | tokens := mocks.NewTokens(t) | 81 | + | tokens := mocks.NewTokenService(t) |
| 82 | tokens.EXPECT().Revoke(mock.Anything, domain.Owner(), "t1").Return(tt.usecase).Once() | 82 | tokens.EXPECT().Revoke(mock.Anything, domain.Owner(), "t1").Return(tt.usecase).Once() | ||
| 83 | _, err := (&tokenService{tokens}).RevokeToken(ownerCtx(), connect.NewRequest(&pb.RevokeTokenRequest{Id: "t1"})) | 83 | _, err := (&tokenService{tokens}).RevokeToken(ownerCtx(), connect.NewRequest(&pb.RevokeTokenRequest{Id: "t1"})) | ||
| 84 | if tt.wantCode != 0 { | 84 | if tt.wantCode != 0 { | ||
| @@ -92,15 +92,15 @@ func TestTokenServiceRevokeToken(t *testing.T) { | |||||
| 92 | 92 | ||||
| 93 | func TestTokenServiceListTokens(t *testing.T) { | 93 | func TestTokenServiceListTokens(t *testing.T) { | ||
| 94 | t.Parallel() | 94 | t.Parallel() | ||
| 95 | - | tokens := mocks.NewTokens(t) | 95 | + | tokens := mocks.NewTokenService(t) |
| 96 | tokens.EXPECT().ListPage(mock.Anything, domain.Owner(), 5, "tok"). | 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 | resp, err := (&tokenService{tokens}).ListTokens(ownerCtx(), connect.NewRequest(&pb.ListTokensRequest{PageSize: 5, PageToken: "tok"})) | 98 | resp, err := (&tokenService{tokens}).ListTokens(ownerCtx(), connect.NewRequest(&pb.ListTokensRequest{PageSize: 5, PageToken: "tok"})) | ||
| 99 | require.NoError(t, err) | 99 | require.NoError(t, err) | ||
| 100 | assert.Len(t, resp.Msg.GetTokens(), 2) | 100 | assert.Len(t, resp.Msg.GetTokens(), 2) | ||
| 101 | assert.Equal(t, "n", resp.Msg.GetNextPageToken()) | 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 | _, err = (&tokenService{tokens}).ListTokens(ownerCtx(), connect.NewRequest(&pb.ListTokensRequest{})) | 104 | _, err = (&tokenService{tokens}).ListTokens(ownerCtx(), connect.NewRequest(&pb.ListTokensRequest{})) | ||
| 105 | requireCode(t, connect.CodeInvalidArgument, err) | 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 | pb "bnema.dev/ermite-api/gen/ermite" | 21 | pb "bnema.dev/ermite-api/gen/ermite" | ||
| 22 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | 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 | func TestFormatEvent(t *testing.T) { | 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 | // eventsServerWith is eventsServer with sessions, when sess is not nil. | 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 | t.Helper() | 120 | t.Helper() | ||
| 120 | api := http.NewServeMux() | 121 | api := http.NewServeMux() | ||
| 121 | api.Handle(ermiteconnect.NewEventServiceHandler(f)) | 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 | if sess == nil { | 292 | if sess == nil { | ||
| 292 | return nil | 293 | return nil | ||
| 293 | } | 294 | } | ||
| 294 | return &countingLimiter{} | 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 | // ended, like SignOutEverywhere does. | 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 | t.Helper() | 301 | t.Helper() | ||
| 301 | var ended atomic.Bool | 302 | var ended atomic.Bool | ||
| 302 | return newVerifier(t, valid, func(tok string) (bool, error) { return tok == valid && !ended.Load(), nil }), &ended | 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 | "github.com/bnema/zerowrap" | 16 | "github.com/bnema/zerowrap" | ||
| 17 | 17 | ||||
| 18 | "bnema.dev/ermite/internal/clientlimit" | 18 | "bnema.dev/ermite/internal/clientlimit" | ||
| 19 | + | "bnema.dev/ermite/internal/ports" | |||
| 19 | ) | 20 | ) | ||
| 20 | 21 | ||||
| 21 | // The owner's session on the web (ADR 0018). | 22 | // The owner's session on the web (ADR 0018). | ||
| @@ -39,31 +40,6 @@ const CookieName = "__Host-ermite" | |||||
| 39 | // loginPrefix is the path of login links, up to the nonce. | 40 | // loginPrefix is the path of login links, up to the nonce. | ||
| 40 | const loginPrefix = "/-/login/" | 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 | type signedInKey struct{} | 43 | type signedInKey struct{} | ||
| 68 | 44 | ||||
| 69 | // SignedIn reports whether the request carries a valid owner session. The | 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 | nonce := r.PathValue("nonce") | 251 | nonce := r.PathValue("nonce") | ||
| 276 | var token string | 252 | var token string | ||
| 277 | var lifetime time.Duration | 253 | var lifetime time.Duration | ||
| 278 | - | err := ErrLinkRejected | 254 | + | err := ports.ErrLinkRejected |
| 279 | if validNonce(nonce) { | 255 | if validNonce(nonce) { | ||
| 280 | token, lifetime, err = s.cfg.Sessions.Login(ctx, nonce) | 256 | token, lifetime, err = s.cfg.Sessions.Login(ctx, nonce) | ||
| 281 | } | 257 | } | ||
| 282 | switch { | 258 | switch { | ||
| 283 | - | case errors.Is(err, ErrLinkRejected): | 259 | + | case errors.Is(err, ports.ErrLinkRejected): |
| 284 | s.cfg.Limiter.Fail(ctx, addr) | 260 | s.cfg.Limiter.Fail(ctx, addr) | ||
| 285 | s.secretPage(w, r, http.StatusNotFound, s.loginRejectedPage()) | 261 | s.secretPage(w, r, http.StatusNotFound, s.loginRejectedPage()) | ||
| 286 | return | 262 | return | ||
M internal/adapters/web/session_test.go +13 -12
| @@ -17,21 +17,22 @@ import ( | |||||
| 17 | "github.com/stretchr/testify/require" | 17 | "github.com/stretchr/testify/require" | ||
| 18 | 18 | ||||
| 19 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | 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 | // nonceA is the one valid login link of the mocks. | 24 | // nonceA is the one valid login link of the mocks. | ||
| 24 | var nonceA = strings.Repeat("a", 43) | 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 | // by verify when it is not nil, and that does not know any login link. A | 28 | // by verify when it is not nil, and that does not know any login link. A | ||
| 28 | // call that is not expected fails the test. | 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 | t.Helper() | 31 | t.Helper() | ||
| 31 | if verify == nil { | 32 | if verify == nil { | ||
| 32 | verify = func(token string) (bool, error) { return token == valid, nil } | 33 | verify = func(token string) (bool, error) { return token == valid, nil } | ||
| 33 | } | 34 | } | ||
| 34 | - | m := mocks.NewSessionAuth(t) | 35 | + | m := mocks.NewWebSessionService(t) |
| 35 | m.EXPECT().Verify(mock.Anything, mock.Anything).RunAndReturn( | 36 | m.EXPECT().Verify(mock.Anything, mock.Anything).RunAndReturn( | ||
| 36 | func(ctx context.Context, token string) (context.Context, bool, error) { | 37 | func(ctx context.Context, token string) (context.Context, bool, error) { | ||
| 37 | ok, err := verify(token) | 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 | // expectLogin makes nonceA the one link of m, answering with the token valid. | 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 | m.EXPECT().LoginLinkValid(mock.Anything).RunAndReturn(func(n string) bool { return n == nonceA }).Maybe() | 46 | m.EXPECT().LoginLinkValid(mock.Anything).RunAndReturn(func(n string) bool { return n == nonceA }).Maybe() | ||
| 46 | m.EXPECT().Login(mock.Anything, nonceA).Return(valid, time.Hour, nil).Maybe() | 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 | + | // newSessions is a WebSessionService with one session token and one login link. |
| 51 | - | func newSessions(t *testing.T, valid string) *mocks.SessionAuth { | 52 | + | func newSessions(t *testing.T, valid string) *mocks.WebSessionService { |
| 52 | t.Helper() | 53 | t.Helper() | ||
| 53 | m := newVerifier(t, valid, nil) | 54 | m := newVerifier(t, valid, nil) | ||
| 54 | expectLogin(m, valid) | 55 | expectLogin(m, valid) | ||
| 55 | return m | 56 | return m | ||
| 56 | } | 57 | } | ||
| 57 | 58 | ||||
| 58 | - | // newBrokenSessions is a SessionAuth whose check cannot be made. | 59 | + | // newBrokenSessions is a WebSessionService whose check cannot be made. |
| 59 | - | func newBrokenSessions(t *testing.T, valid string) *mocks.SessionAuth { | 60 | + | func newBrokenSessions(t *testing.T, valid string) *mocks.WebSessionService { |
| 60 | t.Helper() | 61 | t.Helper() | ||
| 61 | m := newVerifier(t, valid, func(string) (bool, error) { return false, errors.New("kv down") }) | 62 | m := newVerifier(t, valid, func(string) (bool, error) { return false, errors.New("kv down") }) | ||
| 62 | expectLogin(m, valid) | 63 | expectLogin(m, valid) | ||
| @@ -68,7 +69,7 @@ type countingLimiter struct{ fails int } | |||||
| 68 | func (*countingLimiter) Blocked(context.Context, string) (bool, time.Duration) { return false, 0 } | 69 | func (*countingLimiter) Blocked(context.Context, string) (bool, time.Duration) { return false, 0 } | ||
| 69 | func (l *countingLimiter) Fail(context.Context, string) { l.fails++ } | 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 | t.Helper() | 73 | t.Helper() | ||
| 73 | lim := &countingLimiter{} | 74 | lim := &countingLimiter{} | ||
| 74 | srv, err := New(Config{ | 75 | srv, err := New(Config{ | ||
| @@ -294,7 +295,7 @@ func TestNoSessionsNoRoutes(t *testing.T) { | |||||
| 294 | 295 | ||||
| 295 | _, err = New(Config{ | 296 | _, err = New(Config{ | ||
| 296 | Repos: failing{}, Git: ermiteconnect.NewGitServiceClient(http.DefaultClient, "http://unused.invalid"), | 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 | assert.Error(t, err, "sessions need a limiter") | 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 | "github.com/bnema/zerowrap" | 33 | "github.com/bnema/zerowrap" | ||
| 34 | 34 | ||||
| 35 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | 35 | "bnema.dev/ermite-api/gen/ermite/ermiteconnect" | ||
| 36 | + | "bnema.dev/ermite/internal/ports" | |||
| 36 | ) | 37 | ) | ||
| 37 | 38 | ||||
| 38 | // Patterns are the ServeMux patterns the handler serves: everything. The | 39 | // Patterns are the ServeMux patterns the handler serves: everything. The | ||
| @@ -69,10 +70,10 @@ type Config struct { | |||||
| 69 | Now func() time.Time | 70 | Now func() time.Time | ||
| 70 | // Sessions signs the owner in (ADR 0018). Without it there are no login | 71 | // Sessions signs the owner in (ADR 0018). Without it there are no login | ||
| 71 | // routes and every visitor is anonymous. | 72 | // routes and every visitor is anonymous. | ||
| 72 | - | Sessions SessionAuth | 73 | + | Sessions ports.WebSessionService |
| 73 | // Limiter counts the failed logins; required with Sessions. Share it with | 74 | // Limiter counts the failed logins; required with Sessions. Share it with | ||
| 74 | // the API and Git, so that a client has one budget of failures. | 75 | // the API and Git, so that a client has one budget of failures. | ||
| 75 | - | Limiter FailureLimiter | 76 | + | Limiter ports.FailureLimiter |
| 76 | // TrustedProxies are the networks allowed to set X-Forwarded-For, to find | 77 | // TrustedProxies are the networks allowed to set X-Forwarded-For, to find | ||
| 77 | // the address of the client that fails a login. | 78 | // the address of the client that fails a login. | ||
| 78 | TrustedProxies []netip.Prefix | 79 | TrustedProxies []netip.Prefix | ||
M internal/app/browse.go +15 -52
| @@ -31,6 +31,8 @@ type Browse struct { | |||||
| 31 | history *historyCache | 31 | history *historyCache | ||
| 32 | } | 32 | } | ||
| 33 | 33 | ||||
| 34 | + | var _ ports.BrowseService = (*Browse)(nil) | |||
| 35 | + | ||||
| 34 | // NewBrowse builds the read use cases over their ports, with a history cache | 36 | // NewBrowse builds the read use cases over their ports, with a history cache | ||
| 35 | // of the default bounds. | 37 | // of the default bounds. | ||
| 36 | func NewBrowse(meta ports.RepoMetaStore, reader ports.RepoReader) *Browse { | 38 | func NewBrowse(meta ports.RepoMetaStore, reader ports.RepoReader) *Browse { | ||
| @@ -71,23 +73,6 @@ func repoEpoch(r domain.Repo) int64 { | |||||
| 71 | return r.CreatedAt.UnixNano() | 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 | func kindRank(k domain.RefKind) int { | 76 | func kindRank(k domain.RefKind) int { | ||
| 92 | switch k { | 77 | switch k { | ||
| 93 | case domain.RefKindHead: | 78 | case domain.RefKindHead: | ||
| @@ -101,26 +86,26 @@ func kindRank(k domain.RefKind) int { | |||||
| 101 | // ListRefs lists HEAD, the branches and the tags, in that order, then by | 86 | // ListRefs lists HEAD, the branches and the tags, in that order, then by | ||
| 102 | // name. The page token names the last ref of the previous page, so refs that | 87 | // name. The page token names the last ref of the previous page, so refs that | ||
| 103 | // appear or disappear between two pages never shift the others. | 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 | size, err := pageSizeUpTo(params.PageSize, MaxRefPageSize) | 90 | size, err := pageSizeUpTo(params.PageSize, MaxRefPageSize) | ||
| 106 | if err != nil { | 91 | if err != nil { | ||
| 107 | - | return RefPage{}, err | 92 | + | return ports.RefPage{}, err |
| 108 | } | 93 | } | ||
| 109 | for _, k := range params.Kinds { | 94 | for _, k := range params.Kinds { | ||
| 110 | if k != domain.RefKindHead && k != domain.RefKindBranch && k != domain.RefKindTag { | 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 | after, err := decodeRefToken(params.PageToken) | 99 | after, err := decodeRefToken(params.PageToken) | ||
| 115 | if err != nil { | 100 | if err != nil { | ||
| 116 | - | return RefPage{}, err | 101 | + | return ports.RefPage{}, err |
| 117 | } | 102 | } | ||
| 118 | if _, err := b.authorize(ctx, p, repo); err != nil { | 103 | if _, err := b.authorize(ctx, p, repo); err != nil { | ||
| 119 | - | return RefPage{}, err | 104 | + | return ports.RefPage{}, err |
| 120 | } | 105 | } | ||
| 121 | all, err := b.reader.ListRefs(ctx, repo) | 106 | all, err := b.reader.ListRefs(ctx, repo) | ||
| 122 | if err != nil { | 107 | if err != nil { | ||
| 123 | - | return RefPage{}, err | 108 | + | return ports.RefPage{}, err |
| 124 | } | 109 | } | ||
| 125 | 110 | ||||
| 126 | var wanted []domain.Ref | 111 | var wanted []domain.Ref | ||
| @@ -129,7 +114,7 @@ func (b *Browse) ListRefs(ctx context.Context, p domain.Principal, repo domain.R | |||||
| 129 | wanted = append(wanted, r) | 114 | wanted = append(wanted, r) | ||
| 130 | } | 115 | } | ||
| 131 | } | 116 | } | ||
| 132 | - | var page RefPage | 117 | + | var page ports.RefPage |
| 133 | page.Refs, page.NextPageToken = pageAfter(wanted, size, | 118 | page.Refs, page.NextPageToken = pageAfter(wanted, size, | ||
| 134 | func(r domain.Ref) bool { return after == nil || refAfter(r, *after) }, | 119 | func(r domain.Ref) bool { return after == nil || refAfter(r, *after) }, | ||
| 135 | encodeRefToken) | 120 | encodeRefToken) | ||
| @@ -227,53 +212,31 @@ func (b *Browse) OpenBlob(ctx context.Context, p domain.Principal, repo domain.R | |||||
| 227 | return b.reader.OpenBlob(ctx, repo, rev, path) | 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 | // ListCommits returns a page of history. The page token holds the commit the | 215 | // ListCommits returns a page of history. The page token holds the commit the | ||
| 253 | // listing started from, how many commits were already returned and a digest | 216 | // listing started from, how many commits were already returned and a digest | ||
| 254 | // of the path; a token used with another path is invalid. | 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 | size, err := pageSize(params.PageSize) | 219 | size, err := pageSize(params.PageSize) | ||
| 257 | if err != nil { | 220 | if err != nil { | ||
| 258 | - | return CommitPage{}, err | 221 | + | return ports.HistoryPage{}, err |
| 259 | } | 222 | } | ||
| 260 | q := ports.CommitQuery{Revision: params.Revision, Path: params.Path, Limit: size} | 223 | q := ports.CommitQuery{Revision: params.Revision, Path: params.Path, Limit: size} | ||
| 261 | if params.PageToken != "" { | 224 | if params.PageToken != "" { | ||
| 262 | head, skip, err := decodeCommitToken(params.PageToken, params.Path) | 225 | head, skip, err := decodeCommitToken(params.PageToken, params.Path) | ||
| 263 | if err != nil { | 226 | if err != nil { | ||
| 264 | - | return CommitPage{}, err | 227 | + | return ports.HistoryPage{}, err |
| 265 | } | 228 | } | ||
| 266 | q.Revision, q.Skip = domain.RevisionOf(head), skip | 229 | q.Revision, q.Skip = domain.RevisionOf(head), skip | ||
| 267 | } | 230 | } | ||
| 268 | r, err := b.authorize(ctx, p, repo) | 231 | r, err := b.authorize(ctx, p, repo) | ||
| 269 | if err != nil { | 232 | if err != nil { | ||
| 270 | - | return CommitPage{}, err | 233 | + | return ports.HistoryPage{}, err |
| 271 | } | 234 | } | ||
| 272 | res, err := b.listCommits(ctx, r, q) | 235 | res, err := b.listCommits(ctx, r, q) | ||
| 273 | if err != nil { | 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 | if res.HasMore { | 240 | if res.HasMore { | ||
| 278 | out.NextPageToken = encodeCommitToken(res.Head, q.Skip+len(res.Commits), params.Path) | 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 | root := domain.TreePath{} | 55 | root := domain.TreePath{} | ||
| 56 | return []browseOp{ | 56 | return []browseOp{ | ||
| 57 | {"ListRefs", func(b *app.Browse, ctx context.Context, p domain.Principal, repo domain.RepoName) error { | 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 | return err | 59 | return err | ||
| 60 | }, func(r *mocks.RepoReader) { r.EXPECT().ListRefs(mock.Anything, mock.Anything).Return(nil, nil) }}, | 60 | }, func(r *mocks.RepoReader) { r.EXPECT().ListRefs(mock.Anything, mock.Anything).Return(nil, nil) }}, | ||
| 61 | {"ResolveRevision", func(b *app.Browse, ctx context.Context, p domain.Principal, repo domain.RepoName) error { | 61 | {"ResolveRevision", func(b *app.Browse, ctx context.Context, p domain.Principal, repo domain.RepoName) error { | ||
| @@ -87,7 +87,7 @@ func browseOps() []browseOp { | |||||
| 87 | Return(domain.BlobInfo{}, io.NopCloser(strings.NewReader("")), nil) | 87 | Return(domain.BlobInfo{}, io.NopCloser(strings.NewReader("")), nil) | ||
| 88 | }}, | 88 | }}, | ||
| 89 | {"ListCommits", func(b *app.Browse, ctx context.Context, p domain.Principal, repo domain.RepoName) error { | 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 | return err | 91 | return err | ||
| 92 | }, func(r *mocks.RepoReader) { | 92 | }, func(r *mocks.RepoReader) { | ||
| 93 | r.EXPECT().ListCommits(mock.Anything, mock.Anything, mock.Anything).Return(ports.CommitPage{}, nil) | 93 | r.EXPECT().ListCommits(mock.Anything, mock.Anything, mock.Anything).Return(ports.CommitPage{}, nil) | ||
| @@ -214,7 +214,7 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||||
| 214 | tok := "" | 214 | tok := "" | ||
| 215 | for pages := 0; ; pages++ { | 215 | for pages := 0; ; pages++ { | ||
| 216 | require.Less(t, pages, 10) | 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 | require.NoError(t, err) | 218 | require.NoError(t, err) | ||
| 219 | got = append(got, names(page.Refs)...) | 219 | got = append(got, names(page.Refs)...) | ||
| 220 | if tok = page.NextPageToken; tok == "" { | 220 | if tok = page.NextPageToken; tok == "" { | ||
| @@ -226,19 +226,19 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||||
| 226 | 226 | ||||
| 227 | t.Run("a ref that appears between pages does not shift the others", func(t *testing.T) { | 227 | t.Run("a ref that appears between pages does not shift the others", func(t *testing.T) { | ||
| 228 | b := setup(t, all[:4]) | 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 | require.NoError(t, err) | 230 | require.NoError(t, err) | ||
| 231 | require.Equal(t, []string{"HEAD", "refs/heads/a"}, names(page.Refs)) | 231 | require.Equal(t, []string{"HEAD", "refs/heads/a"}, names(page.Refs)) | ||
| 232 | 232 | ||||
| 233 | b2 := setup(t, append([]domain.Ref{all[0], ref(domain.RefKindBranch, "refs/heads/0new")}, all[1:4]...)) | 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 | require.NoError(t, err) | 235 | require.NoError(t, err) | ||
| 236 | assert.Equal(t, []string{"refs/heads/b", "refs/heads/c"}, names(next.Refs)) | 236 | assert.Equal(t, []string{"refs/heads/b", "refs/heads/c"}, names(next.Refs)) | ||
| 237 | }) | 237 | }) | ||
| 238 | 238 | ||||
| 239 | t.Run("kinds filter", func(t *testing.T) { | 239 | t.Run("kinds filter", func(t *testing.T) { | ||
| 240 | b := setup(t, all) | 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 | require.NoError(t, err) | 242 | require.NoError(t, err) | ||
| 243 | assert.Equal(t, []string{"refs/tags/v1", "refs/tags/v2"}, names(page.Refs)) | 243 | assert.Equal(t, []string{"refs/tags/v1", "refs/tags/v2"}, names(page.Refs)) | ||
| 244 | assert.Empty(t, page.NextPageToken) | 244 | assert.Empty(t, page.NextPageToken) | ||
| @@ -251,13 +251,13 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||||
| 251 | many = append(many, ref(domain.RefKindTag, fmt.Sprintf("refs/tags/t%04d", i))) | 251 | many = append(many, ref(domain.RefKindTag, fmt.Sprintf("refs/tags/t%04d", i))) | ||
| 252 | } | 252 | } | ||
| 253 | b := setup(t, many) | 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 | require.NoError(t, err) | 255 | require.NoError(t, err) | ||
| 256 | assert.Len(t, page.Refs, app.DefaultPageSize) | 256 | assert.Len(t, page.Refs, app.DefaultPageSize) | ||
| 257 | assert.NotEmpty(t, page.NextPageToken) | 257 | assert.NotEmpty(t, page.NextPageToken) | ||
| 258 | 258 | ||||
| 259 | b = setup(t, many) | 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 | require.NoError(t, err) | 261 | require.NoError(t, err) | ||
| 262 | assert.Len(t, page.Refs, app.MaxRefPageSize, "a page holds up to MaxRefPageSize refs") | 262 | assert.Len(t, page.Refs, app.MaxRefPageSize, "a page holds up to MaxRefPageSize refs") | ||
| 263 | assert.NotEmpty(t, page.NextPageToken) | 263 | assert.NotEmpty(t, page.NextPageToken) | ||
| @@ -266,7 +266,7 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||||
| 266 | t.Run("bad input never reaches the reader", func(t *testing.T) { | 266 | t.Run("bad input never reaches the reader", func(t *testing.T) { | ||
| 267 | t.Parallel() | 267 | t.Parallel() | ||
| 268 | f := newBrowseFixture(t) | 268 | f := newBrowseFixture(t) | ||
| 269 | - | for _, params := range []app.ListRefsParams{ | 269 | + | for _, params := range []ports.ListRefsParams{ |
| 270 | {PageSize: -1}, | 270 | {PageSize: -1}, | ||
| 271 | {Kinds: []domain.RefKind{"nope"}}, | 271 | {Kinds: []domain.RefKind{"nope"}}, | ||
| 272 | {PageToken: "!!!"}, | 272 | {PageToken: "!!!"}, | ||
| @@ -275,11 +275,11 @@ func TestListRefsPagingAndKinds(t *testing.T) { | |||||
| 275 | _, err := f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, params) | 275 | _, err := f.browse.ListRefs(ctx, domain.Anonymous(), pub.Name, params) | ||
| 276 | assert.Error(t, err, "%+v", params) | 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 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | 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 | assert.ErrorIs(t, err, domain.ErrInvalidRefKind) | 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 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | 283 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | ||
| 284 | }) | 284 | }) | ||
| 285 | } | 285 | } | ||
| @@ -296,7 +296,7 @@ func TestListCommitsPaging(t *testing.T) { | |||||
| 296 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | 296 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | ||
| 297 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Path: p, Limit: 10}). | 297 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Path: p, Limit: 10}). | ||
| 298 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil) | 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 | require.NoError(t, err) | 300 | require.NoError(t, err) | ||
| 301 | require.Len(t, page.Commits, 1) | 301 | require.Len(t, page.Commits, 1) | ||
| 302 | require.NotEmpty(t, page.NextPageToken) | 302 | require.NotEmpty(t, page.NextPageToken) | ||
| @@ -308,7 +308,7 @@ func TestListCommitsPaging(t *testing.T) { | |||||
| 308 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | 308 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | ||
| 309 | // The revision of the request is ignored once there is a token. | 309 | // The revision of the request is ignored once there is a token. | ||
| 310 | rev, _ := domain.ParseRevision("moved") | 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 | Revision: rev, Path: p, PageSize: 10, PageToken: page.NextPageToken, | 312 | Revision: rev, Path: p, PageSize: 10, PageToken: page.NextPageToken, | ||
| 313 | }) | 313 | }) | ||
| 314 | require.NoError(t, err) | 314 | require.NoError(t, err) | ||
| @@ -322,10 +322,10 @@ func TestListCommitsPaging(t *testing.T) { | |||||
| 322 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | 322 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil) | ||
| 323 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.Anything). | 323 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.Anything). | ||
| 324 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil) | 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 | require.NoError(t, err) | 326 | require.NoError(t, err) | ||
| 327 | 327 | ||||
| 328 | - | for _, params := range []app.ListCommitsParams{ | 328 | + | for _, params := range []ports.ListCommitsParams{ |
| 329 | {PageToken: page.NextPageToken}, // no path | 329 | {PageToken: page.NextPageToken}, // no path | ||
| 330 | {Path: mustPath(t, "other"), PageToken: page.NextPageToken}, // another path | 330 | {Path: mustPath(t, "other"), PageToken: page.NextPageToken}, // another path | ||
| 331 | {Path: p, PageToken: "garbage"}, | 331 | {Path: p, PageToken: "garbage"}, | ||
| @@ -343,7 +343,7 @@ func TestListCommitsPaging(t *testing.T) { | |||||
| 343 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil).Maybe() | 343 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil).Maybe() | ||
| 344 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.Anything). | 344 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.Anything). | ||
| 345 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil).Once() | 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 | require.NoError(t, err) | 347 | require.NoError(t, err) | ||
| 348 | raw, err := base64.RawURLEncoding.DecodeString(page.NextPageToken) | 348 | raw, err := base64.RawURLEncoding.DecodeString(page.NextPageToken) | ||
| 349 | require.NoError(t, err) | 349 | require.NoError(t, err) | ||
| @@ -356,9 +356,9 @@ func TestListCommitsPaging(t *testing.T) { | |||||
| 356 | 356 | ||||
| 357 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.MatchedBy(func(q ports.CommitQuery) bool { return q.Skip == app.MaxCommitSkip })). | 357 | f.reader.EXPECT().ListCommits(ctx, pub.Name, mock.MatchedBy(func(q ports.CommitQuery) bool { return q.Skip == app.MaxCommitSkip })). | ||
| 358 | Return(ports.CommitPage{Head: oid("a")}, nil).Once() | 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 | require.NoError(t, err, "the cap itself is allowed") | 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 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | 362 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | ||
| 363 | }) | 363 | }) | ||
| 364 | 364 | ||||
| @@ -368,11 +368,11 @@ func TestListCommitsPaging(t *testing.T) { | |||||
| 368 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil).Times(2) | 368 | f.meta.EXPECT().Get(ctx, pub.Name).Return(pub, nil).Times(2) | ||
| 369 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Limit: app.DefaultPageSize}).Return(ports.CommitPage{}, nil) | 369 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Limit: app.DefaultPageSize}).Return(ports.CommitPage{}, nil) | ||
| 370 | f.reader.EXPECT().ListCommits(ctx, pub.Name, ports.CommitQuery{Limit: 100}).Return(ports.CommitPage{}, nil) | 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 | require.NoError(t, err) | 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 | require.NoError(t, err) | 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 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | 376 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | ||
| 377 | }) | 377 | }) | ||
| 378 | 378 | ||||
| @@ -382,10 +382,10 @@ func TestListCommitsPaging(t *testing.T) { | |||||
| 382 | f.meta.EXPECT().Get(ctx, priv.Name).Return(priv, nil) | 382 | f.meta.EXPECT().Get(ctx, priv.Name).Return(priv, nil) | ||
| 383 | f.reader.EXPECT().ListCommits(ctx, priv.Name, mock.Anything). | 383 | f.reader.EXPECT().ListCommits(ctx, priv.Name, mock.Anything). | ||
| 384 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("b")}}, HasMore: true}, nil) | 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 | require.NoError(t, err) | 386 | require.NoError(t, err) | ||
| 387 | f.meta.EXPECT().Get(ctx, priv.Name).Return(priv, nil) | 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 | assert.ErrorIs(t, err, domain.ErrNotFound) | 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 | r.EXPECT().GetTree(mock.Anything, n, rev, dir, true).Return(domain.Tree{}, domain.ErrNotFound).Once() | 131 | r.EXPECT().GetTree(mock.Anything, n, rev, dir, true).Return(domain.Tree{}, domain.ErrNotFound).Once() | ||
| 132 | }}, | 132 | }}, | ||
| 133 | {"last change of a path", func(b *app.Browse) error { | 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 | return err | 135 | return err | ||
| 136 | }, func(r *mocks.RepoReader) { | 136 | }, func(r *mocks.RepoReader) { | ||
| 137 | q := ports.CommitQuery{Revision: rev, Path: dir, Limit: 1} | 137 | q := ports.CommitQuery{Revision: rev, Path: dir, Limit: 1} | ||
| @@ -305,7 +305,7 @@ func TestListCommitsLastChangeCache(t *testing.T) { | |||||
| 305 | }, nil).Times(tc.calls) | 305 | }, nil).Times(tc.calls) | ||
| 306 | for range 2 { | 306 | for range 2 { | ||
| 307 | page, err := f.browse.ListCommits(ctx, domain.Anonymous(), pub.Name, | 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 | require.NoError(t, err) | 309 | require.NoError(t, err) | ||
| 310 | require.Len(t, page.Commits, 1) | 310 | require.Len(t, page.Commits, 1) | ||
| 311 | page.Commits[0].Parents[0] = oid("f") // must not leak into the cache | 311 | page.Commits[0].Parents[0] = oid("f") // must not leak into the cache | ||
| @@ -319,13 +319,13 @@ func TestListCommitsLastChangeCache(t *testing.T) { | |||||
| 319 | f.meta.EXPECT().Get(mock.Anything, pub.Name).Return(pub, nil) | 319 | f.meta.EXPECT().Get(mock.Anything, pub.Name).Return(pub, nil) | ||
| 320 | f.reader.EXPECT().ListCommits(mock.Anything, pub.Name, ports.CommitQuery{Revision: full, Path: file, Limit: 1}). | 320 | f.reader.EXPECT().ListCommits(mock.Anything, pub.Name, ports.CommitQuery{Revision: full, Path: file, Limit: 1}). | ||
| 321 | Return(ports.CommitPage{Head: oid("a"), Commits: []domain.Commit{{ID: oid("c")}}, HasMore: true}, nil).Once() | 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 | require.NoError(t, err) | 323 | require.NoError(t, err) | ||
| 324 | require.NotEmpty(t, first.NextPageToken) | 324 | require.NotEmpty(t, first.NextPageToken) | ||
| 325 | f.reader.EXPECT().ListCommits(mock.Anything, pub.Name, ports.CommitQuery{Revision: domain.RevisionOf(oid("a")), Path: file, Skip: 1, Limit: 1}). | 325 | f.reader.EXPECT().ListCommits(mock.Anything, pub.Name, ports.CommitQuery{Revision: domain.RevisionOf(oid("a")), Path: file, Skip: 1, Limit: 1}). | ||
| 326 | Return(ports.CommitPage{Head: oid("a")}, nil).Twice() | 326 | Return(ports.CommitPage{Head: oid("a")}, nil).Twice() | ||
| 327 | for range 2 { | 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 | require.NoError(t, err) | 329 | require.NoError(t, err) | ||
| 330 | } | 330 | } | ||
| 331 | }) | 331 | }) | ||
M internal/app/events.go +13 -45
| @@ -27,7 +27,7 @@ const ( | |||||
| 27 | // MaxWatchers is the most watches in progress at once. | 27 | // MaxWatchers is the most watches in progress at once. | ||
| 28 | MaxWatchers = 256 | 28 | MaxWatchers = 256 | ||
| 29 | // MaxWatchersPerClient is the most watches in progress for one client | 29 | // MaxWatchersPerClient is the most watches in progress for one client | ||
| 30 | - | // address (see WatchParams.Client). | 30 | + | // address (see ports.WatchParams.Client). |
| 31 | MaxWatchersPerClient = 16 | 31 | MaxWatchersPerClient = 16 | ||
| 32 | // DefaultRevalidateEvery is how long a watcher with a stored token goes | 32 | // DefaultRevalidateEvery is how long a watcher with a stored token goes | ||
| 33 | // without asking the token store whether the token still exists. | 33 | // without asking the token store whether the token still exists. | ||
| @@ -74,7 +74,7 @@ type bufferedEvent struct { | |||||
| 74 | // NewEvents and lives until Close. | 74 | // NewEvents and lives until Close. | ||
| 75 | type Events struct { | 75 | type Events struct { | ||
| 76 | repos *Repos | 76 | repos *Repos | ||
| 77 | - | auth Revalidator | 77 | + | auth ports.Revalidator |
| 78 | clock ports.Clock | 78 | clock ports.Clock | ||
| 79 | boot string | 79 | boot string | ||
| 80 | size int | 80 | size int | ||
| @@ -92,13 +92,15 @@ type Events struct { | |||||
| 92 | clients map[string]int // watches in progress by client | 92 | clients map[string]int // watches in progress by client | ||
| 93 | } | 93 | } | ||
| 94 | 94 | ||||
| 95 | + | var _ ports.EventService = (*Events)(nil) | |||
| 96 | + | ||||
| 95 | // EventsConfig configures Events. | 97 | // EventsConfig configures Events. | ||
| 96 | type EventsConfig struct { | 98 | type EventsConfig struct { | ||
| 97 | // Size is the number of events remembered; DefaultEventBuffer when not | 99 | // Size is the number of events remembered; DefaultEventBuffer when not | ||
| 98 | // positive. | 100 | // positive. | ||
| 99 | Size int | 101 | Size int | ||
| 100 | // Auth confirms that the token of a watcher still exists. Required. | 102 | // Auth confirms that the token of a watcher still exists. Required. | ||
| 101 | - | Auth Revalidator | 103 | + | Auth ports.Revalidator |
| 102 | // RevalidateEvery is how long the answer of Auth is kept for a watcher; | 104 | // RevalidateEvery is how long the answer of Auth is kept for a watcher; | ||
| 103 | // DefaultRevalidateEvery when zero, and negative to ask for every event. | 105 | // DefaultRevalidateEvery when zero, and negative to ask for every event. | ||
| 104 | RevalidateEvery time.Duration | 106 | RevalidateEvery time.Duration | ||
| @@ -246,40 +248,6 @@ func (e *Events) parseID(id string) (uint64, bool) { | |||||
| 246 | return n, err == nil && n > 0 | 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 | // watch is the state of one Watch call. | 251 | // watch is the state of one Watch call. | ||
| 284 | type watch struct { | 252 | type watch struct { | ||
| 285 | p domain.Principal | 253 | p domain.Principal | ||
| @@ -337,7 +305,7 @@ func (e *Events) parseTopics(ctx context.Context, p domain.Principal, topics []s | |||||
| 337 | // buffered, or was not issued by this run, a gap comes first and the oldest | 305 | // buffered, or was not issued by this run, a gap comes first and the oldest | ||
| 338 | // buffered event follows. A watcher that falls more than the buffer behind | 306 | // buffered event follows. A watcher that falls more than the buffer behind | ||
| 339 | // gets a gap too, and carries on with the oldest buffered event. | 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 | w, err := e.parseTopics(ctx, p, params.Topics) | 309 | w, err := e.parseTopics(ctx, p, params.Topics) | ||
| 342 | if err != nil { | 310 | if err != nil { | ||
| 343 | return err | 311 | return err | ||
| @@ -382,7 +350,7 @@ func (e *Events) Watch(ctx context.Context, p domain.Principal, params WatchPara | |||||
| 382 | log := zerowrap.FromCtx(ctx) | 350 | log := zerowrap.FromCtx(ctx) | ||
| 383 | log.Debug().Strs("topics", params.Topics).Bool("resume", params.ResumeAfter != "").Bool("gap", gap).Msg("watch started") | 351 | log.Debug().Strs("topics", params.Topics).Bool("resume", params.ResumeAfter != "").Bool("gap", gap).Msg("watch started") | ||
| 384 | if gap { | 352 | if gap { | ||
| 385 | - | if err := send(WatchEvent{Gap: true}); err != nil { | 353 | + | if err := send(ports.WatchEvent{Gap: true}); err != nil { |
| 386 | return err | 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 | batch, changed, oldest, lost, closed := e.since(next) | 361 | batch, changed, oldest, lost, closed := e.since(next) | ||
| 394 | if lost { | 362 | if lost { | ||
| 395 | - | if err := send(WatchEvent{Gap: true}); err != nil { | 363 | + | if err := send(ports.WatchEvent{Gap: true}); err != nil { |
| 396 | return err | 364 | return err | ||
| 397 | } | 365 | } | ||
| 398 | next = oldest | 366 | next = oldest | ||
| @@ -482,15 +450,15 @@ func (e *Events) since(next uint64) (batch []bufferedEvent, changed <-chan struc | |||||
| 482 | } | 450 | } | ||
| 483 | 451 | ||||
| 484 | // deliver sends the event if the watcher follows its topic and may see it. | 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 | if err := e.stillAllowed(ctx, w); err != nil { | 454 | if err := e.stillAllowed(ctx, w); err != nil { | ||
| 487 | return err | 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 | switch ev := be.ev.(type) { | 458 | switch ev := be.ev.(type) { | ||
| 491 | case domain.EventGap: | 459 | case domain.EventGap: | ||
| 492 | // The feeder lost events: tell every watcher. | 460 | // The feeder lost events: tell every watcher. | ||
| 493 | - | return send(WatchEvent{Gap: true}) | 461 | + | return send(ports.WatchEvent{Gap: true}) |
| 494 | case domain.RepoDeleted: | 462 | case domain.RepoDeleted: | ||
| 495 | // The repository is gone: use the visibility it had. | 463 | // The repository is gone: use the visibility it had. | ||
| 496 | if !w.wants(ev.Repo) || !canReadAs(w.p, ev.Repo, ev.Visibility) { | 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 | // The exception is a repository that became private: the watchers who could | 491 | // The exception is a repository that became private: the watchers who could | ||
| 524 | // read it before are told once, with its name and its new visibility only, | 492 | // read it before are told once, with its name and its new visibility only, | ||
| 525 | // so that what they show can be removed. | 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 | if !w.wants(name) || !be.known { | 495 | if !w.wants(name) || !be.known { | ||
| 528 | return nil | 496 | return nil | ||
| 529 | } | 497 | } | ||
| @@ -541,7 +509,7 @@ func (e *Events) deliverRepo(ctx context.Context, w *watch, name domain.RepoName | |||||
| 541 | } | 509 | } | ||
| 542 | if !canReadAs(w.p, name, be.vis) { | 510 | if !canReadAs(w.p, name, be.vis) { | ||
| 543 | if up, ok := be.ev.(domain.RepoUpdated); ok && canReadAs(w.p, name, up.Previous) { | 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 | return send(out) | 513 | return send(out) | ||
| 546 | } | 514 | } | ||
| 547 | return nil | 515 | return nil | ||
M internal/app/events_test.go +60 -60
| @@ -17,8 +17,8 @@ import ( | |||||
| 17 | "github.com/stretchr/testify/require" | 17 | "github.com/stretchr/testify/require" | ||
| 18 | 18 | ||||
| 19 | "bnema.dev/ermite/internal/app" | 19 | "bnema.dev/ermite/internal/app" | ||
| 20 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |||
| 21 | "bnema.dev/ermite/internal/domain" | 20 | "bnema.dev/ermite/internal/domain" | ||
| 21 | + | "bnema.dev/ermite/internal/ports" | |||
| 22 | "bnema.dev/ermite/internal/ports/mocks" | 22 | "bnema.dev/ermite/internal/ports/mocks" | ||
| 23 | ) | 23 | ) | ||
| 24 | 24 | ||||
| @@ -28,7 +28,7 @@ type eventRig struct { | |||||
| 28 | meta *mocks.RepoMetaStore | 28 | meta *mocks.RepoMetaStore | ||
| 29 | git *mocks.GitRepos | 29 | git *mocks.GitRepos | ||
| 30 | feed chan domain.Event | 30 | feed chan domain.Event | ||
| 31 | - | auth *appmocks.Revalidator | 31 | + | auth *mocks.Revalidator |
| 32 | revoked sync.Map // token IDs revoked by the test | 32 | revoked sync.Map // token IDs revoked by the test | ||
| 33 | revalidations atomic.Int32 // calls to auth.Revalidate | 33 | revalidations atomic.Int32 // calls to auth.Revalidate | ||
| 34 | events *app.Events | 34 | events *app.Events | ||
| @@ -46,7 +46,7 @@ func newEventRigConfig(t *testing.T, cfg app.EventsConfig) *eventRig { | |||||
| 46 | meta: mocks.NewRepoMetaStore(t), | 46 | meta: mocks.NewRepoMetaStore(t), | ||
| 47 | git: mocks.NewGitRepos(t), | 47 | git: mocks.NewGitRepos(t), | ||
| 48 | feed: make(chan domain.Event, 4096), | 48 | feed: make(chan domain.Event, 4096), | ||
| 49 | - | auth: appmocks.NewRevalidator(t), | 49 | + | auth: mocks.NewRevalidator(t), |
| 50 | } | 50 | } | ||
| 51 | // Tokens are valid until the test revokes them. | 51 | // Tokens are valid until the test revokes them. | ||
| 52 | r.auth.EXPECT().Revalidate(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, p domain.Principal) error { | 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 | // watcher is a running Watch. | 96 | // watcher is a running Watch. | ||
| 97 | type watcher struct { | 97 | type watcher struct { | ||
| 98 | - | got chan app.WatchEvent | 98 | + | got chan ports.WatchEvent |
| 99 | done chan error | 99 | done chan error | ||
| 100 | } | 100 | } | ||
| 101 | 101 | ||||
| 102 | - | func (r *eventRig) watch(ctx context.Context, p domain.Principal, params app.WatchParams) *watcher { | 102 | + | func (r *eventRig) watch(ctx context.Context, p domain.Principal, params ports.WatchParams) *watcher { |
| 103 | - | w := &watcher{got: make(chan app.WatchEvent, 4096), done: make(chan error, 1)} | 103 | + | w := &watcher{got: make(chan ports.WatchEvent, 4096), done: make(chan error, 1)} |
| 104 | go func() { | 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 | w.got <- e | 106 | w.got <- e | ||
| 107 | return nil | 107 | return nil | ||
| 108 | }) | 108 | }) | ||
| @@ -110,7 +110,7 @@ func (r *eventRig) watch(ctx context.Context, p domain.Principal, params app.Wat | |||||
| 110 | return w | 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 | t.Helper() | 114 | t.Helper() | ||
| 115 | synctest.Wait() // everything the event can reach has run | 115 | synctest.Wait() // everything the event can reach has run | ||
| 116 | select { | 116 | select { | ||
| @@ -121,7 +121,7 @@ func (w *watcher) next(t *testing.T) app.WatchEvent { | |||||
| 121 | default: | 121 | default: | ||
| 122 | t.Fatal("no event") | 122 | t.Fatal("no event") | ||
| 123 | } | 123 | } | ||
| 124 | - | return app.WatchEvent{} | 124 | + | return ports.WatchEvent{} |
| 125 | } | 125 | } | ||
| 126 | 126 | ||||
| 127 | // sentinelOID marks the push events that only prove the ones before them were | 127 | // sentinelOID marks the push events that only prove the ones before them were | ||
| @@ -150,10 +150,10 @@ func TestWatchLiveAndFiltered(t *testing.T) { | |||||
| 150 | ctx, cancel := context.WithCancel(context.Background()) | 150 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 151 | defer cancel() | 151 | defer cancel() | ||
| 152 | 152 | ||||
| 153 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | 153 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) |
| 154 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{Topics: []string{"home"}}) | 154 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{Topics: []string{"home"}}) |
| 155 | - | scoped := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "other"), app.WatchParams{}) | 155 | + | scoped := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "other"), ports.WatchParams{}) |
| 156 | - | onlyPriv := r.watch(ctx, domain.Root(), app.WatchParams{Topics: []string{"repo:priv"}}) | 156 | + | onlyPriv := r.watch(ctx, domain.Root(), ports.WatchParams{Topics: []string{"repo:priv"}}) |
| 157 | synctest.Wait() | 157 | synctest.Wait() | ||
| 158 | require.Equal(t, 4, r.events.Watchers()) | 158 | require.Equal(t, 4, r.events.Watchers()) | ||
| 159 | 159 | ||||
| @@ -191,7 +191,7 @@ func TestWatchRechecksAccessPerEvent(t *testing.T) { | |||||
| 191 | }) | 191 | }) | ||
| 192 | ctx, cancel := context.WithCancel(context.Background()) | 192 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 193 | defer cancel() | 193 | defer cancel() | ||
| 194 | - | w := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | 194 | + | w := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) |
| 195 | synctest.Wait() | 195 | synctest.Wait() | ||
| 196 | require.Equal(t, 1, r.events.Watchers()) | 196 | require.Equal(t, 1, r.events.Watchers()) | ||
| 197 | 197 | ||||
| @@ -217,7 +217,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||||
| 217 | ctx, cancel := context.WithCancel(context.Background()) | 217 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 218 | t.Cleanup(cancel) | 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 | synctest.Wait() | 221 | synctest.Wait() | ||
| 222 | require.Equal(t, 1, r.events.Watchers()) | 222 | require.Equal(t, 1, r.events.Watchers()) | ||
| 223 | // One at a time: this watcher must not fall behind the small ring. | 223 | // One at a time: this watcher must not fall behind the small ring. | ||
| @@ -235,7 +235,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||||
| 235 | r, _, ctx, ids := setup(t) | 235 | r, _, ctx, ids := setup(t) | ||
| 236 | // 20 events were taken, the buffer holds the last 8: ids[12] is the | 236 | // 20 events were taken, the buffer holds the last 8: ids[12] is the | ||
| 237 | // oldest still present; ids[0] is long gone. | 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 | gap := w.next(t) | 239 | gap := w.next(t) | ||
| 240 | assert.True(t, gap.Gap) | 240 | assert.True(t, gap.Gap) | ||
| 241 | assert.Empty(t, gap.ID) | 241 | assert.Empty(t, gap.ID) | ||
| @@ -250,7 +250,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||||
| 250 | synctest.Test(t, func(t *testing.T) { | 250 | synctest.Test(t, func(t *testing.T) { | ||
| 251 | r, _, ctx, _ := setup(t) | 251 | r, _, ctx, _ := setup(t) | ||
| 252 | for _, id := range []string{"nonsense", "zz-1", "-", "0-0"} { | 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 | assert.True(t, w.next(t).Gap, id) | 254 | assert.True(t, w.next(t).Gap, id) | ||
| 255 | } | 255 | } | ||
| 256 | }) | 256 | }) | ||
| @@ -260,7 +260,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||||
| 260 | t.Parallel() | 260 | t.Parallel() | ||
| 261 | synctest.Test(t, func(t *testing.T) { | 261 | synctest.Test(t, func(t *testing.T) { | ||
| 262 | r, _, ctx, _ := setup(t) | 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 | assert.True(t, w.next(t).Gap) | 264 | assert.True(t, w.next(t).Gap) | ||
| 265 | }) | 265 | }) | ||
| 266 | }) | 266 | }) | ||
| @@ -269,7 +269,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||||
| 269 | t.Parallel() | 269 | t.Parallel() | ||
| 270 | synctest.Test(t, func(t *testing.T) { | 270 | synctest.Test(t, func(t *testing.T) { | ||
| 271 | r, n, ctx, ids := setup(t) | 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 | for _, want := range ids[17:] { | 273 | for _, want := range ids[17:] { | ||
| 274 | e := w.next(t) | 274 | e := w.next(t) | ||
| 275 | assert.False(t, e.Gap) | 275 | assert.False(t, e.Gap) | ||
| @@ -287,7 +287,7 @@ func TestWatchResumeAndGap(t *testing.T) { | |||||
| 287 | t.Parallel() | 287 | t.Parallel() | ||
| 288 | synctest.Test(t, func(t *testing.T) { | 288 | synctest.Test(t, func(t *testing.T) { | ||
| 289 | r, n, ctx, ids := setup(t) | 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 | r.push(n, 99) | 291 | r.push(n, 99) | ||
| 292 | e := w.next(t) | 292 | e := w.next(t) | ||
| 293 | assert.False(t, e.Gap) | 293 | assert.False(t, e.Gap) | ||
| @@ -302,7 +302,7 @@ func TestWatchTopicErrors(t *testing.T) { | |||||
| 302 | r.repo("pub", domain.VisibilityPublic) | 302 | r.repo("pub", domain.VisibilityPublic) | ||
| 303 | r.repo("priv", domain.VisibilityPrivate) | 303 | r.repo("priv", domain.VisibilityPrivate) | ||
| 304 | r.meta.EXPECT().Get(mock.Anything, name(t, "gone")).Return(domain.Repo{}, domain.ErrNotFound).Maybe() | 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 | ctx := context.Background() | 306 | ctx := context.Background() | ||
| 307 | 307 | ||||
| 308 | for topic, want := range map[string]error{ | 308 | for topic, want := range map[string]error{ | ||
| @@ -313,7 +313,7 @@ func TestWatchTopicErrors(t *testing.T) { | |||||
| 313 | "repo:priv": domain.ErrNotFound, // hidden from anonymous | 313 | "repo:priv": domain.ErrNotFound, // hidden from anonymous | ||
| 314 | "repo:pub:foo": domain.ErrInvalidName, | 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 | assert.ErrorIs(t, err, want, topic) | 317 | assert.ErrorIs(t, err, want, topic) | ||
| 318 | } | 318 | } | ||
| 319 | } | 319 | } | ||
| @@ -325,7 +325,7 @@ func TestWatchEndsCleanly(t *testing.T) { | |||||
| 325 | synctest.Test(t, func(t *testing.T) { | 325 | synctest.Test(t, func(t *testing.T) { | ||
| 326 | r := newEventRig(t, 0) | 326 | r := newEventRig(t, 0) | ||
| 327 | ctx, cancel := context.WithCancel(context.Background()) | 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 | synctest.Wait() | 329 | synctest.Wait() | ||
| 330 | require.Equal(t, 1, r.events.Watchers()) | 330 | require.Equal(t, 1, r.events.Watchers()) | ||
| 331 | cancel() | 331 | cancel() | ||
| @@ -344,7 +344,7 @@ func TestWatchEndsCleanly(t *testing.T) { | |||||
| 344 | t.Parallel() | 344 | t.Parallel() | ||
| 345 | synctest.Test(t, func(t *testing.T) { | 345 | synctest.Test(t, func(t *testing.T) { | ||
| 346 | r := newEventRig(t, 0) | 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 | synctest.Wait() | 348 | synctest.Wait() | ||
| 349 | require.Equal(t, 1, r.events.Watchers()) | 349 | require.Equal(t, 1, r.events.Watchers()) | ||
| 350 | r.events.Close(context.Background()) | 350 | r.events.Close(context.Background()) | ||
| @@ -367,7 +367,7 @@ func TestWatchEndsCleanly(t *testing.T) { | |||||
| 367 | boom := errors.New("client went away") | 367 | boom := errors.New("client went away") | ||
| 368 | done := make(chan error, 1) | 368 | done := make(chan error, 1) | ||
| 369 | go func() { | 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 | synctest.Wait() | 372 | synctest.Wait() | ||
| 373 | require.Equal(t, 1, r.events.Watchers()) | 373 | require.Equal(t, 1, r.events.Watchers()) | ||
| @@ -386,12 +386,12 @@ func TestWatchSlowWatcherGetsAGap(t *testing.T) { | |||||
| 386 | 386 | ||||
| 387 | release := make(chan struct{}) | 387 | release := make(chan struct{}) | ||
| 388 | var mu sync.Mutex | 388 | var mu sync.Mutex | ||
| 389 | - | var got []app.WatchEvent | 389 | + | var got []ports.WatchEvent |
| 390 | done := make(chan error, 1) | 390 | done := make(chan error, 1) | ||
| 391 | blocked := make(chan struct{}) | 391 | blocked := make(chan struct{}) | ||
| 392 | first := true | 392 | first := true | ||
| 393 | go func() { | 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 | if first { // block on the first event while the ring turns over | 395 | if first { // block on the first event while the ring turns over | ||
| 396 | first = false | 396 | first = false | ||
| 397 | close(blocked) | 397 | close(blocked) | ||
| @@ -405,7 +405,7 @@ func TestWatchSlowWatcherGetsAGap(t *testing.T) { | |||||
| 405 | }() | 405 | }() | ||
| 406 | // A second, fast watcher tells when the use case has taken every event: | 406 | // A second, fast watcher tells when the use case has taken every event: | ||
| 407 | // it receives them in order. | 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 | synctest.Wait() | 409 | synctest.Wait() | ||
| 410 | require.Equal(t, 2, r.events.Watchers()) | 410 | require.Equal(t, 2, r.events.Watchers()) | ||
| 411 | r.push(n, 0) | 411 | r.push(n, 0) | ||
| @@ -444,8 +444,8 @@ func TestEventsRepoPayloads(t *testing.T) { | |||||
| 444 | priv := r.repo("priv", domain.VisibilityPrivate) | 444 | priv := r.repo("priv", domain.VisibilityPrivate) | ||
| 445 | ctx, cancel := context.WithCancel(context.Background()) | 445 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 446 | defer cancel() | 446 | defer cancel() | ||
| 447 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | 447 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) |
| 448 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | 448 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) |
| 449 | synctest.Wait() | 449 | synctest.Wait() | ||
| 450 | require.Equal(t, 2, r.events.Watchers()) | 450 | require.Equal(t, 2, r.events.Watchers()) | ||
| 451 | 451 | ||||
| @@ -493,7 +493,7 @@ func TestWatchEndsWhenTheTokenIsRevoked(t *testing.T) { | |||||
| 493 | ctx, cancel := context.WithCancel(context.Background()) | 493 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 494 | defer cancel() | 494 | defer cancel() | ||
| 495 | 495 | ||||
| 496 | - | w := r.watch(ctx, p, app.WatchParams{}) | 496 | + | w := r.watch(ctx, p, ports.WatchParams{}) |
| 497 | synctest.Wait() | 497 | synctest.Wait() | ||
| 498 | require.Equal(t, 1, r.events.Watchers()) | 498 | require.Equal(t, 1, r.events.Watchers()) | ||
| 499 | r.push(pub, 1) | 499 | r.push(pub, 1) | ||
| @@ -523,7 +523,7 @@ func TestWatchEndsWhenTheTokenExpires(t *testing.T) { | |||||
| 523 | pub := r.repo("pub", domain.VisibilityPublic) | 523 | pub := r.repo("pub", domain.VisibilityPublic) | ||
| 524 | // The rig's clock stands at now: this token expired at now. | 524 | // The rig's clock stands at now: this token expired at now. | ||
| 525 | p := tokenWith("tok", now) | 525 | p := tokenWith("tok", now) | ||
| 526 | - | w := r.watch(context.Background(), p, app.WatchParams{}) | 526 | + | w := r.watch(context.Background(), p, ports.WatchParams{}) |
| 527 | r.push(pub, 1) // whether or not the watch had started, it ends unauthenticated | 527 | r.push(pub, 1) // whether or not the watch had started, it ends unauthenticated | ||
| 528 | synctest.Wait() | 528 | synctest.Wait() | ||
| 529 | select { | 529 | select { | ||
| @@ -542,7 +542,7 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||||
| 542 | t.Parallel() | 542 | t.Parallel() | ||
| 543 | synctest.Test(t, func(t *testing.T) { | 543 | synctest.Test(t, func(t *testing.T) { | ||
| 544 | r := newEventRigConfig(t, app.EventsConfig{}) // the production default interval | 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 | synctest.Wait() | 546 | synctest.Wait() | ||
| 547 | require.Equal(t, 1, r.events.Watchers()) | 547 | require.Equal(t, 1, r.events.Watchers()) | ||
| 548 | r.revoked.Store("tok", true) | 548 | r.revoked.Store("tok", true) | ||
| @@ -569,7 +569,7 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||||
| 569 | synctest.Test(t, func(t *testing.T) { | 569 | synctest.Test(t, func(t *testing.T) { | ||
| 570 | r := newEventRigConfig(t, app.EventsConfig{RevalidateEvery: time.Hour}) | 570 | r := newEventRigConfig(t, app.EventsConfig{RevalidateEvery: time.Hour}) | ||
| 571 | pub := r.repo("pub", domain.VisibilityPublic) | 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 | synctest.Wait() | 573 | synctest.Wait() | ||
| 574 | require.Equal(t, 1, r.events.Watchers()) | 574 | require.Equal(t, 1, r.events.Watchers()) | ||
| 575 | for i := range 20 { | 575 | for i := range 20 { | ||
| @@ -592,8 +592,8 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||||
| 592 | synctest.Test(t, func(t *testing.T) { | 592 | synctest.Test(t, func(t *testing.T) { | ||
| 593 | r := newEventRigConfig(t, app.EventsConfig{RevalidateEvery: -1}) | 593 | r := newEventRigConfig(t, app.EventsConfig{RevalidateEvery: -1}) | ||
| 594 | pub := r.repo("pub", domain.VisibilityPublic) | 594 | pub := r.repo("pub", domain.VisibilityPublic) | ||
| 595 | - | a := r.watch(context.Background(), domain.Anonymous(), app.WatchParams{}) | 595 | + | a := r.watch(context.Background(), domain.Anonymous(), ports.WatchParams{}) |
| 596 | - | b := r.watch(context.Background(), domain.Root(), app.WatchParams{}) | 596 | + | b := r.watch(context.Background(), domain.Root(), ports.WatchParams{}) |
| 597 | synctest.Wait() | 597 | synctest.Wait() | ||
| 598 | require.Equal(t, 2, r.events.Watchers()) | 598 | require.Equal(t, 2, r.events.Watchers()) | ||
| 599 | r.push(pub, 1) | 599 | r.push(pub, 1) | ||
| @@ -606,7 +606,7 @@ func TestWatchRevalidatesIdleWatchersAndCachesTheAnswer(t *testing.T) { | |||||
| 606 | 606 | ||||
| 607 | func TestWatchLimits(t *testing.T) { | 607 | func TestWatchLimits(t *testing.T) { | ||
| 608 | t.Parallel() | 608 | t.Parallel() | ||
| 609 | - | noop := func(app.WatchEvent) error { return nil } | 609 | + | noop := func(ports.WatchEvent) error { return nil } |
| 610 | 610 | ||||
| 611 | t.Run("too many topics", func(t *testing.T) { | 611 | t.Run("too many topics", func(t *testing.T) { | ||
| 612 | t.Parallel() | 612 | t.Parallel() | ||
| @@ -619,8 +619,8 @@ func TestWatchLimits(t *testing.T) { | |||||
| 619 | } | 619 | } | ||
| 620 | ctx, cancel := context.WithCancel(context.Background()) | 620 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 621 | cancel() // returns at once once the topics are accepted | 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)) | 622 | + | assert.NoError(t, r.events.Watch(ctx, domain.Root(), ports.WatchParams{Topics: ok}, noop)) |
| 623 | - | err := r.events.Watch(context.Background(), domain.Root(), app.WatchParams{Topics: append(ok, "home")}, noop) | 623 | + | err := r.events.Watch(context.Background(), domain.Root(), ports.WatchParams{Topics: append(ok, "home")}, noop) |
| 624 | assert.ErrorIs(t, err, domain.ErrInvalid) | 624 | assert.ErrorIs(t, err, domain.ErrInvalid) | ||
| 625 | }) | 625 | }) | ||
| 626 | }) | 626 | }) | ||
| @@ -632,11 +632,11 @@ func TestWatchLimits(t *testing.T) { | |||||
| 632 | ctx, cancel := context.WithCancel(context.Background()) | 632 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 633 | defer cancel() | 633 | defer cancel() | ||
| 634 | for range app.MaxWatchers { | 634 | for range app.MaxWatchers { | ||
| 635 | - | r.watch(ctx, domain.Root(), app.WatchParams{}) | 635 | + | r.watch(ctx, domain.Root(), ports.WatchParams{}) |
| 636 | } | 636 | } | ||
| 637 | synctest.Wait() | 637 | synctest.Wait() | ||
| 638 | require.Equal(t, app.MaxWatchers, r.events.Watchers()) | 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 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | 640 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | ||
| 641 | assert.Equal(t, app.MaxWatchers, r.events.Watchers(), "a refused watch is not counted") | 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 | require.Equal(t, 0, r.events.Watchers()) | 645 | require.Equal(t, 0, r.events.Watchers()) | ||
| 646 | again, stop := context.WithCancel(context.Background()) | 646 | again, stop := context.WithCancel(context.Background()) | ||
| 647 | stop() | 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 | ctx, cancel := context.WithCancel(context.Background()) | 656 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 657 | defer cancel() | 657 | defer cancel() | ||
| 658 | for range app.MaxWatchersPerClient { | 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 | synctest.Wait() | 661 | synctest.Wait() | ||
| 662 | require.Equal(t, app.MaxWatchersPerClient, r.events.Watchers()) | 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 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | 665 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | ||
| 666 | 666 | ||||
| 667 | // Another client, and callers in process, are not affected. | 667 | // Another client, and callers in process, are not affected. | ||
| 668 | - | r.watch(ctx, domain.Root(), app.WatchParams{Client: "198.51.100.2"}) | 668 | + | r.watch(ctx, domain.Root(), ports.WatchParams{Client: "198.51.100.2"}) |
| 669 | - | r.watch(ctx, domain.Root(), app.WatchParams{}) | 669 | + | r.watch(ctx, domain.Root(), ports.WatchParams{}) |
| 670 | synctest.Wait() | 670 | synctest.Wait() | ||
| 671 | require.Equal(t, app.MaxWatchersPerClient+2, r.events.Watchers()) | 671 | require.Equal(t, app.MaxWatchersPerClient+2, r.events.Watchers()) | ||
| 672 | 672 | ||||
| @@ -675,7 +675,7 @@ func TestWatchLimits(t *testing.T) { | |||||
| 675 | require.Equal(t, 0, r.events.Watchers()) | 675 | require.Equal(t, 0, r.events.Watchers()) | ||
| 676 | again, stop := context.WithCancel(context.Background()) | 676 | again, stop := context.WithCancel(context.Background()) | ||
| 677 | stop() | 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 | defer cancel() | 712 | defer cancel() | ||
| 713 | r := newEventRig(t, 0) | 713 | r := newEventRig(t, 0) | ||
| 714 | l, n := r.liveRepo("secret", domain.VisibilityPrivate, now) | 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 | synctest.Wait() | 716 | synctest.Wait() | ||
| 717 | require.Equal(t, 1, r.events.Watchers()) | 717 | require.Equal(t, 1, r.events.Watchers()) | ||
| 718 | r.push(n, 1) | 718 | r.push(n, 1) | ||
| @@ -728,7 +728,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||||
| 728 | // An anonymous caller that resumes with an id nobody issued gets what | 728 | // An anonymous caller that resumes with an id nobody issued gets what | ||
| 729 | // is buffered, filtered: the public update and the public push, not the | 729 | // is buffered, filtered: the public update and the public push, not the | ||
| 730 | // pushes of the private era. | 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 | assert.True(t, anon.next(t).Gap) | 732 | assert.True(t, anon.next(t).Gap) | ||
| 733 | upd := anon.next(t) | 733 | upd := anon.next(t) | ||
| 734 | require.IsType(t, domain.RepoUpdated{}, upd.Event) | 734 | require.IsType(t, domain.RepoUpdated{}, upd.Event) | ||
| @@ -747,7 +747,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||||
| 747 | r := newEventRig(t, 0) | 747 | r := newEventRig(t, 0) | ||
| 748 | first := now.Add(-time.Hour) | 748 | first := now.Add(-time.Hour) | ||
| 749 | l, n := r.liveRepo("again", domain.VisibilityPublic, first) | 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 | synctest.Wait() | 751 | synctest.Wait() | ||
| 752 | require.Equal(t, 1, r.events.Watchers()) | 752 | require.Equal(t, 1, r.events.Watchers()) | ||
| 753 | r.push(n, 1) | 753 | r.push(n, 1) | ||
| @@ -757,7 +757,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||||
| 757 | r.push(n, 2) | 757 | r.push(n, 2) | ||
| 758 | root.next(t) | 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 | assert.True(t, anon.next(t).Gap) | 761 | assert.True(t, anon.next(t).Gap) | ||
| 762 | e := anon.next(t) | 762 | e := anon.next(t) | ||
| 763 | require.IsType(t, domain.PushEvent{}, e.Event) | 763 | require.IsType(t, domain.PushEvent{}, e.Event) | ||
| @@ -773,10 +773,10 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||||
| 773 | defer cancel() | 773 | defer cancel() | ||
| 774 | r := newEventRig(t, 0) | 774 | r := newEventRig(t, 0) | ||
| 775 | l, n := r.liveRepo("hide", domain.VisibilityPublic, now) | 775 | l, n := r.liveRepo("hide", domain.VisibilityPublic, now) | ||
| 776 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | 776 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) |
| 777 | - | reader := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "hide"), app.WatchParams{}) | 777 | + | reader := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "hide"), ports.WatchParams{}) |
| 778 | - | other := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "elsewhere"), app.WatchParams{}) | 778 | + | other := r.watch(ctx, tokenPrincipal(domain.ScopeRepoRead, "elsewhere"), ports.WatchParams{}) |
| 779 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | 779 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) |
| 780 | synctest.Wait() | 780 | synctest.Wait() | ||
| 781 | require.Equal(t, 4, r.events.Watchers()) | 781 | require.Equal(t, 4, r.events.Watchers()) | ||
| 782 | 782 | ||||
| @@ -809,7 +809,7 @@ func TestEventsKeepTheVisibilityOfTheirTime(t *testing.T) { | |||||
| 809 | defer cancel() | 809 | defer cancel() | ||
| 810 | r := newEventRig(t, 0) | 810 | r := newEventRig(t, 0) | ||
| 811 | _, n := r.liveRepo("closed", domain.VisibilityPrivate, now) | 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 | synctest.Wait() | 813 | synctest.Wait() | ||
| 814 | require.Equal(t, 1, r.events.Watchers()) | 814 | require.Equal(t, 1, r.events.Watchers()) | ||
| 815 | r.feed <- domain.RepoUpdated{Repo: n, At: now, Visibility: domain.VisibilityPrivate, Previous: domain.VisibilityPrivate, CreatedAt: now} | 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 | defer cancel() | 842 | defer cancel() | ||
| 843 | r := newEventRig(t, 0) | 843 | r := newEventRig(t, 0) | ||
| 844 | l, n := r.liveRepo("secret", domain.VisibilityPrivate, now) | 844 | l, n := r.liveRepo("secret", domain.VisibilityPrivate, now) | ||
| 845 | - | anon := r.watch(ctx, domain.Anonymous(), app.WatchParams{}) | 845 | + | anon := r.watch(ctx, domain.Anonymous(), ports.WatchParams{}) |
| 846 | - | root := r.watch(ctx, domain.Root(), app.WatchParams{}) | 846 | + | root := r.watch(ctx, domain.Root(), ports.WatchParams{}) |
| 847 | synctest.Wait() | 847 | synctest.Wait() | ||
| 848 | require.Equal(t, 2, r.events.Watchers()) | 848 | require.Equal(t, 2, r.events.Watchers()) | ||
| 849 | 849 | ||||
| @@ -859,7 +859,7 @@ func TestPushEventsKeepTheirSnapshot(t *testing.T) { | |||||
| 859 | 859 | ||||
| 860 | anon.quiet(t, r, r.repo("open", domain.VisibilityPublic)) | 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 | assert.True(t, late.next(t).Gap) | 863 | assert.True(t, late.next(t).Gap) | ||
| 864 | late.quiet(t, r, r.repo("open2", domain.VisibilityPublic)) | 864 | late.quiet(t, r, r.repo("open2", domain.VisibilityPublic)) | ||
| 865 | }) | 865 | }) | ||
| @@ -873,7 +873,7 @@ func TestPushEventsKeepTheirSnapshot(t *testing.T) { | |||||
| 873 | defer cancel() | 873 | defer cancel() | ||
| 874 | r := newEventRig(t, 0) | 874 | r := newEventRig(t, 0) | ||
| 875 | n := r.repo("ghost", domain.VisibilityPublic) | 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 | synctest.Wait() | 877 | synctest.Wait() | ||
| 878 | require.Equal(t, 1, r.events.Watchers()) | 878 | require.Equal(t, 1, r.events.Watchers()) | ||
| 879 | r.feed <- domain.PushEvent{Repo: n, Visibility: domain.VisibilityPublic, At: now} | 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 | wg sync.WaitGroup | 38 | wg sync.WaitGroup | ||
| 39 | } | 39 | } | ||
| 40 | 40 | ||||
| 41 | + | var _ ports.MaintenanceScheduler = (*Maintainer)(nil) | |||
| 42 | + | ||||
| 41 | type maintEntry struct { | 43 | type maintEntry struct { | ||
| 42 | timer *time.Timer // pending run, nil while running or idle | 44 | timer *time.Timer // pending run, nil while running or idle | ||
| 43 | running bool | 45 | running bool | ||
M internal/app/mergerequests.go +29 -102
| @@ -47,12 +47,14 @@ type MergeRequests struct { | |||||
| 47 | committer domain.Identity | 47 | committer domain.Identity | ||
| 48 | bus ports.EventBus | 48 | bus ports.EventBus | ||
| 49 | clock ports.Clock | 49 | clock ports.Clock | ||
| 50 | - | maint MaintenanceScheduler | 50 | + | maint ports.MaintenanceScheduler |
| 51 | 51 | ||||
| 52 | mu sync.Mutex | 52 | mu sync.Mutex | ||
| 53 | locks map[domain.RepoName]chan struct{} | 53 | locks map[domain.RepoName]chan struct{} | ||
| 54 | } | 54 | } | ||
| 55 | 55 | ||||
| 56 | + | var _ ports.MergeRequestService = (*MergeRequests)(nil) | |||
| 57 | + | ||||
| 56 | // MergeRequestsConfig holds what the merge request use cases need. Every field | 58 | // MergeRequestsConfig holds what the merge request use cases need. Every field | ||
| 57 | // is required. | 59 | // is required. | ||
| 58 | type MergeRequestsConfig struct { | 60 | type MergeRequestsConfig struct { | ||
| @@ -68,7 +70,7 @@ type MergeRequestsConfig struct { | |||||
| 68 | Bus ports.EventBus | 70 | Bus ports.EventBus | ||
| 69 | Clock ports.Clock | 71 | Clock ports.Clock | ||
| 70 | // Maint queues the maintenance that follows a merge, as it does a push. | 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 | // NewMergeRequests builds the merge request use cases. | 76 | // NewMergeRequests builds the merge request use cases. | ||
| @@ -161,20 +163,12 @@ func (m *MergeRequests) branchOrZero(ctx context.Context, repo domain.RepoName, | |||||
| 161 | return id, err | 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 | // Create opens a merge request and publishes MergeRequestOpened. The principal | 166 | // Create opens a merge request and publishes MergeRequestOpened. The principal | ||
| 173 | // needs mr:write. A request that breaks a rule of ADR 0017 (the texts, a | 167 | // needs mr:write. A request that breaks a rule of ADR 0017 (the texts, a | ||
| 174 | // branch that does not exist, source and target the same) is rejected whole | 168 | // branch that does not exist, source and target the same) is rejected whole | ||
| 175 | // with an *domain.InvalidFieldsError naming the fields. An open request with | 169 | // with an *domain.InvalidFieldsError naming the fields. An open request with | ||
| 176 | // the same source and target gives domain.ErrAlreadyExists. | 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 | repo, err := m.writable(ctx, p, name, domain.ScopeMRWrite) | 172 | repo, err := m.writable(ctx, p, name, domain.ScopeMRWrite) | ||
| 179 | if err != nil { | 173 | if err != nil { | ||
| 180 | return domain.MergeRequest{}, err | 174 | return domain.MergeRequest{}, err | ||
| @@ -239,7 +233,7 @@ func (m *MergeRequests) Create(ctx context.Context, p domain.Principal, name dom | |||||
| 239 | // Only a branch that does not exist is a violation. Any other failure to read | 233 | // Only a branch that does not exist is a violation. Any other failure to read | ||
| 240 | // Git is returned as an error, so that it is logged and masked, not shown in | 234 | // Git is returned as an error, so that it is logged and masked, not shown in | ||
| 241 | // the field violations. | 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 | source, target = params.Source, params.Target | 237 | source, target = params.Source, params.Target | ||
| 244 | if source == "" { | 238 | if source == "" { | ||
| 245 | v.Add("source_branch", "is required") | 239 | v.Add("source_branch", "is required") | ||
| @@ -279,44 +273,27 @@ func (m *MergeRequests) checkBranches(ctx context.Context, name domain.RepoName, | |||||
| 279 | return source, target, nil | 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 | // List returns a page of the merge requests of a repository, highest number | 276 | // List returns a page of the merge requests of a repository, highest number | ||
| 300 | // first. The open ones carry the head of their source branch. The page token | 277 | // first. The open ones carry the head of their source branch. The page token | ||
| 301 | // names the last number of the previous page, so requests created between two | 278 | // names the last number of the previous page, so requests created between two | ||
| 302 | // pages never shift the others. | 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 | size, err := pageSize(params.PageSize) | 281 | size, err := pageSize(params.PageSize) | ||
| 305 | if err != nil { | 282 | if err != nil { | ||
| 306 | - | return MergeRequestPage{}, err | 283 | + | return ports.MergeRequestPage{}, err |
| 307 | } | 284 | } | ||
| 308 | after, err := decodeMRToken(params.PageToken) | 285 | after, err := decodeMRToken(params.PageToken) | ||
| 309 | if err != nil { | 286 | if err != nil { | ||
| 310 | - | return MergeRequestPage{}, err | 287 | + | return ports.MergeRequestPage{}, err |
| 311 | } | 288 | } | ||
| 312 | if _, err := m.readable(ctx, p, name); err != nil { | 289 | if _, err := m.readable(ctx, p, name); err != nil { | ||
| 313 | - | return MergeRequestPage{}, err | 290 | + | return ports.MergeRequestPage{}, err |
| 314 | } | 291 | } | ||
| 315 | all, err := m.store.List(ctx, name) | 292 | all, err := m.store.List(ctx, name) | ||
| 316 | if err != nil { | 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 | page.MergeRequests, page.NextPageToken = pageAfter(all, size, | 297 | page.MergeRequests, page.NextPageToken = pageAfter(all, size, | ||
| 321 | func(mr domain.MergeRequest) bool { | 298 | func(mr domain.MergeRequest) bool { | ||
| 322 | return (params.State == "" || mr.State == params.State) && (after == 0 || mr.Number < after) | 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 | encodeMRToken) | 301 | encodeMRToken) | ||
| 325 | for i, mr := range page.MergeRequests { | 302 | for i, mr := range page.MergeRequests { | ||
| 326 | if page.MergeRequests[i], err = m.withHead(ctx, mr); err != nil { | 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 | return page, nil | 307 | return page, nil | ||
| @@ -361,27 +338,6 @@ func (m *MergeRequests) get(ctx context.Context, p domain.Principal, name domain | |||||
| 361 | return repo, mr, nil | 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 | // Get returns a merge request with its commits, its diff, its comments and the | 341 | // Get returns a merge request with its commits, its diff, its comments and the | ||
| 386 | // read position. The diff compares the merge base of the target and the head | 342 | // read position. The diff compares the merge base of the target and the head | ||
| 387 | // with the head ("target...head"), within domain.DefaultDiffLimits. With | 343 | // with the head ("target...head"), within domain.DefaultDiffLimits. With | ||
| @@ -390,25 +346,25 @@ type MergeRequestDetail struct { | |||||
| 390 | // still exists; when none was recorded the diff is the default one, and when | 346 | // still exists; when none was recorded the diff is the default one, and when | ||
| 391 | // the recorded commit is gone too, with LastReadLost set. A merged or closed | 347 | // the recorded commit is gone too, with LastReadLost set. A merged or closed | ||
| 392 | // request keeps the head and the base it had. | 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 | _, mr, err := m.get(ctx, p, name, number) | 350 | _, mr, err := m.get(ctx, p, name, number) | ||
| 395 | if err != nil { | 351 | if err != nil { | ||
| 396 | - | return MergeRequestDetail{}, err | 352 | + | return ports.MergeRequestDetail{}, err |
| 397 | } | 353 | } | ||
| 398 | if mr, err = m.withHead(ctx, mr); err != nil { | 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 | if d.Comments, err = m.store.ListComments(ctx, name, number); err != nil { | 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 | if d.LastReadID, err = m.store.GetRead(ctx, name, number); err != nil { | 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 | exclude, base, err := m.rangeOf(ctx, mr) | 365 | exclude, base, err := m.rangeOf(ctx, mr) | ||
| 410 | if err != nil { | 366 | if err != nil { | ||
| 411 | - | return MergeRequestDetail{}, err | 367 | + | return ports.MergeRequestDetail{}, err |
| 412 | } | 368 | } | ||
| 413 | head := mr.HeadID | 369 | head := mr.HeadID | ||
| 414 | if head.IsZero() { | 370 | if head.IsZero() { | ||
| @@ -419,18 +375,18 @@ func (m *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain | |||||
| 419 | // source branch; once it is deleted, gc may prune them. | 375 | // source branch; once it is deleted, gc may prune them. | ||
| 420 | switch ok, err := m.git.HasCommit(ctx, name, head); { | 376 | switch ok, err := m.git.HasCommit(ctx, name, head); { | ||
| 421 | case err != nil: | 377 | case err != nil: | ||
| 422 | - | return MergeRequestDetail{}, err | 378 | + | return ports.MergeRequestDetail{}, err |
| 423 | case !ok: | 379 | case !ok: | ||
| 424 | return d, nil // the reviewed commits are gone: no commits, no diff | 380 | return d, nil // the reviewed commits are gone: no commits, no diff | ||
| 425 | } | 381 | } | ||
| 426 | } | 382 | } | ||
| 427 | if d.Commits, d.CommitsTruncated, err = m.git.ListRange(ctx, name, exclude, head, MaxMergeRequestCommits); err != nil { | 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 | if sinceLastRead && !d.LastReadID.IsZero() { | 386 | if sinceLastRead && !d.LastReadID.IsZero() { | ||
| 431 | switch ok, err := m.git.HasCommit(ctx, name, d.LastReadID); { | 387 | switch ok, err := m.git.HasCommit(ctx, name, d.LastReadID); { | ||
| 432 | case err != nil: | 388 | case err != nil: | ||
| 433 | - | return MergeRequestDetail{}, err | 389 | + | return ports.MergeRequestDetail{}, err |
| 434 | case ok: | 390 | case ok: | ||
| 435 | base = d.LastReadID | 391 | base = d.LastReadID | ||
| 436 | default: | 392 | default: | ||
| @@ -442,7 +398,7 @@ func (m *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain | |||||
| 442 | } | 398 | } | ||
| 443 | d.DiffBaseID = base | 399 | d.DiffBaseID = base | ||
| 444 | if d.Stats, d.Diff, err = m.git.DiffCommits(ctx, name, base, head, domain.DefaultDiffLimits()); err != nil { | 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 | return d, nil | 403 | return d, nil | ||
| 448 | } | 404 | } | ||
| @@ -470,23 +426,13 @@ func (m *MergeRequests) rangeOf(ctx context.Context, mr domain.MergeRequest) (ex | |||||
| 470 | return tip, base, err | 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 | // AddComment adds a comment and publishes CommentAdded. The principal needs | 429 | // AddComment adds a comment and publishes CommentAdded. The principal needs | ||
| 484 | // mr:write. The text must follow the rules of ADR 0017 and not be blank; a | 430 | // mr:write. The text must follow the rules of ADR 0017 and not be blank; a | ||
| 485 | // comment on a line must name a line of the current diff of the request (see | 431 | // comment on a line must name a line of the current diff of the request (see | ||
| 486 | // domain.Diff.HasLine), else the call fails with domain.ErrInvalid. A request | 432 | // domain.Diff.HasLine), else the call fails with domain.ErrInvalid. A request | ||
| 487 | // that is not open gives domain.ErrPreconditionFailed, and one that already | 433 | // that is not open gives domain.ErrPreconditionFailed, and one that already | ||
| 488 | // holds MaxCommentsPerMergeRequest comments domain.ErrResourceExhausted. | 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 | repo, err := m.writable(ctx, p, name, domain.ScopeMRWrite) | 436 | repo, err := m.writable(ctx, p, name, domain.ScopeMRWrite) | ||
| 491 | if err != nil { | 437 | if err != nil { | ||
| 492 | return domain.Comment{}, err | 438 | return domain.Comment{}, err | ||
| @@ -567,7 +513,7 @@ func (m *MergeRequests) AddComment(ctx context.Context, p domain.Principal, name | |||||
| 567 | 513 | ||||
| 568 | // checkLine verifies that a comment designates a line of the current diff of | 514 | // checkLine verifies that a comment designates a line of the current diff of | ||
| 569 | // the request. | 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 | var v domain.Violations | 517 | var v domain.Violations | ||
| 572 | _, base, err := m.rangeOf(ctx, mr) | 518 | _, base, err := m.rangeOf(ctx, mr) | ||
| 573 | if err != nil { | 519 | if err != nil { | ||
| @@ -706,25 +652,6 @@ func (m *MergeRequests) MarkRead(ctx context.Context, p domain.Principal, name d | |||||
| 706 | return head, nil | 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 | // Merge merges an open merge request, publishes MergeRequestMerged then a | 655 | // Merge merges an open merge request, publishes MergeRequestMerged then a | ||
| 729 | // PushEvent for the target branch, and returns the merged request. The | 656 | // PushEvent for the target branch, and returns the merged request. The | ||
| 730 | // principal needs mr:merge. Merges of one repository run one at a time. | 657 | // principal needs mr:merge. Merges of one repository run one at a time. | ||
| @@ -748,12 +675,12 @@ type MergeResult struct { | |||||
| 748 | // request. After the merge the source is deleted if it still points to the | 675 | // request. After the merge the source is deleted if it still points to the | ||
| 749 | // head; the PushEvent then carries the deletion too. A failed deletion is | 676 | // head; the PushEvent then carries the deletion too. A failed deletion is | ||
| 750 | // logged and leaves the branch: the merge stands and SourceDeleted is false. | 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 | mr, deleted, err := m.merge(ctx, p, name, number, params) | 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 | repo, err := m.writable(ctx, p, name, domain.ScopeMRMerge) | 684 | repo, err := m.writable(ctx, p, name, domain.ScopeMRMerge) | ||
| 758 | if err != nil { | 685 | if err != nil { | ||
| 759 | return domain.MergeRequest{}, false, err | 686 | return domain.MergeRequest{}, false, err | ||
M internal/app/mergerequests_delete_test.go +13 -12
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | "bnema.dev/ermite/internal/adapters/gitcli" | 12 | "bnema.dev/ermite/internal/adapters/gitcli" | ||
| 13 | "bnema.dev/ermite/internal/app" | 13 | "bnema.dev/ermite/internal/app" | ||
| 14 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 15 | ) | 16 | ) | ||
| 16 | 17 | ||||
| 17 | // A merge can delete its source branch; the push event carries both refs. | 18 | // A merge can delete its source branch; the push event carries both refs. | ||
| @@ -26,7 +27,7 @@ func TestMergeDeletesTheSourceBranch(t *testing.T) { | |||||
| 26 | mr := r.open("feat") | 27 | mr := r.open("feat") | ||
| 27 | r.drain() | 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 | require.NoError(t, err) | 31 | require.NoError(t, err) | ||
| 31 | assert.True(t, res.SourceDeleted) | 32 | assert.True(t, res.SourceDeleted) | ||
| 32 | assert.Equal(t, domain.MRStateMerged, res.State) | 33 | assert.Equal(t, domain.MRStateMerged, res.State) | ||
| @@ -54,7 +55,7 @@ func TestMergeDeletesTheSourceBranch(t *testing.T) { | |||||
| 54 | r.seed() | 55 | r.seed() | ||
| 55 | head := r.feature("feat") | 56 | head := r.feature("feat") | ||
| 56 | mr := r.open("feat") | 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 | require.NoError(t, err) | 59 | require.NoError(t, err) | ||
| 59 | assert.False(t, res.SourceDeleted) | 60 | assert.False(t, res.SourceDeleted) | ||
| 60 | assert.Equal(t, head, r.branchHead("feat")) | 61 | assert.Equal(t, head, r.branchHead("feat")) | ||
| @@ -73,10 +74,10 @@ func TestMergeRefusesToDeleteANeededBranch(t *testing.T) { | |||||
| 73 | r.sh("checkout", "-q", "-B", "release", "main") | 74 | r.sh("checkout", "-q", "-B", "release", "main") | ||
| 74 | r.push("release") | 75 | r.push("release") | ||
| 75 | mr := r.open("feat") | 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 | require.NoError(t, err) | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | 81 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 81 | assert.Contains(t, err.Error(), "!2 still uses") | 82 | assert.Contains(t, err.Error(), "!2 still uses") | ||
| 82 | assert.Equal(t, main, r.branchHead("main"), "not merged") | 83 | assert.Equal(t, main, r.branchHead("main"), "not merged") | ||
| @@ -95,9 +96,9 @@ func TestMergeRefusesToDeleteANeededBranch(t *testing.T) { | |||||
| 95 | r.sh("checkout", "-q", "-B", "sub", "feat") | 96 | r.sh("checkout", "-q", "-B", "sub", "feat") | ||
| 96 | r.commit(author, "d.txt", "dee\n", "add d") | 97 | r.commit(author, "d.txt", "dee\n", "add d") | ||
| 97 | r.push("sub") | 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 | require.NoError(t, err) | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | 102 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 102 | assert.Equal(t, head, r.branchHead("feat")) | 103 | assert.Equal(t, head, r.branchHead("feat")) | ||
| 103 | }) | 104 | }) | ||
| @@ -109,9 +110,9 @@ func TestMergeRefusesToDeleteANeededBranch(t *testing.T) { | |||||
| 109 | r.sh("checkout", "-q", "-B", "old", "main~1") | 110 | r.sh("checkout", "-q", "-B", "old", "main~1") | ||
| 110 | r.push("old") | 111 | r.push("old") | ||
| 111 | old := r.branchHead("old") | 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 | require.NoError(t, err) | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | 116 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 116 | assert.Contains(t, err.Error(), "default branch") | 117 | assert.Contains(t, err.Error(), "default branch") | ||
| 117 | assert.Equal(t, old, r.branchHead("old"), "not merged") | 118 | assert.Equal(t, old, r.branchHead("old"), "not merged") | ||
| @@ -127,7 +128,7 @@ func TestSquashMergedRequestReadsAfterItsCommitsArePruned(t *testing.T) { | |||||
| 127 | r.seed() | 128 | r.seed() | ||
| 128 | head := r.feature("feat") | 129 | head := r.feature("feat") | ||
| 129 | mr := r.open("feat") | 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 | require.NoError(t, err) | 132 | require.NoError(t, err) | ||
| 132 | require.True(t, res.SourceDeleted) | 133 | require.True(t, res.SourceDeleted) | ||
| 133 | 134 | ||||
| @@ -154,9 +155,9 @@ func TestCreateAfterAMergeDeletedTheBranch(t *testing.T) { | |||||
| 154 | r.seed() | 155 | r.seed() | ||
| 155 | head := r.feature("feat") | 156 | head := r.feature("feat") | ||
| 156 | mr := r.open("feat") | 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 | require.NoError(t, err) | 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 | require.ErrorIs(t, err, domain.ErrInvalid) | 161 | require.ErrorIs(t, err, domain.ErrInvalid) | ||
| 161 | assert.Contains(t, fieldsOf(t, err), "source_branch") | 162 | assert.Contains(t, fieldsOf(t, err), "source_branch") | ||
| 162 | } | 163 | } | ||
| @@ -189,7 +190,7 @@ func TestMergeKeepsASourceThatMovedAfterTheMerge(t *testing.T) { | |||||
| 189 | }) | 190 | }) | ||
| 190 | r.drain() | 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 | require.NoError(t, err, "the merge stands") | 194 | require.NoError(t, err, "the merge stands") | ||
| 194 | assert.False(t, res.SourceDeleted) | 195 | assert.False(t, res.SourceDeleted) | ||
| 195 | assert.Equal(t, domain.MRStateMerged, res.State) | 196 | assert.Equal(t, domain.MRStateMerged, res.State) | ||
M internal/app/mergerequests_integration_test.go +116 -115
| @@ -23,8 +23,9 @@ import ( | |||||
| 23 | "bnema.dev/ermite/internal/adapters/kvstore" | 23 | "bnema.dev/ermite/internal/adapters/kvstore" | ||
| 24 | "bnema.dev/ermite/internal/adapters/sshsig" | 24 | "bnema.dev/ermite/internal/adapters/sshsig" | ||
| 25 | "bnema.dev/ermite/internal/app" | 25 | "bnema.dev/ermite/internal/app" | ||
| 26 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |||
| 27 | "bnema.dev/ermite/internal/domain" | 26 | "bnema.dev/ermite/internal/domain" | ||
| 27 | + | "bnema.dev/ermite/internal/ports" | |||
| 28 | + | "bnema.dev/ermite/internal/ports/mocks" | |||
| 28 | ) | 29 | ) | ||
| 29 | 30 | ||||
| 30 | // queuedRepos records the repositories whose maintenance was queued. | 31 | // queuedRepos records the repositories whose maintenance was queued. | ||
| @@ -58,7 +59,7 @@ type mrRig struct { | |||||
| 58 | store *kvstore.Store | 59 | store *kvstore.Store | ||
| 59 | git *gitcli.Git | 60 | git *gitcli.Git | ||
| 60 | bus *eventbus.Bus | 61 | bus *eventbus.Bus | ||
| 61 | - | sched *appmocks.MaintenanceScheduler | 62 | + | sched *mocks.MaintenanceScheduler |
| 62 | queued *queuedRepos | 63 | queued *queuedRepos | ||
| 63 | events <-chan domain.Event | 64 | events <-chan domain.Event | ||
| 64 | work string | 65 | work string | ||
| @@ -94,7 +95,7 @@ func newMRRig(t *testing.T) *mrRig { | |||||
| 94 | require.NoError(t, err) | 95 | require.NoError(t, err) | ||
| 95 | bus := eventbus.NewWithBuffer(1024) | 96 | bus := eventbus.NewWithBuffer(1024) | ||
| 96 | committer := domain.Identity{Name: "ermite", Email: "ermite@git.example.org"} | 97 | committer := domain.Identity{Name: "ermite", Email: "ermite@git.example.org"} | ||
| 97 | - | sched := appmocks.NewMaintenanceScheduler(t) | 98 | + | sched := mocks.NewMaintenanceScheduler(t) |
| 98 | queued := &queuedRepos{} | 99 | queued := &queuedRepos{} | ||
| 99 | sched.EXPECT().Schedule(mock.Anything, mock.Anything).Run(queued.add).Return().Maybe() | 100 | sched.EXPECT().Schedule(mock.Anything, mock.Anything).Run(queued.add).Return().Maybe() | ||
| 100 | r := &mrRig{ | 101 | r := &mrRig{ | ||
| @@ -109,7 +110,7 @@ func newMRRig(t *testing.T) *mrRig { | |||||
| 109 | Meta: store, Store: store.MergeRequests(), Repos: git, Git: git, Signer: signer, | 110 | Meta: store, Store: store.MergeRequests(), Repos: git, Git: git, Signer: signer, | ||
| 110 | Committer: committer, Bus: bus, Clock: fixedClock{}, Maint: r.sched, | 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 | require.NoError(t, err) | 114 | require.NoError(t, err) | ||
| 114 | r.sh("init", "-q", "--initial-branch=main") | 115 | r.sh("init", "-q", "--initial-branch=main") | ||
| 115 | return r | 116 | return r | ||
| @@ -196,7 +197,7 @@ func (r *mrRig) feature(branch string) domain.ObjectID { | |||||
| 196 | 197 | ||||
| 197 | func (r *mrRig) open(branch string) domain.MergeRequest { | 198 | func (r *mrRig) open(branch string) domain.MergeRequest { | ||
| 198 | r.t.Helper() | 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 | require.NoError(r.t, err) | 201 | require.NoError(r.t, err) | ||
| 201 | return mr | 202 | return mr | ||
| 202 | } | 203 | } | ||
| @@ -252,26 +253,26 @@ func TestCreateMergeRequestInputRules(t *testing.T) { | |||||
| 252 | 253 | ||||
| 253 | tests := []struct { | 254 | tests := []struct { | ||
| 254 | name string | 255 | name string | ||
| 255 | - | params app.CreateMergeRequestParams | 256 | + | params ports.CreateMergeRequestParams |
| 256 | field string // "" for valid | 257 | field string // "" for valid | ||
| 257 | }{ | 258 | }{ | ||
| 258 | - | {"valid, default target", app.CreateMergeRequestParams{Title: "t", Source: "feat"}, ""}, | 259 | + | {"valid, default target", ports.CreateMergeRequestParams{Title: "t", Source: "feat"}, ""}, |
| 259 | - | {"valid, explicit target and description", app.CreateMergeRequestParams{Title: "t", Description: "a\nb", Source: "other", Target: "main"}, ""}, | 260 | + | {"valid, explicit target and description", ports.CreateMergeRequestParams{Title: "t", Description: "a\nb", Source: "other", Target: "main"}, ""}, |
| 260 | - | {"empty title", app.CreateMergeRequestParams{Title: "", Source: "feat", Target: "other"}, "title"}, | 261 | + | {"empty title", ports.CreateMergeRequestParams{Title: "", Source: "feat", Target: "other"}, "title"}, |
| 261 | - | {"two-line title", app.CreateMergeRequestParams{Title: "a\nb", Source: "feat", Target: "other"}, "title"}, | 262 | + | {"two-line title", ports.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 too long", ports.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 a bidi override", ports.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 | + | {"title with an escape", ports.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 control character", ports.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 with a bidi isolate", ports.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 too long", ports.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 | + | {"description not utf-8", ports.CreateMergeRequestParams{Title: "t", Description: "\xff", Source: "feat", Target: "other"}, "description"}, |
| 269 | - | {"source missing", app.CreateMergeRequestParams{Title: "t", Source: ""}, "source_branch"}, | 270 | + | {"source missing", ports.CreateMergeRequestParams{Title: "t", Source: ""}, "source_branch"}, |
| 270 | - | {"source does not exist", app.CreateMergeRequestParams{Title: "t", Source: "nope", Target: "main"}, "source_branch"}, | 271 | + | {"source does not exist", ports.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 not a branch name", ports.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 | + | {"source is a full ref", ports.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 | + | {"target does not exist", ports.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "nope"}, "target_branch"}, |
| 274 | - | {"same branch", app.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "feat"}, "target_branch"}, | 275 | + | {"same branch", ports.CreateMergeRequestParams{Title: "t", Source: "feat", Target: "feat"}, "target_branch"}, |
| 275 | } | 276 | } | ||
| 276 | for _, tc := range tests { | 277 | for _, tc := range tests { | ||
| 277 | t.Run(tc.name, func(t *testing.T) { | 278 | t.Run(tc.name, func(t *testing.T) { | ||
| @@ -290,7 +291,7 @@ func TestCreateMergeRequestInputRules(t *testing.T) { | |||||
| 290 | } | 291 | } | ||
| 291 | 292 | ||||
| 292 | t.Run("a request is rejected whole with every field named", func(t *testing.T) { | 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 | got := fieldsOf(t, err) | 295 | got := fieldsOf(t, err) | ||
| 295 | assert.Contains(t, got, "title") | 296 | assert.Contains(t, got, "title") | ||
| 296 | assert.Contains(t, got, "description") | 297 | assert.Contains(t, got, "description") | ||
| @@ -309,22 +310,22 @@ func TestCreateMergeRequestNumbersAndDuplicates(t *testing.T) { | |||||
| 309 | second := r.open("two") | 310 | second := r.open("two") | ||
| 310 | assert.Equal(t, int64(2), second.Number) | 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 | require.ErrorIs(t, err, domain.ErrAlreadyExists, "same open source and target") | 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 | require.ErrorIs(t, err, domain.ErrAlreadyExists, "the default target is the same target") | 316 | require.ErrorIs(t, err, domain.ErrAlreadyExists, "the default target is the same target") | ||
| 316 | 317 | ||||
| 317 | // Another target is another request. | 318 | // Another target is another request. | ||
| 318 | r.sh("checkout", "-q", "-B", "stage", "main") | 319 | r.sh("checkout", "-q", "-B", "stage", "main") | ||
| 319 | r.push("stage") | 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 | require.NoError(t, err) | 322 | require.NoError(t, err) | ||
| 322 | assert.Equal(t, int64(3), third.Number) | 323 | assert.Equal(t, int64(3), third.Number) | ||
| 323 | 324 | ||||
| 324 | // Once the first is closed, the pair is free again, with a new number. | 325 | // Once the first is closed, the pair is free again, with a new number. | ||
| 325 | _, err = r.mrs.Close(r.ctx, root, r.repo, first.Number) | 326 | _, err = r.mrs.Close(r.ctx, root, r.repo, first.Number) | ||
| 326 | require.NoError(t, err) | 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 | require.NoError(t, err) | 329 | require.NoError(t, err) | ||
| 329 | assert.Equal(t, int64(4), fourth.Number, "numbers are never reused") | 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 | reads := map[string]func(p domain.Principal) error{ | 342 | reads := map[string]func(p domain.Principal) error{ | ||
| 342 | "List": func(p domain.Principal) error { | 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 | return err | 345 | return err | ||
| 345 | }, | 346 | }, | ||
| 346 | "Get": func(p domain.Principal) error { | 347 | "Get": func(p domain.Principal) error { | ||
| @@ -357,16 +358,16 @@ func TestMergeRequestAccess(t *testing.T) { | |||||
| 357 | } | 358 | } | ||
| 358 | _, err := r.mrs.Get(r.ctx, reader, r.repo, n+1, false) | 359 | _, err := r.mrs.Get(r.ctx, reader, r.repo, n+1, false) | ||
| 359 | assert.ErrorIs(t, err, domain.ErrNotFound, "unknown number") | 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 | assert.ErrorIs(t, err, domain.ErrNotFound, "unknown repository") | 362 | assert.ErrorIs(t, err, domain.ErrNotFound, "unknown repository") | ||
| 362 | 363 | ||||
| 363 | writes := map[string]func(p domain.Principal) error{ | 364 | writes := map[string]func(p domain.Principal) error{ | ||
| 364 | "Create": func(p domain.Principal) error { | 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 | return err | 367 | return err | ||
| 367 | }, | 368 | }, | ||
| 368 | "AddComment": func(p domain.Principal) error { | 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 | return err | 371 | return err | ||
| 371 | }, | 372 | }, | ||
| 372 | "ResolveComment": func(p domain.Principal) error { | 373 | "ResolveComment": func(p domain.Principal) error { | ||
| @@ -382,7 +383,7 @@ func TestMergeRequestAccess(t *testing.T) { | |||||
| 382 | return err | 383 | return err | ||
| 383 | }, | 384 | }, | ||
| 384 | "Merge": func(p domain.Principal) error { | 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 | return err | 387 | return err | ||
| 387 | }, | 388 | }, | ||
| 388 | } | 389 | } | ||
| @@ -413,11 +414,11 @@ func TestMergeRequestAccess(t *testing.T) { | |||||
| 413 | // On a public repository an anonymous caller reads, but writing is | 414 | // On a public repository an anonymous caller reads, but writing is | ||
| 414 | // unauthenticated rather than not found. | 415 | // unauthenticated rather than not found. | ||
| 415 | pubName := name(t, "pub") | 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 | require.NoError(t, err) | 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 | assert.NoError(t, err) | 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 | assert.ErrorIs(t, err, domain.ErrUnauthenticated) | 422 | assert.ErrorIs(t, err, domain.ErrUnauthenticated) | ||
| 422 | } | 423 | } | ||
| 423 | 424 | ||||
| @@ -434,24 +435,24 @@ func TestListMergeRequests(t *testing.T) { | |||||
| 434 | require.NoError(t, err) | 435 | require.NoError(t, err) | ||
| 435 | r.sh("checkout", "-q", "main") | 436 | r.sh("checkout", "-q", "main") | ||
| 436 | merged := r.feature("f0") | 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 | require.NoError(t, err) | 439 | require.NoError(t, err) | ||
| 439 | r.sh("branch", "-D", "f4") | 440 | r.sh("branch", "-D", "f4") | ||
| 440 | r.run(r.bare(), r.env(author), "branch", "-D", "f4") | 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 | var out []int64 | 444 | var out []int64 | ||
| 444 | for _, m := range p.MergeRequests { | 445 | for _, m := range p.MergeRequests { | ||
| 445 | out = append(out, m.Number) | 446 | out = append(out, m.Number) | ||
| 446 | } | 447 | } | ||
| 447 | return out | 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 | require.NoError(t, err) | 451 | require.NoError(t, err) | ||
| 451 | assert.Equal(t, []int64{5, 4, 3, 2, 1}, numbers(all), "highest number first") | 452 | assert.Equal(t, []int64{5, 4, 3, 2, 1}, numbers(all), "highest number first") | ||
| 452 | assert.Empty(t, all.NextPageToken) | 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 | require.NoError(t, err) | 456 | require.NoError(t, err) | ||
| 456 | assert.Equal(t, []int64{5, 4, 3}, numbers(open)) | 457 | assert.Equal(t, []int64{5, 4, 3}, numbers(open)) | ||
| 457 | for _, m := range open.MergeRequests { | 458 | for _, m := range open.MergeRequests { | ||
| @@ -461,35 +462,35 @@ func TestListMergeRequests(t *testing.T) { | |||||
| 461 | assert.False(t, m.HeadID.IsZero(), "an open request carries its head") | 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 | require.NoError(t, err) | 466 | require.NoError(t, err) | ||
| 466 | assert.Equal(t, []int64{2}, numbers(closed)) | 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 | require.NoError(t, err) | 469 | require.NoError(t, err) | ||
| 469 | assert.Equal(t, []int64{1}, numbers(mergedPage)) | 470 | assert.Equal(t, []int64{1}, numbers(mergedPage)) | ||
| 470 | assert.Equal(t, merged, mergedPage.MergeRequests[0].HeadID, "a merged request keeps the head it had") | 471 | assert.Equal(t, merged, mergedPage.MergeRequests[0].HeadID, "a merged request keeps the head it had") | ||
| 471 | 472 | ||||
| 472 | // Paging: the token names the last number. | 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 | require.NoError(t, err) | 475 | require.NoError(t, err) | ||
| 475 | assert.Equal(t, []int64{5, 4}, numbers(p1)) | 476 | assert.Equal(t, []int64{5, 4}, numbers(p1)) | ||
| 476 | require.NotEmpty(t, p1.NextPageToken) | 477 | require.NotEmpty(t, p1.NextPageToken) | ||
| 477 | // A request created between the pages does not shift them. | 478 | // A request created between the pages does not shift them. | ||
| 478 | r.feature("late") | 479 | r.feature("late") | ||
| 479 | r.open("late") | 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 | require.NoError(t, err) | 482 | require.NoError(t, err) | ||
| 482 | assert.Equal(t, []int64{3, 2}, numbers(p2)) | 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 | require.NoError(t, err) | 485 | require.NoError(t, err) | ||
| 485 | assert.Equal(t, []int64{1}, numbers(p3)) | 486 | assert.Equal(t, []int64{1}, numbers(p3)) | ||
| 486 | assert.Empty(t, p3.NextPageToken) | 487 | assert.Empty(t, p3.NextPageToken) | ||
| 487 | 488 | ||||
| 488 | for _, tok := range []string{"garbage", "bW9yZQ"} { | 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 | assert.ErrorIs(t, err, domain.ErrInvalidPageToken) | 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 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | 494 | assert.ErrorIs(t, err, domain.ErrInvalidPageSize) | ||
| 494 | _ = nums | 495 | _ = nums | ||
| 495 | } | 496 | } | ||
| @@ -499,9 +500,9 @@ func TestGetMergeRequest(t *testing.T) { | |||||
| 499 | main := r.seed() | 500 | main := r.seed() | ||
| 500 | head := r.feature("feat") | 501 | head := r.feature("feat") | ||
| 501 | mr := r.open("feat") | 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 | require.NoError(t, err) | 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 | require.NoError(t, err) | 506 | require.NoError(t, err) | ||
| 506 | 507 | ||||
| 507 | d, err := r.mrs.Get(r.ctx, reader, r.repo, mr.Number, false) | 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 | tests := []struct { | 567 | tests := []struct { | ||
| 567 | name string | 568 | name string | ||
| 568 | - | params app.AddCommentParams | 569 | + | params ports.AddCommentParams |
| 569 | field string // "" for valid | 570 | field string // "" for valid | ||
| 570 | }{ | 571 | }{ | ||
| 571 | - | {"general", app.AddCommentParams{Text: "looks good"}, ""}, | 572 | + | {"general", ports.AddCommentParams{Text: "looks good"}, ""}, |
| 572 | - | {"multi-line general", app.AddCommentParams{Text: "a\n\nb"}, ""}, | 573 | + | {"multi-line general", ports.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 | + | {"new side of a changed line", ports.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 | + | {"old side of a changed line", ports.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 | + | {"context line", ports.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 | + | {"added file", ports.AddCommentParams{Path: "c.txt", Line: 1, Side: domain.SideNew, Text: "x"}, ""}, |
| 577 | - | {"empty text", app.AddCommentParams{Text: ""}, "text"}, | 578 | + | {"empty text", ports.AddCommentParams{Text: ""}, "text"}, |
| 578 | - | {"blank text", app.AddCommentParams{Text: " \n "}, "text"}, | 579 | + | {"blank text", ports.AddCommentParams{Text: " \n "}, "text"}, |
| 579 | - | {"text too long", app.AddCommentParams{Text: strings.Repeat("x", 8001)}, "text"}, | 580 | + | {"text too long", ports.AddCommentParams{Text: strings.Repeat("x", 8001)}, "text"}, |
| 580 | - | {"text with a control character", app.AddCommentParams{Text: "a\x1b[0m"}, "text"}, | 581 | + | {"text with a control character", ports.AddCommentParams{Text: "a\x1b[0m"}, "text"}, |
| 581 | - | {"text with a tab", app.AddCommentParams{Text: "a\tb"}, "text"}, | 582 | + | {"text with a tab", ports.AddCommentParams{Text: "a\tb"}, "text"}, |
| 582 | - | {"text with a bidi override", app.AddCommentParams{Text: "a\u202eb"}, "text"}, | 583 | + | {"text with a bidi override", ports.AddCommentParams{Text: "a\u202eb"}, "text"}, |
| 583 | - | {"line outside the diff", app.AddCommentParams{Path: "a.txt", Line: 40, Side: domain.SideNew, Text: "x"}, "path"}, | 584 | + | {"line outside the diff", ports.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 | + | {"unchanged file", ports.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 | + | {"unknown path", ports.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 | + | {"deleted line on the wrong side", ports.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 line", ports.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 | + | {"path without a side", ports.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 | + | {"line without a path", ports.AddCommentParams{Line: 2, Side: domain.SideNew, Text: "x"}, "path"}, |
| 590 | - | {"side without a path", app.AddCommentParams{Side: domain.SideOld, Text: "x"}, "path"}, | 591 | + | {"side without a path", ports.AddCommentParams{Side: domain.SideOld, Text: "x"}, "path"}, |
| 591 | - | {"negative line", app.AddCommentParams{Path: "a.txt", Line: -2, Side: domain.SideNew, Text: "x"}, "line"}, | 592 | + | {"negative line", ports.AddCommentParams{Path: "a.txt", Line: -2, Side: domain.SideNew, Text: "x"}, "line"}, |
| 592 | } | 593 | } | ||
| 593 | for _, tc := range tests { | 594 | for _, tc := range tests { | ||
| 594 | t.Run(tc.name, func(t *testing.T) { | 595 | t.Run(tc.name, func(t *testing.T) { | ||
| @@ -625,7 +626,7 @@ func TestAddComment(t *testing.T) { | |||||
| 625 | t.Run("not open", func(t *testing.T) { | 626 | t.Run("not open", func(t *testing.T) { | ||
| 626 | _, err := r.mrs.Close(r.ctx, mrW, r.repo, n) | 627 | _, err := r.mrs.Close(r.ctx, mrW, r.repo, n) | ||
| 627 | require.NoError(t, err) | 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 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | 630 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 630 | _, err = r.mrs.ResolveComment(r.ctx, mrW, r.repo, n, 1, true) | 631 | _, err = r.mrs.ResolveComment(r.ctx, mrW, r.repo, n, 1, true) | ||
| 631 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | 632 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| @@ -642,7 +643,7 @@ func TestConcurrentComments(t *testing.T) { | |||||
| 642 | ids := make(chan int64, workers) | 643 | ids := make(chan int64, workers) | ||
| 643 | for i := range workers { | 644 | for i := range workers { | ||
| 644 | wg.Go(func() { | 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 | if assert.NoError(t, err) { | 647 | if assert.NoError(t, err) { | ||
| 647 | ids <- c.ID | 648 | ids <- c.ID | ||
| 648 | } | 649 | } | ||
| @@ -666,7 +667,7 @@ func TestResolveComment(t *testing.T) { | |||||
| 666 | r.seed() | 667 | r.seed() | ||
| 667 | r.feature("feat") | 668 | r.feature("feat") | ||
| 668 | mr := r.open("feat") | 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 | require.NoError(t, err) | 671 | require.NoError(t, err) | ||
| 671 | r.drain() | 672 | r.drain() | ||
| 672 | 673 | ||||
| @@ -698,9 +699,9 @@ func TestEventsOfAMergeRequest(t *testing.T) { | |||||
| 698 | r.drain() | 699 | r.drain() | ||
| 699 | 700 | ||||
| 700 | mr := r.open("feat") | 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 | require.NoError(t, err) | 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 | require.NoError(t, err) | 705 | require.NoError(t, err) | ||
| 705 | 706 | ||||
| 706 | r.feature("other") | 707 | r.feature("other") | ||
| @@ -732,7 +733,7 @@ func TestEventsOfAMergeRequest(t *testing.T) { | |||||
| 732 | // Failed calls publish nothing. | 733 | // Failed calls publish nothing. | ||
| 733 | _, err = r.mrs.Close(r.ctx, mrW, r.repo, other.Number) | 734 | _, err = r.mrs.Close(r.ctx, mrW, r.repo, other.Number) | ||
| 734 | require.Error(t, err) | 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 | require.Error(t, err) | 737 | require.Error(t, err) | ||
| 737 | assert.Empty(t, r.drain()) | 738 | assert.Empty(t, r.drain()) | ||
| 738 | } | 739 | } | ||
| @@ -859,7 +860,7 @@ func TestMergeFastForward(t *testing.T) { | |||||
| 859 | mr := r.open("feat") | 860 | mr := r.open("feat") | ||
| 860 | r.drain() | 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 | require.NoError(t, err) | 864 | require.NoError(t, err) | ||
| 864 | assert.Equal(t, domain.MRStateMerged, merged.State) | 865 | assert.Equal(t, domain.MRStateMerged, merged.State) | ||
| 865 | assert.Equal(t, domain.MergeModeFastForward, merged.MergeMode, "the default mode") | 866 | assert.Equal(t, domain.MergeModeFastForward, merged.MergeMode, "the default mode") | ||
| @@ -880,11 +881,11 @@ func TestMergeFastForward(t *testing.T) { | |||||
| 880 | assert.Len(t, d.Diff.Files, 2) | 881 | assert.Len(t, d.Diff.Files, 2) | ||
| 881 | 882 | ||||
| 882 | // Repeating it, or touching a final request, is a failed precondition. | 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 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | 885 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 885 | _, err = r.mrs.Close(r.ctx, mrW, r.repo, mr.Number) | 886 | _, err = r.mrs.Close(r.ctx, mrW, r.repo, mr.Number) | ||
| 886 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | 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 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | 889 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 889 | } | 890 | } | ||
| 890 | 891 | ||||
| @@ -897,14 +898,14 @@ func TestMergeRefusals(t *testing.T) { | |||||
| 897 | mr := r.open("feat") | 898 | mr := r.open("feat") | ||
| 898 | r.commit(author, "more.txt", "m\n", "pushed after the review") | 899 | r.commit(author, "more.txt", "m\n", "pushed after the review") | ||
| 899 | r.push("feat") | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | 902 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 902 | assert.Contains(t, err.Error(), "branch moved, read again") | 903 | assert.Contains(t, err.Error(), "branch moved, read again") | ||
| 903 | assert.NotEqual(t, head, r.branchHead("main"), "main did not move") | 904 | assert.NotEqual(t, head, r.branchHead("main"), "main did not move") | ||
| 904 | // Reading again gives the new head, which merges. | 905 | // Reading again gives the new head, which merges. | ||
| 905 | d, err := r.mrs.Get(r.ctx, mrM, r.repo, mr.Number, false) | 906 | d, err := r.mrs.Get(r.ctx, mrM, r.repo, mr.Number, false) | ||
| 906 | require.NoError(t, err) | 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 | require.NoError(t, err) | 909 | require.NoError(t, err) | ||
| 909 | }) | 910 | }) | ||
| 910 | 911 | ||||
| @@ -919,7 +920,7 @@ func TestMergeRefusals(t *testing.T) { | |||||
| 919 | tip := r.branchHead("main") | 920 | tip := r.branchHead("main") | ||
| 920 | 921 | ||||
| 921 | for _, mode := range []domain.MergeMode{domain.MergeModeFastForward, domain.MergeModeSquash} { | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed, mode) | 924 | require.ErrorIs(t, err, domain.ErrPreconditionFailed, mode) | ||
| 924 | assert.Contains(t, err.Error(), "rebase", mode) | 925 | assert.Contains(t, err.Error(), "rebase", mode) | ||
| 925 | } | 926 | } | ||
| @@ -932,7 +933,7 @@ func TestMergeRefusals(t *testing.T) { | |||||
| 932 | r.sh("checkout", "-q", "feat") | 933 | r.sh("checkout", "-q", "feat") | ||
| 933 | r.sh("rebase", "-q", "main") | 934 | r.sh("rebase", "-q", "main") | ||
| 934 | r.push("feat") | 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 | require.NoError(t, err) | 937 | require.NoError(t, err) | ||
| 937 | }) | 938 | }) | ||
| 938 | 939 | ||||
| @@ -942,13 +943,13 @@ func TestMergeRefusals(t *testing.T) { | |||||
| 942 | head := r.feature("feat") | 943 | head := r.feature("feat") | ||
| 943 | mr := r.open("feat") | 944 | mr := r.open("feat") | ||
| 944 | modes := []domain.MergeMode{domain.MergeModeFastForward} | 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 | require.NoError(t, err) | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | 950 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 950 | assert.Contains(t, err.Error(), "squash") | 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 | require.NoError(t, err, "fast-forward is allowed") | 953 | require.NoError(t, err, "fast-forward is allowed") | ||
| 953 | }) | 954 | }) | ||
| 954 | 955 | ||||
| @@ -958,11 +959,11 @@ func TestMergeRefusals(t *testing.T) { | |||||
| 958 | head := r.feature("feat") | 959 | head := r.feature("feat") | ||
| 959 | mr := r.open("feat") | 960 | mr := r.open("feat") | ||
| 960 | modes := []domain.MergeMode{domain.MergeModeSquash} | 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 | require.NoError(t, err) | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | 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 | require.NoError(t, err) | 967 | require.NoError(t, err) | ||
| 967 | }) | 968 | }) | ||
| 968 | 969 | ||||
| @@ -971,13 +972,13 @@ func TestMergeRefusals(t *testing.T) { | |||||
| 971 | r.seed() | 972 | r.seed() | ||
| 972 | head := r.feature("feat") | 973 | head := r.feature("feat") | ||
| 973 | mr := r.open("feat") | 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 | require.ErrorIs(t, err, domain.ErrInvalid) | 976 | require.ErrorIs(t, err, domain.ErrInvalid) | ||
| 976 | assert.Contains(t, fieldsOf(t, err), "head_id") | 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 | require.ErrorIs(t, err, domain.ErrInvalid) | 979 | require.ErrorIs(t, err, domain.ErrInvalid) | ||
| 979 | assert.Contains(t, fieldsOf(t, err), "mode") | 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 | assert.ErrorIs(t, err, domain.ErrNotFound) | 982 | assert.ErrorIs(t, err, domain.ErrNotFound) | ||
| 982 | }) | 983 | }) | ||
| 983 | 984 | ||||
| @@ -987,13 +988,13 @@ func TestMergeRefusals(t *testing.T) { | |||||
| 987 | head := r.feature("feat") | 988 | head := r.feature("feat") | ||
| 988 | mr := r.open("feat") | 989 | mr := r.open("feat") | ||
| 989 | r.run(r.bare(), r.env(author), "branch", "-D", "feat") | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | 992 | require.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 992 | assert.Contains(t, err.Error(), "no longer exists") | 993 | assert.Contains(t, err.Error(), "no longer exists") | ||
| 993 | 994 | ||||
| 994 | r.push("feat") | 995 | r.push("feat") | ||
| 995 | r.run(r.bare(), r.env(author), "update-ref", "refs/heads/main", head.String()) | 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 | require.ErrorIs(t, err, domain.ErrPreconditionFailed, "the target already is at the head") | 998 | require.ErrorIs(t, err, domain.ErrPreconditionFailed, "the target already is at the head") | ||
| 998 | assert.Contains(t, err.Error(), "nothing to merge") | 999 | assert.Contains(t, err.Error(), "nothing to merge") | ||
| 999 | }) | 1000 | }) | ||
| @@ -1022,7 +1023,7 @@ func TestConcurrentMergesSerialize(t *testing.T) { | |||||
| 1022 | continue | 1023 | continue | ||
| 1023 | } | 1024 | } | ||
| 1024 | wg.Go(func() { | 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 | results <- outcome{number, err} | 1027 | results <- outcome{number, err} | ||
| 1027 | }) | 1028 | }) | ||
| 1028 | } | 1029 | } | ||
| @@ -1079,11 +1080,11 @@ func TestSquashMerge(t *testing.T) { | |||||
| 1079 | r.commit(bob, "w.txt", "w\n", "bob again") | 1080 | r.commit(bob, "w.txt", "w\n", "bob again") | ||
| 1080 | r.push("feat") | 1081 | r.push("feat") | ||
| 1081 | head := r.branchHead("feat") | 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 | require.NoError(t, err) | 1084 | require.NoError(t, err) | ||
| 1084 | r.drain() | 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 | require.NoError(t, err) | 1088 | require.NoError(t, err) | ||
| 1088 | assert.Equal(t, domain.MergeModeSquash, merged.MergeMode) | 1089 | assert.Equal(t, domain.MergeModeSquash, merged.MergeMode) | ||
| 1089 | require.False(t, merged.MergedCommitID.IsZero()) | 1090 | require.False(t, merged.MergedCommitID.IsZero()) | ||
| @@ -1144,7 +1145,7 @@ func TestSquashSingleCommitHasNoTrailer(t *testing.T) { | |||||
| 1144 | r.commit(author, "m.txt", "m\n", "only") | 1145 | r.commit(author, "m.txt", "m\n", "only") | ||
| 1145 | r.push("mine") | 1146 | r.push("mine") | ||
| 1146 | mr := r.open("mine") | 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 | require.NoError(t, err) | 1149 | require.NoError(t, err) | ||
| 1149 | msg := r.run(r.bare(), r.env(author), "log", "-1", "--format=%B", merged.MergedCommitID.String()) | 1150 | msg := r.run(r.bare(), r.env(author), "log", "-1", "--format=%B", merged.MergedCommitID.String()) | ||
| 1150 | assert.Equal(t, "Add mine (!1)\n\n- only", msg) | 1151 | assert.Equal(t, "Add mine (!1)\n\n- only", msg) | ||
| @@ -1159,7 +1160,7 @@ func TestUpdateRepoSettings(t *testing.T) { | |||||
| 1159 | 1160 | ||||
| 1160 | modes := []domain.MergeMode{domain.MergeModeSquash, domain.MergeModeSquash} | 1161 | modes := []domain.MergeMode{domain.MergeModeSquash, domain.MergeModeSquash} | ||
| 1161 | off := false | 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 | require.NoError(t, err) | 1164 | require.NoError(t, err) | ||
| 1164 | assert.Equal(t, domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}, FailingChecksBlock: false}, got.Settings) | 1165 | assert.Equal(t, domain.RepoSettings{AllowedMergeModes: []domain.MergeMode{domain.MergeModeSquash}, FailingChecksBlock: false}, got.Settings) | ||
| 1165 | again, err := r.repos.Get(r.ctx, root, r.repo) | 1166 | again, err := r.repos.Get(r.ctx, root, r.repo) | ||
| @@ -1168,14 +1169,14 @@ func TestUpdateRepoSettings(t *testing.T) { | |||||
| 1168 | 1169 | ||||
| 1169 | // Only the named setting changes. | 1170 | // Only the named setting changes. | ||
| 1170 | on := true | 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 | require.NoError(t, err) | 1173 | require.NoError(t, err) | ||
| 1173 | assert.Equal(t, []domain.MergeMode{domain.MergeModeSquash}, got.Settings.AllowedMergeModes) | 1174 | assert.Equal(t, []domain.MergeMode{domain.MergeModeSquash}, got.Settings.AllowedMergeModes) | ||
| 1174 | assert.True(t, got.Settings.FailingChecksBlock) | 1175 | assert.True(t, got.Settings.FailingChecksBlock) | ||
| 1175 | 1176 | ||||
| 1176 | for _, bad := range [][]domain.MergeMode{{}, nil, {"rebase"}} { | 1177 | for _, bad := range [][]domain.MergeMode{{}, nil, {"rebase"}} { | ||
| 1177 | bad := bad | 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 | assert.ErrorIs(t, err, domain.ErrInvalid, "%v", bad) | 1180 | assert.ErrorIs(t, err, domain.ErrInvalid, "%v", bad) | ||
| 1180 | } | 1181 | } | ||
| 1181 | again, err = r.repos.Get(r.ctx, root, r.repo) | 1182 | again, err = r.repos.Get(r.ctx, root, r.repo) | ||
| @@ -1183,7 +1184,7 @@ func TestUpdateRepoSettings(t *testing.T) { | |||||
| 1183 | assert.Equal(t, got.Settings, again.Settings, "a refused change stores nothing") | 1184 | assert.Equal(t, got.Settings, again.Settings, "a refused change stores nothing") | ||
| 1184 | 1185 | ||||
| 1185 | // repo:admin is needed, like for any other field. | 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 | assert.ErrorIs(t, err, domain.ErrForbidden) | 1188 | assert.ErrorIs(t, err, domain.ErrForbidden) | ||
| 1188 | } | 1189 | } | ||
| 1189 | 1190 | ||||
| @@ -1194,13 +1195,13 @@ func TestDeletingARepositoryDropsItsMergeRequests(t *testing.T) { | |||||
| 1194 | r.open("feat") | 1195 | r.open("feat") | ||
| 1195 | require.NoError(t, r.repos.Delete(r.ctx, root, r.repo)) | 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 | assert.ErrorIs(t, err, domain.ErrNotFound) | 1199 | assert.ErrorIs(t, err, domain.ErrNotFound) | ||
| 1199 | 1200 | ||||
| 1200 | // Created again under the same name, it starts empty. | 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 | require.NoError(t, err) | 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 | require.NoError(t, err) | 1205 | require.NoError(t, err) | ||
| 1205 | assert.Empty(t, page.MergeRequests) | 1206 | assert.Empty(t, page.MergeRequests) | ||
| 1206 | } | 1207 | } | ||
| @@ -1222,12 +1223,12 @@ func TestAgentPresetWorksOnItsPrivateRepository(t *testing.T) { | |||||
| 1222 | r.seed() | 1223 | r.seed() | ||
| 1223 | head := r.feature("feat") | 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 | require.NoError(t, err) | 1227 | require.NoError(t, err) | ||
| 1227 | assert.Equal(t, head, mr.HeadID) | 1228 | assert.Equal(t, head, mr.HeadID) | ||
| 1228 | assert.Equal(t, "agent-1", mr.Author) | 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 | require.NoError(t, err) | 1232 | require.NoError(t, err) | ||
| 1232 | _, err = r.mrs.ResolveComment(r.ctx, agent, r.repo, mr.Number, c.ID, true) | 1233 | _, err = r.mrs.ResolveComment(r.ctx, agent, r.repo, mr.Number, c.ID, true) | ||
| 1233 | require.NoError(t, err) | 1234 | require.NoError(t, err) | ||
| @@ -1235,7 +1236,7 @@ func TestAgentPresetWorksOnItsPrivateRepository(t *testing.T) { | |||||
| 1235 | require.NoError(t, err) | 1236 | require.NoError(t, err) | ||
| 1236 | 1237 | ||||
| 1237 | // repo:write alone does not read merge requests. | 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 | assert.ErrorIs(t, err, domain.ErrNotFound) | 1240 | assert.ErrorIs(t, err, domain.ErrNotFound) | ||
| 1240 | _, err = r.mrs.Get(r.ctx, agent, r.repo, mr.Number, false) | 1241 | _, err = r.mrs.Get(r.ctx, agent, r.repo, mr.Number, false) | ||
| 1241 | assert.ErrorIs(t, err, domain.ErrNotFound) | 1242 | assert.ErrorIs(t, err, domain.ErrNotFound) | ||
| @@ -1245,11 +1246,11 @@ func TestAgentPresetWorksOnItsPrivateRepository(t *testing.T) { | |||||
| 1245 | assert.Equal(t, domain.MRStateClosed, closed.State) | 1246 | assert.Equal(t, domain.MRStateClosed, closed.State) | ||
| 1246 | 1247 | ||||
| 1247 | // An unknown repository is not found whatever the scopes. | 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 | assert.ErrorIs(t, err, domain.ErrNotFound) | 1250 | assert.ErrorIs(t, err, domain.ErrNotFound) | ||
| 1250 | // A token limited to other repositories does not get the scope here. | 1251 | // A token limited to other repositories does not get the scope here. | ||
| 1251 | elsewhere := domain.TokenPrincipal(domain.Token{ID: "e", Scopes: []domain.Scope{domain.ScopeRepoWrite, domain.ScopeMRWrite}, Repos: []domain.RepoName{name(t, "else")}}) | 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 | assert.ErrorIs(t, err, domain.ErrNotFound) | 1254 | assert.ErrorIs(t, err, domain.ErrNotFound) | ||
| 1254 | } | 1255 | } | ||
| 1255 | 1256 | ||||
| @@ -1267,7 +1268,7 @@ func TestMergeRecordsAPush(t *testing.T) { | |||||
| 1267 | require.True(t, before.PushedAt.IsZero(), "no push recorded yet") | 1268 | require.True(t, before.PushedAt.IsZero(), "no push recorded yet") | ||
| 1268 | assert.Empty(t, r.queued.names()) | 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 | require.NoError(t, err) | 1272 | require.NoError(t, err) | ||
| 1272 | 1273 | ||||
| 1273 | after, err := r.repos.Get(r.ctx, root, r.repo) | 1274 | after, err := r.repos.Get(r.ctx, root, r.repo) | ||
| @@ -1285,10 +1286,10 @@ func TestCommentsPerMergeRequestAreBounded(t *testing.T) { | |||||
| 1285 | r.feature("feat") | 1286 | r.feature("feat") | ||
| 1286 | mr := r.open("feat") | 1287 | mr := r.open("feat") | ||
| 1287 | for i := range app.MaxCommentsPerMergeRequest { | 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 | require.NoError(t, err, "comment %d", i+1) | 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 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | 1293 | assert.ErrorIs(t, err, domain.ErrResourceExhausted) | ||
| 1293 | d, err := r.mrs.Get(r.ctx, root, r.repo, mr.Number, false) | 1294 | d, err := r.mrs.Get(r.ctx, root, r.repo, mr.Number, false) | ||
| 1294 | require.NoError(t, err) | 1295 | require.NoError(t, err) | ||
| @@ -1301,6 +1302,6 @@ func TestCommentsPerMergeRequestAreBounded(t *testing.T) { | |||||
| 1301 | r.commit(author, "o.txt", "o\n", "other") | 1302 | r.commit(author, "o.txt", "o\n", "other") | ||
| 1302 | r.push("other") | 1303 | r.push("other") | ||
| 1303 | other := r.open("other") | 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 | require.NoError(t, err) | 1306 | require.NoError(t, err) | ||
| 1306 | } | 1307 | } | ||
M internal/app/mergerequests_test.go +5 -5
| @@ -12,8 +12,8 @@ import ( | |||||
| 12 | "github.com/stretchr/testify/require" | 12 | "github.com/stretchr/testify/require" | ||
| 13 | 13 | ||||
| 14 | "bnema.dev/ermite/internal/app" | 14 | "bnema.dev/ermite/internal/app" | ||
| 15 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |||
| 16 | "bnema.dev/ermite/internal/domain" | 15 | "bnema.dev/ermite/internal/domain" | ||
| 16 | + | "bnema.dev/ermite/internal/ports" | |||
| 17 | "bnema.dev/ermite/internal/ports/mocks" | 17 | "bnema.dev/ermite/internal/ports/mocks" | ||
| 18 | ) | 18 | ) | ||
| 19 | 19 | ||||
| @@ -37,7 +37,7 @@ func newMRUnit(t *testing.T) *mrUnit { | |||||
| 37 | } | 37 | } | ||
| 38 | clock := mocks.NewClock(t) | 38 | clock := mocks.NewClock(t) | ||
| 39 | clock.EXPECT().Now().Return(now).Maybe() | 39 | clock.EXPECT().Now().Return(now).Maybe() | ||
| 40 | - | sched := appmocks.NewMaintenanceScheduler(t) | 40 | + | sched := mocks.NewMaintenanceScheduler(t) |
| 41 | sched.EXPECT().Schedule(mock.Anything, mock.Anything).Return().Maybe() | 41 | sched.EXPECT().Schedule(mock.Anything, mock.Anything).Return().Maybe() | ||
| 42 | u.mrs = app.NewMergeRequests(app.MergeRequestsConfig{ | 42 | u.mrs = app.NewMergeRequests(app.MergeRequestsConfig{ | ||
| 43 | Meta: u.meta, Store: u.store, Repos: u.repos, Git: u.git, | 43 | Meta: u.meta, Store: u.store, Repos: u.repos, Git: u.git, | ||
| @@ -51,7 +51,7 @@ func newMRUnit(t *testing.T) *mrUnit { | |||||
| 51 | func TestCreateReturnsGitFailuresAsErrors(t *testing.T) { | 51 | func TestCreateReturnsGitFailuresAsErrors(t *testing.T) { | ||
| 52 | t.Parallel() | 52 | t.Parallel() | ||
| 53 | boom := errors.New("fatal: /srv/ermite/repos/proj.git: permission denied") | 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 | t.Run("reading a branch", func(t *testing.T) { | 56 | t.Run("reading a branch", func(t *testing.T) { | ||
| 57 | t.Parallel() | 57 | t.Parallel() | ||
| @@ -70,7 +70,7 @@ func TestCreateReturnsGitFailuresAsErrors(t *testing.T) { | |||||
| 70 | u := newMRUnit(t) | 70 | u := newMRUnit(t) | ||
| 71 | u.meta.EXPECT().Get(mock.Anything, u.repo.Name).Return(u.repo, nil) | 71 | u.meta.EXPECT().Get(mock.Anything, u.repo.Name).Return(u.repo, nil) | ||
| 72 | u.repos.EXPECT().DefaultBranch(mock.Anything, u.repo.Name).Return("", false, boom) | 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 | require.ErrorIs(t, err, boom) | 74 | require.ErrorIs(t, err, boom) | ||
| 75 | var fe *domain.InvalidFieldsError | 75 | var fe *domain.InvalidFieldsError | ||
| 76 | assert.False(t, errors.As(err, &fe), "not a field violation: %v", err) | 76 | assert.False(t, errors.As(err, &fe), "not a field violation: %v", err) | ||
| @@ -109,7 +109,7 @@ func TestMergeReturnsTheFailureToReadTheSettings(t *testing.T) { | |||||
| 109 | u.store.EXPECT().Get(mock.Anything, u.repo.Name, int64(1)).Return(domain.MergeRequest{ | 109 | u.store.EXPECT().Get(mock.Anything, u.repo.Name, int64(1)).Return(domain.MergeRequest{ | ||
| 110 | Repo: u.repo.Name, Number: 1, State: domain.MRStateOpen, Source: "feat", Target: "main", | 110 | Repo: u.repo.Name, Number: 1, State: domain.MRStateOpen, Source: "feat", Target: "main", | ||
| 111 | }, nil) | 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 | require.ErrorIs(t, err, tc.want) | 113 | require.ErrorIs(t, err, tc.want) | ||
| 114 | if tc.want == boom { | 114 | if tc.want == boom { | ||
| 115 | assert.NotErrorIs(t, err, domain.ErrNotFound) | 115 | assert.NotErrorIs(t, err, domain.ErrNotFound) | ||
M internal/app/paging.go +11 -24
| @@ -11,6 +11,7 @@ import ( | |||||
| 11 | "strings" | 11 | "strings" | ||
| 12 | 12 | ||||
| 13 | "bnema.dev/ermite/internal/domain" | 13 | "bnema.dev/ermite/internal/domain" | ||
| 14 | + | "bnema.dev/ermite/internal/ports" | |||
| 14 | ) | 15 | ) | ||
| 15 | 16 | ||||
| 16 | const ( | 17 | const ( | ||
| @@ -83,31 +84,24 @@ func pageAfter[T any](items []T, size int, after func(T) bool, token func(T) str | |||||
| 83 | return page, "" | 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 | // ListPage returns a page of the repositories the principal may read, ordered | 87 | // ListPage returns a page of the repositories the principal may read, ordered | ||
| 94 | // by name. size is 0 for DefaultPageSize and lowered to MaxRepoPageSize; the page | 88 | // by name. size is 0 for DefaultPageSize and lowered to MaxRepoPageSize; the page | ||
| 95 | // token names the last repository of the previous page, so repositories that | 89 | // token names the last repository of the previous page, so repositories that | ||
| 96 | // appear or disappear between two pages never shift the others. | 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 | n, err := pageSizeUpTo(size, MaxRepoPageSize) | 92 | n, err := pageSizeUpTo(size, MaxRepoPageSize) | ||
| 99 | if err != nil { | 93 | if err != nil { | ||
| 100 | - | return RepoPage{}, err | 94 | + | return ports.RepoPage{}, err |
| 101 | } | 95 | } | ||
| 102 | after, err := decodeRepoToken(token) | 96 | after, err := decodeRepoToken(token) | ||
| 103 | if err != nil { | 97 | if err != nil { | ||
| 104 | - | return RepoPage{}, err | 98 | + | return ports.RepoPage{}, err |
| 105 | } | 99 | } | ||
| 106 | all, err := r.List(ctx, p) | 100 | all, err := r.List(ctx, p) | ||
| 107 | if err != nil { | 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 | page.Repos, page.NextPageToken = pageAfter(all, n, | 105 | page.Repos, page.NextPageToken = pageAfter(all, n, | ||
| 112 | func(repo domain.Repo) bool { return after == "" || repo.Name.String() > after }, | 106 | func(repo domain.Repo) bool { return after == "" || repo.Name.String() > after }, | ||
| 113 | func(repo domain.Repo) string { return encodeRepoToken(repo.Name) }) | 107 | func(repo domain.Repo) string { return encodeRepoToken(repo.Name) }) | ||
| @@ -130,28 +124,21 @@ func decodeRepoToken(tok string) (string, error) { | |||||
| 130 | return raw, nil | 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 | // ListPage returns a page of the tokens List returns, newest first (then by | 127 | // ListPage returns a page of the tokens List returns, newest first (then by | ||
| 141 | // id). size and the page token work like Repos.ListPage; the token names the | 128 | // id). size and the page token work like Repos.ListPage; the token names the | ||
| 142 | // last token of the previous page. | 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 | n, err := pageSize(size) | 131 | n, err := pageSize(size) | ||
| 145 | if err != nil { | 132 | if err != nil { | ||
| 146 | - | return TokenPage{}, err | 133 | + | return ports.TokenPage{}, err |
| 147 | } | 134 | } | ||
| 148 | after, err := decodeTokenCursor(token) | 135 | after, err := decodeTokenCursor(token) | ||
| 149 | if err != nil { | 136 | if err != nil { | ||
| 150 | - | return TokenPage{}, err | 137 | + | return ports.TokenPage{}, err |
| 151 | } | 138 | } | ||
| 152 | all, err := t.List(ctx, p) | 139 | all, err := t.List(ctx, p) | ||
| 153 | if err != nil { | 140 | if err != nil { | ||
| 154 | - | return TokenPage{}, err | 141 | + | return ports.TokenPage{}, err |
| 155 | } | 142 | } | ||
| 156 | slices.SortFunc(all, func(a, b domain.Token) int { | 143 | slices.SortFunc(all, func(a, b domain.Token) int { | ||
| 157 | if c := b.CreatedAt.Compare(a.CreatedAt); c != 0 { | 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 | return strings.Compare(b.ID, a.ID) | 147 | return strings.Compare(b.ID, a.ID) | ||
| 161 | }) | 148 | }) | ||
| 162 | - | var page TokenPage | 149 | + | var page ports.TokenPage |
| 163 | page.Tokens, page.NextPageToken = pageAfter(all, n, | 150 | page.Tokens, page.NextPageToken = pageAfter(all, n, | ||
| 164 | func(tok domain.Token) bool { return after == nil || tokenAfter(tok, *after) }, | 151 | func(tok domain.Token) bool { return after == nil || tokenAfter(tok, *after) }, | ||
| 165 | encodeTokenCursor) | 152 | encodeTokenCursor) | ||
M internal/app/pushes.go +9 -15
| @@ -18,17 +18,6 @@ import ( | |||||
| 18 | // pushRetries bounds the retries of a metadata update that loses a race. | 18 | // pushRetries bounds the retries of a metadata update that loses a race. | ||
| 19 | const pushRetries = 5 | 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 | // Pushes are the use cases around a Git push. | 21 | // Pushes are the use cases around a Git push. | ||
| 33 | type Pushes struct { | 22 | type Pushes struct { | ||
| 34 | meta ports.RepoMetaStore | 23 | meta ports.RepoMetaStore | ||
| @@ -36,15 +25,20 @@ type Pushes struct { | |||||
| 36 | git ports.GitRepos | 25 | git ports.GitRepos | ||
| 37 | bus ports.EventBus | 26 | bus ports.EventBus | ||
| 38 | clock ports.Clock | 27 | clock ports.Clock | ||
| 39 | - | maint MaintenanceScheduler | 28 | + | maint ports.MaintenanceScheduler |
| 40 | - | auth Revalidator | 29 | + | auth ports.Revalidator |
| 41 | fresh ports.RepoFreshener // nil: the reader needs no telling | 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 | // NewPushes builds the push use cases. Every argument is required: auth | 38 | // NewPushes builds the push use cases. Every argument is required: auth | ||
| 45 | // re-validates the token of a push when its pre-receive hook runs, maint | 39 | // re-validates the token of a push when its pre-receive hook runs, maint | ||
| 46 | // queues the maintenance that follows a push. | 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 | return &Pushes{meta: meta, repos: repos, git: git, bus: bus, clock: clock, maint: maint, auth: auth} | 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 | if !create || !canWrite(p, name) { | 72 | if !create || !canWrite(p, name) { | ||
| 79 | return domain.ErrNotFound | 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 | switch { | 76 | switch { | ||
| 83 | case err == nil: | 77 | case err == nil: | ||
| 84 | return nil // Create published RepoCreated | 78 | return nil // Create published RepoCreated | ||
M internal/app/pushes_test.go +2 -3
| @@ -13,7 +13,6 @@ import ( | |||||
| 13 | "github.com/stretchr/testify/require" | 13 | "github.com/stretchr/testify/require" | ||
| 14 | 14 | ||||
| 15 | "bnema.dev/ermite/internal/app" | 15 | "bnema.dev/ermite/internal/app" | ||
| 16 | - | appmocks "bnema.dev/ermite/internal/app/mocks" | |||
| 17 | "bnema.dev/ermite/internal/domain" | 16 | "bnema.dev/ermite/internal/domain" | ||
| 18 | "bnema.dev/ermite/internal/ports" | 17 | "bnema.dev/ermite/internal/ports" | ||
| 19 | "bnema.dev/ermite/internal/ports/mocks" | 18 | "bnema.dev/ermite/internal/ports/mocks" | ||
| @@ -25,7 +24,7 @@ type pushFixture struct { | |||||
| 25 | bus *mocks.EventBus | 24 | bus *mocks.EventBus | ||
| 26 | clock *mocks.Clock | 25 | clock *mocks.Clock | ||
| 27 | tokens *mocks.TokenStore | 26 | tokens *mocks.TokenStore | ||
| 28 | - | sched *appmocks.MaintenanceScheduler | 27 | + | sched *mocks.MaintenanceScheduler |
| 29 | pushes *app.Pushes | 28 | pushes *app.Pushes | ||
| 30 | } | 29 | } | ||
| 31 | 30 | ||||
| @@ -37,7 +36,7 @@ func newPushFixture(t *testing.T) *pushFixture { | |||||
| 37 | bus: mocks.NewEventBus(t), | 36 | bus: mocks.NewEventBus(t), | ||
| 38 | clock: mocks.NewClock(t), | 37 | clock: mocks.NewClock(t), | ||
| 39 | tokens: mocks.NewTokenStore(t), | 38 | tokens: mocks.NewTokenStore(t), | ||
| 40 | - | sched: appmocks.NewMaintenanceScheduler(t), | 39 | + | sched: mocks.NewMaintenanceScheduler(t), |
| 41 | } | 40 | } | ||
| 42 | f.clock.EXPECT().Now().Return(now).Maybe() | 41 | f.clock.EXPECT().Now().Return(now).Maybe() | ||
| 43 | repos := app.NewRepos(f.meta, f.git, f.bus, f.clock) | 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 | clock ports.Clock | 23 | clock ports.Clock | ||
| 24 | } | 24 | } | ||
| 25 | 25 | ||||
| 26 | + | var _ ports.RepoService = (*Repos)(nil) | |||
| 27 | + | ||||
| 26 | // NewRepos builds the repository use cases over their ports. Changes are | 28 | // NewRepos builds the repository use cases over their ports. Changes are | ||
| 27 | // published on bus. | 29 | // published on bus. | ||
| 28 | func NewRepos(meta ports.RepoMetaStore, git ports.GitRepos, bus ports.EventBus, clock ports.Clock) *Repos { | 30 | func NewRepos(meta ports.RepoMetaStore, git ports.GitRepos, bus ports.EventBus, clock ports.Clock) *Repos { | ||
| 29 | return &Repos{meta: meta, git: git, bus: bus, clock: clock} | 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 | // Create makes a repository and publishes RepoCreated: it stages a bare repository, records the | 34 | // Create makes a repository and publishes RepoCreated: it stages a bare repository, records the | ||
| 41 | // metadata (which fails with domain.ErrAlreadyExists if the name is taken, | 35 | // metadata (which fails with domain.ErrAlreadyExists if the name is taken, | ||
| 42 | // also when a concurrent Create wins) and publishes the directory. A failure | 36 | // also when a concurrent Create wins) and publishes the directory. A failure | ||
| @@ -45,7 +39,7 @@ type CreateParams struct { | |||||
| 45 | // | 39 | // | ||
| 46 | // The principal needs repo:write on the name: anonymous callers get | 40 | // The principal needs repo:write on the name: anonymous callers get | ||
| 47 | // domain.ErrUnauthenticated, other callers without it domain.ErrForbidden. | 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 | if params.Name.IsZero() { | 43 | if params.Name.IsZero() { | ||
| 50 | return domain.Repo{}, fmt.Errorf("%w: empty name", domain.ErrInvalidName) | 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 | "bnema.dev/ermite/internal/adapters/kvstore" | 20 | "bnema.dev/ermite/internal/adapters/kvstore" | ||
| 21 | "bnema.dev/ermite/internal/app" | 21 | "bnema.dev/ermite/internal/app" | ||
| 22 | "bnema.dev/ermite/internal/domain" | 22 | "bnema.dev/ermite/internal/domain" | ||
| 23 | + | "bnema.dev/ermite/internal/ports" | |||
| 23 | ) | 24 | ) | ||
| 24 | 25 | ||||
| 25 | type fixedClock struct{} | 26 | type fixedClock struct{} | ||
| @@ -56,7 +57,7 @@ func TestCreateConcurrentSameNameRealAdapters(t *testing.T) { | |||||
| 56 | wg.Add(1) | 57 | wg.Add(1) | ||
| 57 | go func() { | 58 | go func() { | ||
| 58 | defer wg.Done() | 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 | errs <- err | 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 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(nil) | 63 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(nil) | ||
| 64 | f.bus.EXPECT().Publish(ctx, domain.RepoCreated{Repo: n, Visibility: domain.VisibilityPrivate, At: now}).Return().Once() | 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 | require.NoError(t, err) | 67 | require.NoError(t, err) | ||
| 68 | assert.Equal(t, want, got) | 68 | assert.Equal(t, want, got) | ||
| 69 | }) | 69 | }) | ||
| @@ -71,7 +71,7 @@ func TestCreate(t *testing.T) { | |||||
| 71 | t.Run("anonymous is refused before anything runs", func(t *testing.T) { | 71 | t.Run("anonymous is refused before anything runs", func(t *testing.T) { | ||
| 72 | t.Parallel() | 72 | t.Parallel() | ||
| 73 | f := newFixture(t) | 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 | assert.ErrorIs(t, err, domain.ErrUnauthenticated) | 75 | assert.ErrorIs(t, err, domain.ErrUnauthenticated) | ||
| 76 | }) | 76 | }) | ||
| 77 | 77 | ||||
| @@ -81,7 +81,7 @@ func TestCreate(t *testing.T) { | |||||
| 81 | tokenPrincipal(domain.ScopeRepoWrite, "other"), | 81 | tokenPrincipal(domain.ScopeRepoWrite, "other"), | ||
| 82 | } { | 82 | } { | ||
| 83 | f := newFixture(t) | 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 | assert.ErrorIs(t, err, domain.ErrForbidden) | 85 | assert.ErrorIs(t, err, domain.ErrForbidden) | ||
| 86 | } | 86 | } | ||
| 87 | }) | 87 | }) | ||
| @@ -94,21 +94,21 @@ func TestCreate(t *testing.T) { | |||||
| 94 | f.meta.EXPECT().Create(ctx, mock.Anything).Return(nil) | 94 | f.meta.EXPECT().Create(ctx, mock.Anything).Return(nil) | ||
| 95 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(nil) | 95 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(nil) | ||
| 96 | f.bus.EXPECT().Publish(ctx, mock.Anything).Return().Once() | 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 | require.NoError(t, err) | 98 | require.NoError(t, err) | ||
| 99 | }) | 99 | }) | ||
| 100 | 100 | ||||
| 101 | t.Run("zero name is invalid", func(t *testing.T) { | 101 | t.Run("zero name is invalid", func(t *testing.T) { | ||
| 102 | t.Parallel() | 102 | t.Parallel() | ||
| 103 | f := newFixture(t) | 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 | assert.ErrorIs(t, err, domain.ErrInvalidName) | 105 | assert.ErrorIs(t, err, domain.ErrInvalidName) | ||
| 106 | }) | 106 | }) | ||
| 107 | 107 | ||||
| 108 | t.Run("unknown visibility is invalid", func(t *testing.T) { | 108 | t.Run("unknown visibility is invalid", func(t *testing.T) { | ||
| 109 | t.Parallel() | 109 | t.Parallel() | ||
| 110 | f := newFixture(t) | 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 | assert.ErrorIs(t, err, domain.ErrInvalidVisibility) | 112 | assert.ErrorIs(t, err, domain.ErrInvalidVisibility) | ||
| 113 | }) | 113 | }) | ||
| 114 | 114 | ||||
| @@ -116,7 +116,7 @@ func TestCreate(t *testing.T) { | |||||
| 116 | t.Parallel() | 116 | t.Parallel() | ||
| 117 | f := newFixture(t) | 117 | f := newFixture(t) | ||
| 118 | f.git.EXPECT().Stage(ctx).Return("", errBoom) | 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 | assert.ErrorIs(t, err, errBoom) | 120 | assert.ErrorIs(t, err, errBoom) | ||
| 121 | }) | 121 | }) | ||
| 122 | 122 | ||||
| @@ -126,7 +126,7 @@ func TestCreate(t *testing.T) { | |||||
| 126 | f.git.EXPECT().Stage(ctx).Return(ports.StagedID("s1"), nil) | 126 | f.git.EXPECT().Stage(ctx).Return(ports.StagedID("s1"), nil) | ||
| 127 | f.meta.EXPECT().Create(ctx, mock.Anything).Return(domain.ErrAlreadyExists) | 127 | f.meta.EXPECT().Create(ctx, mock.Anything).Return(domain.ErrAlreadyExists) | ||
| 128 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).Return(nil) | 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 | assert.ErrorIs(t, err, domain.ErrAlreadyExists) | 130 | assert.ErrorIs(t, err, domain.ErrAlreadyExists) | ||
| 131 | }) | 131 | }) | ||
| 132 | 132 | ||||
| @@ -139,7 +139,7 @@ func TestCreate(t *testing.T) { | |||||
| 139 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(domain.ErrAlreadyExists) | 139 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(domain.ErrAlreadyExists) | ||
| 140 | f.meta.EXPECT().Delete(mock.Anything, n).Return(nil) | 140 | f.meta.EXPECT().Delete(mock.Anything, n).Return(nil) | ||
| 141 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).Return(nil) | 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 | assert.ErrorIs(t, err, domain.ErrAlreadyExists) | 143 | assert.ErrorIs(t, err, domain.ErrAlreadyExists) | ||
| 144 | }) | 144 | }) | ||
| 145 | 145 | ||||
| @@ -152,7 +152,7 @@ func TestCreate(t *testing.T) { | |||||
| 152 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(errBoom) | 152 | f.git.EXPECT().Publish(ctx, ports.StagedID("s1"), n).Return(errBoom) | ||
| 153 | f.meta.EXPECT().Delete(mock.Anything, n).Return(nil) | 153 | f.meta.EXPECT().Delete(mock.Anything, n).Return(nil) | ||
| 154 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).Return(nil) | 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 | assert.ErrorIs(t, err, errBoom) | 156 | assert.ErrorIs(t, err, errBoom) | ||
| 157 | }) | 157 | }) | ||
| 158 | 158 | ||||
| @@ -174,7 +174,7 @@ func TestCreate(t *testing.T) { | |||||
| 174 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).RunAndReturn(func(c context.Context, _ ports.StagedID) error { | 174 | f.git.EXPECT().Discard(mock.Anything, ports.StagedID("s1")).RunAndReturn(func(c context.Context, _ ports.StagedID) error { | ||
| 175 | return c.Err() | 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 | assert.ErrorIs(t, err, errBoom) | 178 | assert.ErrorIs(t, err, errBoom) | ||
| 179 | }) | 179 | }) | ||
| 180 | } | 180 | } | ||
M internal/app/repos_write.go +6 -25
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | "github.com/bnema/zerowrap" | 12 | "github.com/bnema/zerowrap" | ||
| 13 | 13 | ||||
| 14 | "bnema.dev/ermite/internal/domain" | 14 | "bnema.dev/ermite/internal/domain" | ||
| 15 | + | "bnema.dev/ermite/internal/ports" | |||
| 15 | ) | 16 | ) | ||
| 16 | 17 | ||||
| 17 | // MaxDescriptionLen is the longest repository description, in bytes. | 18 | // MaxDescriptionLen is the longest repository description, in bytes. | ||
| @@ -33,34 +34,14 @@ func validateDescription(s string) error { | |||||
| 33 | return nil | 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 | // View adds the default branch to a repository the caller has already been | 37 | // View adds the default branch to a repository the caller has already been | ||
| 45 | // allowed to see. A repository without a directory has no default branch. | 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 | branch, err := r.git.HeadBranch(ctx, repo.Name) | 40 | branch, err := r.git.HeadBranch(ctx, repo.Name) | ||
| 48 | if err != nil && !errors.Is(err, domain.ErrNotFound) { | 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 | 44 | + | return ports.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 | |||
| 64 | } | 45 | } | ||
| 65 | 46 | ||||
| 66 | // Update changes the description, the visibility, the default branch and the | 47 | // Update changes the description, the visibility, the default branch and the | ||
| @@ -71,7 +52,7 @@ type UpdateParams struct { | |||||
| 71 | // The metadata is written first, then HEAD, and RepoUpdated is published after | 52 | // The metadata is written first, then HEAD, and RepoUpdated is published after | ||
| 72 | // both. When only the HEAD move fails, RepoUpdated is still published for the | 53 | // both. When only the HEAD move fails, RepoUpdated is still published for the | ||
| 73 | // stored metadata and the HEAD error is returned. | 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 | repo, err := lookupRepo(ctx, r.meta, name) | 56 | repo, err := lookupRepo(ctx, r.meta, name) | ||
| 76 | if err != nil { | 57 | if err != nil { | ||
| 77 | return domain.Repo{}, err | 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 | // updateMeta applies the metadata fields, retrying when a write (a push | 140 | // updateMeta applies the metadata fields, retrying when a write (a push | ||
| 160 | // recording pushed_at) gets in between. | 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 | for range pushRetries { | 143 | for range pushRetries { | ||
| 163 | repo, err := r.meta.Get(ctx, name) | 144 | repo, err := r.meta.Get(ctx, name) | ||
| 164 | if err != nil { | 145 | if err != nil { | ||
M internal/app/repos_write_test.go +11 -10
| @@ -15,6 +15,7 @@ import ( | |||||
| 15 | 15 | ||||
| 16 | "bnema.dev/ermite/internal/app" | 16 | "bnema.dev/ermite/internal/app" | ||
| 17 | "bnema.dev/ermite/internal/domain" | 17 | "bnema.dev/ermite/internal/domain" | ||
| 18 | + | "bnema.dev/ermite/internal/ports" | |||
| 18 | ) | 19 | ) | ||
| 19 | 20 | ||||
| 20 | func ptr[T any](v T) *T { return &v } | 21 | func ptr[T any](v T) *T { return &v } | ||
| @@ -36,7 +37,7 @@ func TestUpdate(t *testing.T) { | |||||
| 36 | Repo: n, At: now, Visibility: domain.VisibilityPublic, Previous: domain.VisibilityPrivate, | 37 | Repo: n, At: now, Visibility: domain.VisibilityPublic, Previous: domain.VisibilityPrivate, | ||
| 37 | }).Return().Once() | 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 | Description: ptr("new"), Visibility: ptr(domain.VisibilityPublic), | 41 | Description: ptr("new"), Visibility: ptr(domain.VisibilityPublic), | ||
| 41 | }) | 42 | }) | ||
| 42 | require.NoError(t, err) | 43 | require.NoError(t, err) | ||
| @@ -50,7 +51,7 @@ func TestUpdate(t *testing.T) { | |||||
| 50 | f.meta.EXPECT().Update(ctx, mock.Anything).Return(domain.ErrConflict).Once() | 51 | f.meta.EXPECT().Update(ctx, mock.Anything).Return(domain.ErrConflict).Once() | ||
| 51 | f.meta.EXPECT().Update(ctx, mock.Anything).Return(nil).Once() | 52 | f.meta.EXPECT().Update(ctx, mock.Anything).Return(nil).Once() | ||
| 52 | f.bus.EXPECT().Publish(ctx, mock.Anything).Return().Once() | 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 | require.NoError(t, err) | 55 | require.NoError(t, err) | ||
| 55 | }) | 56 | }) | ||
| 56 | 57 | ||||
| @@ -61,7 +62,7 @@ func TestUpdate(t *testing.T) { | |||||
| 61 | f.git.EXPECT().HasBranch(ctx, n, "dev").Return(true, nil) | 62 | f.git.EXPECT().HasBranch(ctx, n, "dev").Return(true, nil) | ||
| 62 | f.git.EXPECT().SetDefaultBranch(ctx, n, "dev").Return(nil) | 63 | f.git.EXPECT().SetDefaultBranch(ctx, n, "dev").Return(nil) | ||
| 63 | f.bus.EXPECT().Publish(ctx, mock.Anything).Return().Once() | 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 | require.NoError(t, err) | 66 | require.NoError(t, err) | ||
| 66 | assert.Equal(t, priv, got) | 67 | assert.Equal(t, priv, got) | ||
| 67 | }) | 68 | }) | ||
| @@ -81,7 +82,7 @@ func TestUpdate(t *testing.T) { | |||||
| 81 | return nil | 82 | return nil | ||
| 82 | }) | 83 | }) | ||
| 83 | f.bus.EXPECT().Publish(ctx, mock.Anything).Run(func(context.Context, domain.Event) { order = append(order, "event") }).Return().Once() | 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 | require.NoError(t, err) | 86 | require.NoError(t, err) | ||
| 86 | assert.Equal(t, []string{"meta", "head", "event"}, order) | 87 | assert.Equal(t, []string{"meta", "head", "event"}, order) | ||
| 87 | }) | 88 | }) | ||
| @@ -98,7 +99,7 @@ func TestUpdate(t *testing.T) { | |||||
| 98 | f.bus.EXPECT().Publish(ctx, domain.RepoUpdated{ | 99 | f.bus.EXPECT().Publish(ctx, domain.RepoUpdated{ | ||
| 99 | Repo: n, At: now, Visibility: domain.VisibilityPrivate, Previous: domain.VisibilityPublic, | 100 | Repo: n, At: now, Visibility: domain.VisibilityPrivate, Previous: domain.VisibilityPublic, | ||
| 100 | }).Return().Once() | 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 | assert.ErrorIs(t, err, boom) | 103 | assert.ErrorIs(t, err, boom) | ||
| 103 | }) | 104 | }) | ||
| 104 | 105 | ||||
| @@ -109,7 +110,7 @@ func TestUpdate(t *testing.T) { | |||||
| 109 | f.meta.EXPECT().Get(ctx, n).Return(priv, nil) | 110 | f.meta.EXPECT().Get(ctx, n).Return(priv, nil) | ||
| 110 | f.git.EXPECT().HasBranch(ctx, n, "dev").Return(true, nil) | 111 | f.git.EXPECT().HasBranch(ctx, n, "dev").Return(true, nil) | ||
| 111 | f.git.EXPECT().SetDefaultBranch(ctx, n, "dev").Return(boom) | 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 | assert.ErrorIs(t, err, boom) | 114 | assert.ErrorIs(t, err, boom) | ||
| 114 | }) | 115 | }) | ||
| 115 | 116 | ||||
| @@ -118,12 +119,12 @@ func TestUpdate(t *testing.T) { | |||||
| 118 | f := newFixture(t) | 119 | f := newFixture(t) | ||
| 119 | f.meta.EXPECT().Get(ctx, n).Return(priv, nil) | 120 | f.meta.EXPECT().Get(ctx, n).Return(priv, nil) | ||
| 120 | f.git.EXPECT().HasBranch(ctx, n, "nope").Return(false, nil) | 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 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | 123 | assert.ErrorIs(t, err, domain.ErrPreconditionFailed) | ||
| 123 | }) | 124 | }) | ||
| 124 | 125 | ||||
| 125 | t.Run("invalid input changes nothing", func(t *testing.T) { | 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 | "empty": {}, | 128 | "empty": {}, | ||
| 128 | "empty branch": {DefaultBranch: ptr("")}, | 129 | "empty branch": {DefaultBranch: ptr("")}, | ||
| 129 | "multi-line": {Description: ptr("a\nb")}, | 130 | "multi-line": {Description: ptr("a\nb")}, | ||
| @@ -157,7 +158,7 @@ func TestUpdate(t *testing.T) { | |||||
| 157 | t.Parallel() | 158 | t.Parallel() | ||
| 158 | f := newFixture(t) | 159 | f := newFixture(t) | ||
| 159 | f.meta.EXPECT().Get(ctx, n).Return(tt.repo, nil) | 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 | assert.ErrorIs(t, err, tt.want) | 162 | assert.ErrorIs(t, err, tt.want) | ||
| 162 | err = f.repos.Delete(ctx, tt.p, n) | 163 | err = f.repos.Delete(ctx, tt.p, n) | ||
| 163 | assert.ErrorIs(t, err, tt.want) | 164 | assert.ErrorIs(t, err, tt.want) | ||
| @@ -168,7 +169,7 @@ func TestUpdate(t *testing.T) { | |||||
| 168 | t.Parallel() | 169 | t.Parallel() | ||
| 169 | f := newFixture(t) | 170 | f := newFixture(t) | ||
| 170 | f.meta.EXPECT().Get(ctx, n).Return(domain.Repo{}, domain.ErrNotFound) | 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 | assert.ErrorIs(t, err, domain.ErrNotFound) | 173 | assert.ErrorIs(t, err, domain.ErrNotFound) | ||
| 173 | }) | 174 | }) | ||
| 174 | } | 175 | } | ||
M internal/app/sessions.go +7 -12
| @@ -39,13 +39,6 @@ const ( | |||||
| 39 | LoginPath = "/-/login/" | 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 | // Sessions are the use cases of the owner's browser sessions: login links, | 42 | // Sessions are the use cases of the owner's browser sessions: login links, | ||
| 50 | // session tokens and signing out everywhere. Login links live in memory only, | 43 | // session tokens and signing out everywhere. Login links live in memory only, | ||
| 51 | // so a restart voids them; the signing key and the epoch are in the store. | 44 | // so a restart voids them; the signing key and the epoch are in the store. | ||
| @@ -59,6 +52,8 @@ type Sessions struct { | |||||
| 59 | links map[[sha256.Size]byte]pendingLink // by hash of the nonce | 52 | links map[[sha256.Size]byte]pendingLink // by hash of the nonce | ||
| 60 | } | 53 | } | ||
| 61 | 54 | ||||
| 55 | + | var _ ports.SessionService = (*Sessions)(nil) | |||
| 56 | + | ||||
| 62 | // pendingLink is a login link that waits to be used. | 57 | // pendingLink is a login link that waits to be used. | ||
| 63 | type pendingLink struct { | 58 | type pendingLink struct { | ||
| 64 | expires time.Time | 59 | expires time.Time | ||
| @@ -95,13 +90,13 @@ func requireOwner(p domain.Principal) error { | |||||
| 95 | // created it: it is capped at that token's expiry (no cap for root, or a token | 90 | // created it: it is capped at that token's expiry (no cap for root, or a token | ||
| 96 | // that never expires). It gives domain.ErrResourceExhausted when MaxPendingLoginLinks | 91 | // that never expires). It gives domain.ErrResourceExhausted when MaxPendingLoginLinks | ||
| 97 | // links wait. The nonce is never logged. | 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 | if err := requireOwner(p); err != nil { | 94 | if err := requireOwner(p); err != nil { | ||
| 100 | - | return LoginLink{}, err | 95 | + | return ports.LoginLink{}, err |
| 101 | } | 96 | } | ||
| 102 | var raw [loginNonceBytes]byte | 97 | var raw [loginNonceBytes]byte | ||
| 103 | if _, err := rand.Read(raw[:]); err != nil { | 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 | nonce := base64.RawURLEncoding.EncodeToString(raw[:]) | 101 | nonce := base64.RawURLEncoding.EncodeToString(raw[:]) | ||
| 107 | now := s.clock.Now() | 102 | now := s.clock.Now() | ||
| @@ -115,14 +110,14 @@ func (s *Sessions) CreateLoginLink(ctx context.Context, p domain.Principal) (Log | |||||
| 115 | } | 110 | } | ||
| 116 | if len(s.links) >= MaxPendingLoginLinks { | 111 | if len(s.links) >= MaxPendingLoginLinks { | ||
| 117 | s.mu.Unlock() | 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 | s.links[sha256.Sum256([]byte(nonce))] = pendingLink{expires: exp, sessionCap: p.ExpiresAt()} | 115 | s.links[sha256.Sum256([]byte(nonce))] = pendingLink{expires: exp, sessionCap: p.ExpiresAt()} | ||
| 121 | s.mu.Unlock() | 116 | s.mu.Unlock() | ||
| 122 | 117 | ||||
| 123 | log := zerowrap.FromCtx(ctx) | 118 | log := zerowrap.FromCtx(ctx) | ||
| 124 | log.Info().Str("created_by", p.Label()).Str("created_by_token", p.TokenID()).Time("expires_at", exp).Msg("login link created") | 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 | // LoginLinkValid reports whether the nonce is a pending link, without using | 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 | committer domain.Identity | 14 | committer domain.Identity | ||
| 15 | } | 15 | } | ||
| 16 | 16 | ||||
| 17 | + | var _ ports.SigningKeyService = (*SigningKey)(nil) | |||
| 18 | + | ||||
| 17 | // NewSigningKey builds the use case over the signer and the identity recorded | 19 | // NewSigningKey builds the use case over the signer and the identity recorded | ||
| 18 | // as the committer of the signed commits. | 20 | // as the committer of the signed commits. | ||
| 19 | func NewSigningKey(signer ports.CommitSigner, committer domain.Identity) *SigningKey { | 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 | sessions ports.SessionStore | 40 | sessions ports.SessionStore | ||
| 41 | } | 41 | } | ||
| 42 | 42 | ||||
| 43 | + | var _ ports.TokenService = (*Tokens)(nil) | |||
| 44 | + | ||||
| 43 | // NewTokens builds the token use cases over their ports. sessions is where | 45 | // NewTokens builds the token use cases over their ports. sessions is where | ||
| 44 | // revoking a token with owner rights ends every web session (see Revoke). | 46 | // revoking a token with owner rights ends every web session (see Revoke). | ||
| 45 | func NewTokens(store ports.TokenStore, clock ports.Clock, sessions ports.SessionStore) *Tokens { | 47 | func NewTokens(store ports.TokenStore, clock ports.Clock, sessions ports.SessionStore) *Tokens { | ||
| 46 | return &Tokens{store: store, clock: clock, sessions: sessions} | 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 | // Create makes a stored token and returns it with its secret. | 51 | // Create makes a stored token and returns it with its secret. | ||
| 68 | // | 52 | // | ||
| 69 | // The principal needs token:admin: anonymous callers get | 53 | // The principal needs token:admin: anonymous callers get | ||
| @@ -75,20 +59,20 @@ type CreatedToken struct { | |||||
| 75 | // domain.ErrInvalidToken (this includes the labels "owner" and "root", which | 59 | // domain.ErrInvalidToken (this includes the labels "owner" and "root", which | ||
| 76 | // are reserved, in any case and around spaces), an unknown scope | 60 | // are reserved, in any case and around spaces), an unknown scope | ||
| 77 | // domain.ErrInvalidScope. | 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 | if p.IsAnonymous() { | 63 | if p.IsAnonymous() { | ||
| 80 | - | return CreatedToken{}, domain.ErrUnauthenticated | 64 | + | return ports.CreatedToken{}, domain.ErrUnauthenticated |
| 81 | } | 65 | } | ||
| 82 | if !canManageTokens(p) { | 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 | now := t.clock.Now().UTC() | 69 | now := t.clock.Now().UTC() | ||
| 86 | tok, err := buildToken(params, now) | 70 | tok, err := buildToken(params, now) | ||
| 87 | if err != nil { | 71 | if err != nil { | ||
| 88 | - | return CreatedToken{}, err | 72 | + | return ports.CreatedToken{}, err |
| 89 | } | 73 | } | ||
| 90 | if err := checkNoEscalation(p, tok); err != nil { | 74 | if err := checkNoEscalation(p, tok); err != nil { | ||
| 91 | - | return CreatedToken{}, err | 75 | + | return ports.CreatedToken{}, err |
| 92 | } | 76 | } | ||
| 93 | 77 | ||||
| 94 | for range 3 { | 78 | for range 3 { | ||
| @@ -99,7 +83,7 @@ func (t *Tokens) Create(ctx context.Context, p domain.Principal, params CreateTo | |||||
| 99 | continue // a random id or secret collided: practically never | 83 | continue // a random id or secret collided: practically never | ||
| 100 | } | 84 | } | ||
| 101 | if err != nil { | 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 | log := zerowrap.FromCtx(ctx) | 88 | log := zerowrap.FromCtx(ctx) | ||
| 105 | log.Info(). | 89 | log.Info(). | ||
| @@ -107,13 +91,13 @@ func (t *Tokens) Create(ctx context.Context, p domain.Principal, params CreateTo | |||||
| 107 | Int("scopes", len(tok.Scopes)).Int("repos", len(tok.Repos)). | 91 | Int("scopes", len(tok.Scopes)).Int("repos", len(tok.Repos)). | ||
| 108 | Str("created_by", p.Label()).Str("created_by_token", p.TokenID()). | 92 | Str("created_by", p.Label()).Str("created_by_token", p.TokenID()). | ||
| 109 | Msg("token created") | 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 | // buildToken validates the settings and returns the token without id and hash. | 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 | if params.Label == "" || len(params.Label) > MaxTokenLabelLen || !utf8.ValidString(params.Label) { | 101 | if params.Label == "" || len(params.Label) > MaxTokenLabelLen || !utf8.ValidString(params.Label) { | ||
| 118 | return domain.Token{}, fmt.Errorf("%w: label must be 1 to %d bytes of UTF-8", domain.ErrInvalidToken, MaxTokenLabelLen) | 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 | clock ports.Clock | 258 | clock ports.Clock | ||
| 275 | } | 259 | } | ||
| 276 | 260 | ||||
| 261 | + | var ( | |||
| 262 | + | _ ports.AuthService = (*Auth)(nil) | |||
| 263 | + | _ ports.Revalidator = (*Auth)(nil) | |||
| 264 | + | ) | |||
| 265 | + | ||||
| 277 | // NewAuth builds the authentication use case. rootHash is the SHA-256 of the | 266 | // NewAuth builds the authentication use case. rootHash is the SHA-256 of the | ||
| 278 | // admin token. | 267 | // admin token. | ||
| 279 | func NewAuth(rootHash domain.TokenHash, tokens ports.TokenStore, clock ports.Clock) *Auth { | 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 | "bnema.dev/ermite/internal/app" | 17 | "bnema.dev/ermite/internal/app" | ||
| 18 | "bnema.dev/ermite/internal/domain" | 18 | "bnema.dev/ermite/internal/domain" | ||
| 19 | + | "bnema.dev/ermite/internal/ports" | |||
| 19 | "bnema.dev/ermite/internal/ports/mocks" | 20 | "bnema.dev/ermite/internal/ports/mocks" | ||
| 20 | ) | 21 | ) | ||
| 21 | 22 | ||||
| @@ -65,7 +66,7 @@ func TestTokensCreateAllowsLabelsNearReserved(t *testing.T) { | |||||
| 65 | t.Parallel() | 66 | t.Parallel() | ||
| 66 | f := newTokenFixture(t) | 67 | f := newTokenFixture(t) | ||
| 67 | f.store.EXPECT().Create(ctx, mock.Anything).Return(nil) | 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 | assert.NoError(t, err) | 70 | assert.NoError(t, err) | ||
| 70 | }) | 71 | }) | ||
| 71 | } | 72 | } | ||
| @@ -82,7 +83,7 @@ func TestTokensCreate(t *testing.T) { | |||||
| 82 | f.store.EXPECT().Create(ctx, mock.Anything).Run(func(_ context.Context, tok domain.Token) { stored = tok }).Return(nil) | 83 | f.store.EXPECT().Create(ctx, mock.Anything).Run(func(_ context.Context, tok domain.Token) { stored = tok }).Return(nil) | ||
| 83 | 84 | ||||
| 84 | exp := now.Add(48 * time.Hour) | 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 | Label: "ci", | 87 | Label: "ci", | ||
| 87 | Scopes: scopes(domain.ScopeRepoWrite, domain.ScopeRepoRead, domain.ScopeRepoRead), | 88 | Scopes: scopes(domain.ScopeRepoWrite, domain.ScopeRepoRead, domain.ScopeRepoRead), | ||
| 88 | Repos: names(t, "b", "a", "b"), | 89 | Repos: names(t, "b", "a", "b"), | ||
| @@ -109,9 +110,9 @@ func TestTokensCreate(t *testing.T) { | |||||
| 109 | t.Parallel() | 110 | t.Parallel() | ||
| 110 | f := newTokenFixture(t) | 111 | f := newTokenFixture(t) | ||
| 111 | f.store.EXPECT().Create(ctx, mock.Anything).Return(nil) | 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 | require.NoError(t, err) | 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 | require.NoError(t, err) | 116 | require.NoError(t, err) | ||
| 116 | assert.NotEqual(t, a.Secret, b.Secret) | 117 | assert.NotEqual(t, a.Secret, b.Secret) | ||
| 117 | assert.NotEqual(t, a.Token.ID, b.Token.ID) | 118 | assert.NotEqual(t, a.Token.ID, b.Token.ID) | ||
| @@ -122,7 +123,7 @@ func TestTokensCreate(t *testing.T) { | |||||
| 122 | f := newTokenFixture(t) | 123 | f := newTokenFixture(t) | ||
| 123 | f.store.EXPECT().Create(ctx, mock.Anything).Return(domain.ErrAlreadyExists).Once() | 124 | f.store.EXPECT().Create(ctx, mock.Anything).Return(domain.ErrAlreadyExists).Once() | ||
| 124 | f.store.EXPECT().Create(ctx, mock.Anything).Return(nil).Once() | 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 | require.NoError(t, err) | 127 | require.NoError(t, err) | ||
| 127 | }) | 128 | }) | ||
| 128 | 129 | ||||
| @@ -131,27 +132,27 @@ func TestTokensCreate(t *testing.T) { | |||||
| 131 | f := newTokenFixture(t) | 132 | f := newTokenFixture(t) | ||
| 132 | boom := errors.New("boom") | 133 | boom := errors.New("boom") | ||
| 133 | f.store.EXPECT().Create(ctx, mock.Anything).Return(boom) | 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 | assert.ErrorIs(t, err, boom) | 136 | assert.ErrorIs(t, err, boom) | ||
| 136 | }) | 137 | }) | ||
| 137 | 138 | ||||
| 138 | invalid := []struct { | 139 | invalid := []struct { | ||
| 139 | name string | 140 | name string | ||
| 140 | - | params app.CreateTokenParams | 141 | + | params ports.CreateTokenParams |
| 141 | want error | 142 | want error | ||
| 142 | }{ | 143 | }{ | ||
| 143 | - | {"empty label", app.CreateTokenParams{Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | 144 | + | {"empty label", ports.CreateTokenParams{Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, |
| 144 | - | {"long label", app.CreateTokenParams{Label: strings.Repeat("x", 101), Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | 145 | + | {"long label", ports.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 | + | {"bad utf8 label", ports.CreateTokenParams{Label: "\xff", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, |
| 146 | - | {"reserved owner", app.CreateTokenParams{Label: "owner", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | 147 | + | {"reserved owner", ports.CreateTokenParams{Label: "owner", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, |
| 147 | - | {"reserved root", app.CreateTokenParams{Label: "root", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | 148 | + | {"reserved root", ports.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, upper case", ports.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, mixed case", ports.CreateTokenParams{Label: "Root", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, |
| 150 | - | {"reserved, padded", app.CreateTokenParams{Label: " \towner \n", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, | 151 | + | {"reserved, padded", ports.CreateTokenParams{Label: " \towner \n", Scopes: scopes(domain.ScopeRepoRead)}, domain.ErrInvalidToken}, |
| 151 | - | {"no scopes", app.CreateTokenParams{Label: "x"}, domain.ErrInvalidToken}, | 152 | + | {"no scopes", ports.CreateTokenParams{Label: "x"}, domain.ErrInvalidToken}, |
| 152 | - | {"unknown scope", app.CreateTokenParams{Label: "x", Scopes: scopes("nope")}, domain.ErrInvalidScope}, | 153 | + | {"unknown scope", ports.CreateTokenParams{Label: "x", Scopes: scopes("nope")}, domain.ErrInvalidScope}, |
| 153 | - | {"past expiry", app.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), ExpiresAt: now}, domain.ErrInvalidToken}, | 154 | + | {"past expiry", ports.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}, | 155 | + | {"zero repo name", ports.CreateTokenParams{Label: "x", Scopes: scopes(domain.ScopeRepoRead), Repos: []domain.RepoName{{}}}, domain.ErrInvalidToken}, |
| 155 | } | 156 | } | ||
| 156 | for _, tt := range invalid { | 157 | for _, tt := range invalid { | ||
| 157 | t.Run("invalid/"+tt.name, func(t *testing.T) { | 158 | t.Run("invalid/"+tt.name, func(t *testing.T) { | ||
| @@ -179,37 +180,37 @@ func TestTokensCreateNoEscalation(t *testing.T) { | |||||
| 179 | tests := []struct { | 180 | tests := []struct { | ||
| 180 | name string | 181 | name string | ||
| 181 | principal domain.Principal | 182 | principal domain.Principal | ||
| 182 | - | params app.CreateTokenParams | 183 | + | params ports.CreateTokenParams |
| 183 | want error // nil = allowed | 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 | {"token without token:admin", | 187 | {"token without token:admin", | ||
| 187 | domain.TokenPrincipal(domain.Token{Scopes: scopes(domain.ScopeRepoWrite)}), | 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 | {"subset of scopes", admin(nil, time.Time{}), | 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 | {"same scopes incl. token:admin", admin(nil, time.Time{}), | 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 | {"scope it lacks", admin(nil, time.Time{}), | 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 | {"limited creator, same repos", admin(names(t, "a", "b"), time.Time{}), | 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 | {"limited creator, repo outside its list", admin(names(t, "a"), time.Time{}), | 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 | {"limited creator, unlimited child", admin(names(t, "a"), time.Time{}), | 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 | {"unlimited creator may limit", admin(nil, time.Time{}), | 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 | {"expiring creator, child never expires", admin(nil, exp), | 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 | {"expiring creator, child outlasts", admin(nil, exp), | 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 | {"expiring creator, child within", admin(nil, exp), | 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 | {"expiring creator, child same expiry", admin(nil, exp), | 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 | {"root: everything", domain.Root(), | 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 | for _, tt := range tests { | 215 | for _, tt := range tests { | ||
| 215 | t.Run(tt.name, func(t *testing.T) { | 216 | t.Run(tt.name, func(t *testing.T) { | ||
M internal/clientlimit/limiter.go +4 -0
| @@ -16,6 +16,8 @@ import ( | |||||
| 16 | "time" | 16 | "time" | ||
| 17 | 17 | ||||
| 18 | "github.com/bnema/zerowrap" | 18 | "github.com/bnema/zerowrap" | ||
| 19 | + | ||||
| 20 | + | "bnema.dev/ermite/internal/ports" | |||
| 19 | ) | 21 | ) | ||
| 20 | 22 | ||||
| 21 | // Limiter defaults: 10 failed authentications in 10 minutes block the client | 23 | // Limiter defaults: 10 failed authentications in 10 minutes block the client | ||
| @@ -54,6 +56,8 @@ type Limiter struct { | |||||
| 54 | lastSweep time.Time | 56 | lastSweep time.Time | ||
| 55 | } | 57 | } | ||
| 56 | 58 | ||||
| 59 | + | var _ ports.FailureLimiter = (*Limiter)(nil) | |||
| 60 | + | ||||
| 57 | // NewLimiter builds a limiter. now defaults to time.Now. | 61 | // NewLimiter builds a limiter. now defaults to time.Now. | ||
| 58 | func NewLimiter(now func() time.Time) *Limiter { | 62 | func NewLimiter(now func() time.Time) *Limiter { | ||
| 59 | if now == nil { | 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 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 15 | // The first argument is typically a *testing.T value. | ||
| 16 | - | func NewAuthenticator(t interface { | 16 | + | func NewAuthService(t interface { |
| 17 | mock.TestingT | 17 | mock.TestingT | ||
| 18 | Cleanup(func()) | 18 | Cleanup(func()) | ||
| 19 | - | }) *Authenticator { | 19 | + | }) *AuthService { |
| 20 | if helper, ok := t.(interface{ Helper() }); ok { | 20 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 21 | helper.Helper() | 21 | helper.Helper() | ||
| 22 | } | 22 | } | ||
| 23 | 23 | ||||
| 24 | - | mock := &Authenticator{} | 24 | + | mock := &AuthService{} |
| 25 | mock.Mock.Test(t) | 25 | mock.Mock.Test(t) | ||
| 26 | 26 | ||||
| 27 | t.Cleanup(func() { | 27 | t.Cleanup(func() { | ||
| @@ -34,21 +34,21 @@ func NewAuthenticator(t interface { | |||||
| 34 | return mock | 34 | return mock | ||
| 35 | } | 35 | } | ||
| 36 | 36 | ||||
| 37 | - | // Authenticator is an autogenerated mock type for the Authenticator type | 37 | + | // AuthService is an autogenerated mock type for the AuthService type |
| 38 | - | type Authenticator struct { | 38 | + | type AuthService struct { |
| 39 | mock.Mock | 39 | mock.Mock | ||
| 40 | } | 40 | } | ||
| 41 | 41 | ||||
| 42 | - | type Authenticator_Expecter struct { | 42 | + | type AuthService_Expecter struct { |
| 43 | mock *mock.Mock | 43 | mock *mock.Mock | ||
| 44 | } | 44 | } | ||
| 45 | 45 | ||||
| 46 | - | func (_m *Authenticator) EXPECT() *Authenticator_Expecter { | 46 | + | func (_m *AuthService) EXPECT() *AuthService_Expecter { |
| 47 | - | return &Authenticator_Expecter{mock: &_m.Mock} | 47 | + | return &AuthService_Expecter{mock: &_m.Mock} |
| 48 | } | 48 | } | ||
| 49 | 49 | ||||
| 50 | - | // Authenticate provides a mock function for the type Authenticator | 50 | + | // Authenticate provides a mock function for the type AuthService |
| 51 | - | func (_mock *Authenticator) Authenticate(ctx context.Context, secret string) (domain.Principal, error) { | 51 | + | func (_mock *AuthService) Authenticate(ctx context.Context, secret string) (domain.Principal, error) { |
| 52 | ret := _mock.Called(ctx, secret) | 52 | ret := _mock.Called(ctx, secret) | ||
| 53 | 53 | ||||
| 54 | if len(ret) == 0 { | 54 | if len(ret) == 0 { | ||
| @@ -73,19 +73,19 @@ func (_mock *Authenticator) Authenticate(ctx context.Context, secret string) (do | |||||
| 73 | return r0, r1 | 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' | 76 | + | // AuthService_Authenticate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Authenticate' |
| 77 | - | type Authenticator_Authenticate_Call struct { | 77 | + | type AuthService_Authenticate_Call struct { |
| 78 | *mock.Call | 78 | *mock.Call | ||
| 79 | } | 79 | } | ||
| 80 | 80 | ||||
| 81 | // Authenticate is a helper method to define mock.On call | 81 | // Authenticate is a helper method to define mock.On call | ||
| 82 | // - ctx context.Context | 82 | // - ctx context.Context | ||
| 83 | // - secret string | 83 | // - secret string | ||
| 84 | - | func (_e *Authenticator_Expecter) Authenticate(ctx any, secret any) *Authenticator_Authenticate_Call { | 84 | + | func (_e *AuthService_Expecter) Authenticate(ctx any, secret any) *AuthService_Authenticate_Call { |
| 85 | - | return &Authenticator_Authenticate_Call{Call: _e.mock.On("Authenticate", ctx, secret)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 89 | _c.Call.Run(func(args mock.Arguments) { | ||
| 90 | var arg0 context.Context | 90 | var arg0 context.Context | ||
| 91 | if args[0] != nil { | 91 | if args[0] != nil { | ||
| @@ -103,12 +103,12 @@ func (_c *Authenticator_Authenticate_Call) Run(run func(ctx context.Context, sec | |||||
| 103 | return _c | 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 | _c.Call.Return(principal, err) | 107 | _c.Call.Return(principal, err) | ||
| 108 | return _c | 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 | _c.Call.Return(run) | 112 | _c.Call.Return(run) | ||
| 113 | return _c | 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 | "context" | 8 | "context" | ||
| 9 | "io" | 9 | "io" | ||
| 10 | 10 | ||||
| 11 | - | "bnema.dev/ermite/internal/app" | |||
| 12 | "bnema.dev/ermite/internal/domain" | 11 | "bnema.dev/ermite/internal/domain" | ||
| 12 | + | "bnema.dev/ermite/internal/ports" | |||
| 13 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 17 | // The first argument is typically a *testing.T value. | ||
| 18 | - | func NewBrowse(t interface { | 18 | + | func NewBrowseService(t interface { |
| 19 | mock.TestingT | 19 | mock.TestingT | ||
| 20 | Cleanup(func()) | 20 | Cleanup(func()) | ||
| 21 | - | }) *Browse { | 21 | + | }) *BrowseService { |
| 22 | if helper, ok := t.(interface{ Helper() }); ok { | 22 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 23 | helper.Helper() | 23 | helper.Helper() | ||
| 24 | } | 24 | } | ||
| 25 | 25 | ||||
| 26 | - | mock := &Browse{} | 26 | + | mock := &BrowseService{} |
| 27 | mock.Mock.Test(t) | 27 | mock.Mock.Test(t) | ||
| 28 | 28 | ||||
| 29 | t.Cleanup(func() { | 29 | t.Cleanup(func() { | ||
| @@ -36,21 +36,21 @@ func NewBrowse(t interface { | |||||
| 36 | return mock | 36 | return mock | ||
| 37 | } | 37 | } | ||
| 38 | 38 | ||||
| 39 | - | // Browse is an autogenerated mock type for the Browse type | 39 | + | // BrowseService is an autogenerated mock type for the BrowseService type |
| 40 | - | type Browse struct { | 40 | + | type BrowseService struct { |
| 41 | mock.Mock | 41 | mock.Mock | ||
| 42 | } | 42 | } | ||
| 43 | 43 | ||||
| 44 | - | type Browse_Expecter struct { | 44 | + | type BrowseService_Expecter struct { |
| 45 | mock *mock.Mock | 45 | mock *mock.Mock | ||
| 46 | } | 46 | } | ||
| 47 | 47 | ||||
| 48 | - | func (_m *Browse) EXPECT() *Browse_Expecter { | 48 | + | func (_m *BrowseService) EXPECT() *BrowseService_Expecter { |
| 49 | - | return &Browse_Expecter{mock: &_m.Mock} | 49 | + | return &BrowseService_Expecter{mock: &_m.Mock} |
| 50 | } | 50 | } | ||
| 51 | 51 | ||||
| 52 | - | // GetCommit provides a mock function for the type Browse | 52 | + | // GetCommit provides a mock function for the type BrowseService |
| 53 | - | func (_mock *Browse) GetCommit(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error) { | 53 | + | func (_mock *BrowseService) GetCommit(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.CommitDetail, error) { |
| 54 | ret := _mock.Called(ctx, p, repo, rev) | 54 | ret := _mock.Called(ctx, p, repo, rev) | ||
| 55 | 55 | ||||
| 56 | if len(ret) == 0 { | 56 | if len(ret) == 0 { | ||
| @@ -75,8 +75,8 @@ func (_mock *Browse) GetCommit(ctx context.Context, p domain.Principal, repo dom | |||||
| 75 | return r0, r1 | 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' | 78 | + | // BrowseService_GetCommit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommit' |
| 79 | - | type Browse_GetCommit_Call struct { | 79 | + | type BrowseService_GetCommit_Call struct { |
| 80 | *mock.Call | 80 | *mock.Call | ||
| 81 | } | 81 | } | ||
| 82 | 82 | ||||
| @@ -85,11 +85,11 @@ type Browse_GetCommit_Call struct { | |||||
| 85 | // - p domain.Principal | 85 | // - p domain.Principal | ||
| 86 | // - repo domain.RepoName | 86 | // - repo domain.RepoName | ||
| 87 | // - rev domain.Revision | 87 | // - rev domain.Revision | ||
| 88 | - | func (_e *Browse_Expecter) GetCommit(ctx any, p any, repo any, rev any) *Browse_GetCommit_Call { | 88 | + | func (_e *BrowseService_Expecter) GetCommit(ctx any, p any, repo any, rev any) *BrowseService_GetCommit_Call { |
| 89 | - | return &Browse_GetCommit_Call{Call: _e.mock.On("GetCommit", ctx, p, repo, rev)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 93 | _c.Call.Run(func(args mock.Arguments) { | ||
| 94 | var arg0 context.Context | 94 | var arg0 context.Context | ||
| 95 | if args[0] != nil { | 95 | if args[0] != nil { | ||
| @@ -117,18 +117,18 @@ func (_c *Browse_GetCommit_Call) Run(run func(ctx context.Context, p domain.Prin | |||||
| 117 | return _c | 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 | _c.Call.Return(commitDetail, err) | 121 | _c.Call.Return(commitDetail, err) | ||
| 122 | return _c | 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 | _c.Call.Return(run) | 126 | _c.Call.Return(run) | ||
| 127 | return _c | 127 | return _c | ||
| 128 | } | 128 | } | ||
| 129 | 129 | ||||
| 130 | - | // GetTree provides a mock function for the type Browse | 130 | + | // GetTree provides a mock function for the type BrowseService |
| 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) { | 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 | ret := _mock.Called(ctx, p, repo, rev, path, includeLastCommit) | 132 | ret := _mock.Called(ctx, p, repo, rev, path, includeLastCommit) | ||
| 133 | 133 | ||||
| 134 | if len(ret) == 0 { | 134 | if len(ret) == 0 { | ||
| @@ -153,8 +153,8 @@ func (_mock *Browse) GetTree(ctx context.Context, p domain.Principal, repo domai | |||||
| 153 | return r0, r1 | 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' | 156 | + | // BrowseService_GetTree_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetTree' |
| 157 | - | type Browse_GetTree_Call struct { | 157 | + | type BrowseService_GetTree_Call struct { |
| 158 | *mock.Call | 158 | *mock.Call | ||
| 159 | } | 159 | } | ||
| 160 | 160 | ||||
| @@ -165,11 +165,11 @@ type Browse_GetTree_Call struct { | |||||
| 165 | // - rev domain.Revision | 165 | // - rev domain.Revision | ||
| 166 | // - path domain.TreePath | 166 | // - path domain.TreePath | ||
| 167 | // - includeLastCommit bool | 167 | // - includeLastCommit bool | ||
| 168 | - | func (_e *Browse_Expecter) GetTree(ctx any, p any, repo any, rev any, path any, includeLastCommit any) *Browse_GetTree_Call { | 168 | + | func (_e *BrowseService_Expecter) GetTree(ctx any, p any, repo any, rev any, path any, includeLastCommit any) *BrowseService_GetTree_Call { |
| 169 | - | return &Browse_GetTree_Call{Call: _e.mock.On("GetTree", ctx, p, repo, rev, path, includeLastCommit)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 173 | _c.Call.Run(func(args mock.Arguments) { | ||
| 174 | var arg0 context.Context | 174 | var arg0 context.Context | ||
| 175 | if args[0] != nil { | 175 | if args[0] != nil { | ||
| @@ -207,35 +207,35 @@ func (_c *Browse_GetTree_Call) Run(run func(ctx context.Context, p domain.Princi | |||||
| 207 | return _c | 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 | _c.Call.Return(tree, err) | 211 | _c.Call.Return(tree, err) | ||
| 212 | return _c | 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 | _c.Call.Return(run) | 216 | _c.Call.Return(run) | ||
| 217 | return _c | 217 | return _c | ||
| 218 | } | 218 | } | ||
| 219 | 219 | ||||
| 220 | - | // ListCommits provides a mock function for the type Browse | 220 | + | // ListCommits provides a mock function for the type BrowseService |
| 221 | - | func (_mock *Browse) ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListCommitsParams) (app.CommitPage, error) { | 221 | + | func (_mock *BrowseService) ListCommits(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListCommitsParams) (ports.HistoryPage, error) { |
| 222 | ret := _mock.Called(ctx, p, repo, params) | 222 | ret := _mock.Called(ctx, p, repo, params) | ||
| 223 | 223 | ||||
| 224 | if len(ret) == 0 { | 224 | if len(ret) == 0 { | ||
| 225 | panic("no return value specified for ListCommits") | 225 | panic("no return value specified for ListCommits") | ||
| 226 | } | 226 | } | ||
| 227 | 227 | ||||
| 228 | - | var r0 app.CommitPage | 228 | + | var r0 ports.HistoryPage |
| 229 | var r1 error | 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 | return returnFunc(ctx, p, repo, params) | 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 | r0 = returnFunc(ctx, p, repo, params) | 234 | r0 = returnFunc(ctx, p, repo, params) | ||
| 235 | } else { | 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 | r1 = returnFunc(ctx, p, repo, params) | 239 | r1 = returnFunc(ctx, p, repo, params) | ||
| 240 | } else { | 240 | } else { | ||
| 241 | r1 = ret.Error(1) | 241 | r1 = ret.Error(1) | ||
| @@ -243,8 +243,8 @@ func (_mock *Browse) ListCommits(ctx context.Context, p domain.Principal, repo d | |||||
| 243 | return r0, r1 | 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' | 246 | + | // BrowseService_ListCommits_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListCommits' |
| 247 | - | type Browse_ListCommits_Call struct { | 247 | + | type BrowseService_ListCommits_Call struct { |
| 248 | *mock.Call | 248 | *mock.Call | ||
| 249 | } | 249 | } | ||
| 250 | 250 | ||||
| @@ -252,12 +252,12 @@ type Browse_ListCommits_Call struct { | |||||
| 252 | // - ctx context.Context | 252 | // - ctx context.Context | ||
| 253 | // - p domain.Principal | 253 | // - p domain.Principal | ||
| 254 | // - repo domain.RepoName | 254 | // - repo domain.RepoName | ||
| 255 | - | // - params app.ListCommitsParams | 255 | + | // - params ports.ListCommitsParams |
| 256 | - | func (_e *Browse_Expecter) ListCommits(ctx any, p any, repo any, params any) *Browse_ListCommits_Call { | 256 | + | func (_e *BrowseService_Expecter) ListCommits(ctx any, p any, repo any, params any) *BrowseService_ListCommits_Call { |
| 257 | - | return &Browse_ListCommits_Call{Call: _e.mock.On("ListCommits", ctx, p, repo, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 261 | _c.Call.Run(func(args mock.Arguments) { | ||
| 262 | var arg0 context.Context | 262 | var arg0 context.Context | ||
| 263 | if args[0] != nil { | 263 | if args[0] != nil { | ||
| @@ -271,9 +271,9 @@ func (_c *Browse_ListCommits_Call) Run(run func(ctx context.Context, p domain.Pr | |||||
| 271 | if args[2] != nil { | 271 | if args[2] != nil { | ||
| 272 | arg2 = args[2].(domain.RepoName) | 272 | arg2 = args[2].(domain.RepoName) | ||
| 273 | } | 273 | } | ||
| 274 | - | var arg3 app.ListCommitsParams | 274 | + | var arg3 ports.ListCommitsParams |
| 275 | if args[3] != nil { | 275 | if args[3] != nil { | ||
| 276 | - | arg3 = args[3].(app.ListCommitsParams) | 276 | + | arg3 = args[3].(ports.ListCommitsParams) |
| 277 | } | 277 | } | ||
| 278 | run( | 278 | run( | ||
| 279 | arg0, | 279 | arg0, | ||
| @@ -285,35 +285,35 @@ func (_c *Browse_ListCommits_Call) Run(run func(ctx context.Context, p domain.Pr | |||||
| 285 | return _c | 285 | return _c | ||
| 286 | } | 286 | } | ||
| 287 | 287 | ||||
| 288 | - | func (_c *Browse_ListCommits_Call) Return(commitPage app.CommitPage, err error) *Browse_ListCommits_Call { | 288 | + | func (_c *BrowseService_ListCommits_Call) Return(historyPage ports.HistoryPage, err error) *BrowseService_ListCommits_Call { |
| 289 | - | _c.Call.Return(commitPage, err) | 289 | + | _c.Call.Return(historyPage, err) |
| 290 | return _c | 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 | _c.Call.Return(run) | 294 | _c.Call.Return(run) | ||
| 295 | return _c | 295 | return _c | ||
| 296 | } | 296 | } | ||
| 297 | 297 | ||||
| 298 | - | // ListRefs provides a mock function for the type Browse | 298 | + | // ListRefs provides a mock function for the type BrowseService |
| 299 | - | func (_mock *Browse) ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params app.ListRefsParams) (app.RefPage, error) { | 299 | + | func (_mock *BrowseService) ListRefs(ctx context.Context, p domain.Principal, repo domain.RepoName, params ports.ListRefsParams) (ports.RefPage, error) { |
| 300 | ret := _mock.Called(ctx, p, repo, params) | 300 | ret := _mock.Called(ctx, p, repo, params) | ||
| 301 | 301 | ||||
| 302 | if len(ret) == 0 { | 302 | if len(ret) == 0 { | ||
| 303 | panic("no return value specified for ListRefs") | 303 | panic("no return value specified for ListRefs") | ||
| 304 | } | 304 | } | ||
| 305 | 305 | ||||
| 306 | - | var r0 app.RefPage | 306 | + | var r0 ports.RefPage |
| 307 | var r1 error | 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 | return returnFunc(ctx, p, repo, params) | 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 | r0 = returnFunc(ctx, p, repo, params) | 312 | r0 = returnFunc(ctx, p, repo, params) | ||
| 313 | } else { | 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 | r1 = returnFunc(ctx, p, repo, params) | 317 | r1 = returnFunc(ctx, p, repo, params) | ||
| 318 | } else { | 318 | } else { | ||
| 319 | r1 = ret.Error(1) | 319 | r1 = ret.Error(1) | ||
| @@ -321,8 +321,8 @@ func (_mock *Browse) ListRefs(ctx context.Context, p domain.Principal, repo doma | |||||
| 321 | return r0, r1 | 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' | 324 | + | // BrowseService_ListRefs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRefs' |
| 325 | - | type Browse_ListRefs_Call struct { | 325 | + | type BrowseService_ListRefs_Call struct { |
| 326 | *mock.Call | 326 | *mock.Call | ||
| 327 | } | 327 | } | ||
| 328 | 328 | ||||
| @@ -330,12 +330,12 @@ type Browse_ListRefs_Call struct { | |||||
| 330 | // - ctx context.Context | 330 | // - ctx context.Context | ||
| 331 | // - p domain.Principal | 331 | // - p domain.Principal | ||
| 332 | // - repo domain.RepoName | 332 | // - repo domain.RepoName | ||
| 333 | - | // - params app.ListRefsParams | 333 | + | // - params ports.ListRefsParams |
| 334 | - | func (_e *Browse_Expecter) ListRefs(ctx any, p any, repo any, params any) *Browse_ListRefs_Call { | 334 | + | func (_e *BrowseService_Expecter) ListRefs(ctx any, p any, repo any, params any) *BrowseService_ListRefs_Call { |
| 335 | - | return &Browse_ListRefs_Call{Call: _e.mock.On("ListRefs", ctx, p, repo, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 339 | _c.Call.Run(func(args mock.Arguments) { | ||
| 340 | var arg0 context.Context | 340 | var arg0 context.Context | ||
| 341 | if args[0] != nil { | 341 | if args[0] != nil { | ||
| @@ -349,9 +349,9 @@ func (_c *Browse_ListRefs_Call) Run(run func(ctx context.Context, p domain.Princ | |||||
| 349 | if args[2] != nil { | 349 | if args[2] != nil { | ||
| 350 | arg2 = args[2].(domain.RepoName) | 350 | arg2 = args[2].(domain.RepoName) | ||
| 351 | } | 351 | } | ||
| 352 | - | var arg3 app.ListRefsParams | 352 | + | var arg3 ports.ListRefsParams |
| 353 | if args[3] != nil { | 353 | if args[3] != nil { | ||
| 354 | - | arg3 = args[3].(app.ListRefsParams) | 354 | + | arg3 = args[3].(ports.ListRefsParams) |
| 355 | } | 355 | } | ||
| 356 | run( | 356 | run( | ||
| 357 | arg0, | 357 | arg0, | ||
| @@ -363,18 +363,18 @@ func (_c *Browse_ListRefs_Call) Run(run func(ctx context.Context, p domain.Princ | |||||
| 363 | return _c | 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 | _c.Call.Return(refPage, err) | 367 | _c.Call.Return(refPage, err) | ||
| 368 | return _c | 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 | _c.Call.Return(run) | 372 | _c.Call.Return(run) | ||
| 373 | return _c | 373 | return _c | ||
| 374 | } | 374 | } | ||
| 375 | 375 | ||||
| 376 | - | // OpenBlob provides a mock function for the type Browse | 376 | + | // OpenBlob provides a mock function for the type BrowseService |
| 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) { | 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 | ret := _mock.Called(ctx, p, repo, rev, path) | 378 | ret := _mock.Called(ctx, p, repo, rev, path) | ||
| 379 | 379 | ||||
| 380 | if len(ret) == 0 { | 380 | if len(ret) == 0 { | ||
| @@ -407,8 +407,8 @@ func (_mock *Browse) OpenBlob(ctx context.Context, p domain.Principal, repo doma | |||||
| 407 | return r0, r1, r2 | 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' | 410 | + | // BrowseService_OpenBlob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenBlob' |
| 411 | - | type Browse_OpenBlob_Call struct { | 411 | + | type BrowseService_OpenBlob_Call struct { |
| 412 | *mock.Call | 412 | *mock.Call | ||
| 413 | } | 413 | } | ||
| 414 | 414 | ||||
| @@ -418,11 +418,11 @@ type Browse_OpenBlob_Call struct { | |||||
| 418 | // - repo domain.RepoName | 418 | // - repo domain.RepoName | ||
| 419 | // - rev domain.Revision | 419 | // - rev domain.Revision | ||
| 420 | // - path domain.TreePath | 420 | // - path domain.TreePath | ||
| 421 | - | func (_e *Browse_Expecter) OpenBlob(ctx any, p any, repo any, rev any, path any) *Browse_OpenBlob_Call { | 421 | + | func (_e *BrowseService_Expecter) OpenBlob(ctx any, p any, repo any, rev any, path any) *BrowseService_OpenBlob_Call { |
| 422 | - | return &Browse_OpenBlob_Call{Call: _e.mock.On("OpenBlob", ctx, p, repo, rev, path)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 426 | _c.Call.Run(func(args mock.Arguments) { | ||
| 427 | var arg0 context.Context | 427 | var arg0 context.Context | ||
| 428 | if args[0] != nil { | 428 | if args[0] != nil { | ||
| @@ -455,18 +455,18 @@ func (_c *Browse_OpenBlob_Call) Run(run func(ctx context.Context, p domain.Princ | |||||
| 455 | return _c | 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 | _c.Call.Return(blobInfo, readCloser, err) | 459 | _c.Call.Return(blobInfo, readCloser, err) | ||
| 460 | return _c | 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 | _c.Call.Return(run) | 464 | _c.Call.Return(run) | ||
| 465 | return _c | 465 | return _c | ||
| 466 | } | 466 | } | ||
| 467 | 467 | ||||
| 468 | - | // ResolveRevision provides a mock function for the type Browse | 468 | + | // ResolveRevision provides a mock function for the type BrowseService |
| 469 | - | func (_mock *Browse) ResolveRevision(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) { | 469 | + | func (_mock *BrowseService) ResolveRevision(ctx context.Context, p domain.Principal, repo domain.RepoName, rev domain.Revision) (domain.ResolvedRevision, error) { |
| 470 | ret := _mock.Called(ctx, p, repo, rev) | 470 | ret := _mock.Called(ctx, p, repo, rev) | ||
| 471 | 471 | ||||
| 472 | if len(ret) == 0 { | 472 | if len(ret) == 0 { | ||
| @@ -491,8 +491,8 @@ func (_mock *Browse) ResolveRevision(ctx context.Context, p domain.Principal, re | |||||
| 491 | return r0, r1 | 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' | 494 | + | // BrowseService_ResolveRevision_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveRevision' |
| 495 | - | type Browse_ResolveRevision_Call struct { | 495 | + | type BrowseService_ResolveRevision_Call struct { |
| 496 | *mock.Call | 496 | *mock.Call | ||
| 497 | } | 497 | } | ||
| 498 | 498 | ||||
| @@ -501,11 +501,11 @@ type Browse_ResolveRevision_Call struct { | |||||
| 501 | // - p domain.Principal | 501 | // - p domain.Principal | ||
| 502 | // - repo domain.RepoName | 502 | // - repo domain.RepoName | ||
| 503 | // - rev domain.Revision | 503 | // - rev domain.Revision | ||
| 504 | - | func (_e *Browse_Expecter) ResolveRevision(ctx any, p any, repo any, rev any) *Browse_ResolveRevision_Call { | 504 | + | func (_e *BrowseService_Expecter) ResolveRevision(ctx any, p any, repo any, rev any) *BrowseService_ResolveRevision_Call { |
| 505 | - | return &Browse_ResolveRevision_Call{Call: _e.mock.On("ResolveRevision", ctx, p, repo, rev)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 509 | _c.Call.Run(func(args mock.Arguments) { | ||
| 510 | var arg0 context.Context | 510 | var arg0 context.Context | ||
| 511 | if args[0] != nil { | 511 | if args[0] != nil { | ||
| @@ -533,12 +533,12 @@ func (_c *Browse_ResolveRevision_Call) Run(run func(ctx context.Context, p domai | |||||
| 533 | return _c | 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 | _c.Call.Return(resolvedRevision, err) | 537 | _c.Call.Return(resolvedRevision, err) | ||
| 538 | return _c | 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 | _c.Call.Return(run) | 542 | _c.Call.Return(run) | ||
| 543 | return _c | 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 | import ( | 7 | import ( | ||
| 8 | "context" | 8 | "context" | ||
| 9 | 9 | ||||
| 10 | - | "bnema.dev/ermite/internal/app" | |||
| 11 | "bnema.dev/ermite/internal/domain" | 10 | "bnema.dev/ermite/internal/domain" | ||
| 11 | + | "bnema.dev/ermite/internal/ports" | |||
| 12 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 16 | // The first argument is typically a *testing.T value. | ||
| 17 | - | func NewMergeRequests(t interface { | 17 | + | func NewMergeRequestService(t interface { |
| 18 | mock.TestingT | 18 | mock.TestingT | ||
| 19 | Cleanup(func()) | 19 | Cleanup(func()) | ||
| 20 | - | }) *MergeRequests { | 20 | + | }) *MergeRequestService { |
| 21 | if helper, ok := t.(interface{ Helper() }); ok { | 21 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 22 | helper.Helper() | 22 | helper.Helper() | ||
| 23 | } | 23 | } | ||
| 24 | 24 | ||||
| 25 | - | mock := &MergeRequests{} | 25 | + | mock := &MergeRequestService{} |
| 26 | mock.Mock.Test(t) | 26 | mock.Mock.Test(t) | ||
| 27 | 27 | ||||
| 28 | t.Cleanup(func() { | 28 | t.Cleanup(func() { | ||
| @@ -35,21 +35,21 @@ func NewMergeRequests(t interface { | |||||
| 35 | return mock | 35 | return mock | ||
| 36 | } | 36 | } | ||
| 37 | 37 | ||||
| 38 | - | // MergeRequests is an autogenerated mock type for the MergeRequests type | 38 | + | // MergeRequestService is an autogenerated mock type for the MergeRequestService type |
| 39 | - | type MergeRequests struct { | 39 | + | type MergeRequestService struct { |
| 40 | mock.Mock | 40 | mock.Mock | ||
| 41 | } | 41 | } | ||
| 42 | 42 | ||||
| 43 | - | type MergeRequests_Expecter struct { | 43 | + | type MergeRequestService_Expecter struct { |
| 44 | mock *mock.Mock | 44 | mock *mock.Mock | ||
| 45 | } | 45 | } | ||
| 46 | 46 | ||||
| 47 | - | func (_m *MergeRequests) EXPECT() *MergeRequests_Expecter { | 47 | + | func (_m *MergeRequestService) EXPECT() *MergeRequestService_Expecter { |
| 48 | - | return &MergeRequests_Expecter{mock: &_m.Mock} | 48 | + | return &MergeRequestService_Expecter{mock: &_m.Mock} |
| 49 | } | 49 | } | ||
| 50 | 50 | ||||
| 51 | - | // AddComment provides a mock function for the type MergeRequests | 51 | + | // AddComment provides a mock function for the type MergeRequestService |
| 52 | - | func (_mock *MergeRequests) AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.AddCommentParams) (domain.Comment, error) { | 52 | + | func (_mock *MergeRequestService) AddComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.AddCommentParams) (domain.Comment, error) { |
| 53 | ret := _mock.Called(ctx, p, name, number, params) | 53 | ret := _mock.Called(ctx, p, name, number, params) | ||
| 54 | 54 | ||||
| 55 | if len(ret) == 0 { | 55 | if len(ret) == 0 { | ||
| @@ -58,15 +58,15 @@ func (_mock *MergeRequests) AddComment(ctx context.Context, p domain.Principal, | |||||
| 58 | 58 | ||||
| 59 | var r0 domain.Comment | 59 | var r0 domain.Comment | ||
| 60 | var r1 error | 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 | return returnFunc(ctx, p, name, number, params) | 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 | r0 = returnFunc(ctx, p, name, number, params) | 65 | r0 = returnFunc(ctx, p, name, number, params) | ||
| 66 | } else { | 66 | } else { | ||
| 67 | r0 = ret.Get(0).(domain.Comment) | 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 | r1 = returnFunc(ctx, p, name, number, params) | 70 | r1 = returnFunc(ctx, p, name, number, params) | ||
| 71 | } else { | 71 | } else { | ||
| 72 | r1 = ret.Error(1) | 72 | r1 = ret.Error(1) | ||
| @@ -74,8 +74,8 @@ func (_mock *MergeRequests) AddComment(ctx context.Context, p domain.Principal, | |||||
| 74 | return r0, r1 | 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' | 77 | + | // MergeRequestService_AddComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddComment' |
| 78 | - | type MergeRequests_AddComment_Call struct { | 78 | + | type MergeRequestService_AddComment_Call struct { |
| 79 | *mock.Call | 79 | *mock.Call | ||
| 80 | } | 80 | } | ||
| 81 | 81 | ||||
| @@ -84,12 +84,12 @@ type MergeRequests_AddComment_Call struct { | |||||
| 84 | // - p domain.Principal | 84 | // - p domain.Principal | ||
| 85 | // - name domain.RepoName | 85 | // - name domain.RepoName | ||
| 86 | // - number int64 | 86 | // - number int64 | ||
| 87 | - | // - params app.AddCommentParams | 87 | + | // - params ports.AddCommentParams |
| 88 | - | func (_e *MergeRequests_Expecter) AddComment(ctx any, p any, name any, number any, params any) *MergeRequests_AddComment_Call { | 88 | + | func (_e *MergeRequestService_Expecter) AddComment(ctx any, p any, name any, number any, params any) *MergeRequestService_AddComment_Call { |
| 89 | - | return &MergeRequests_AddComment_Call{Call: _e.mock.On("AddComment", ctx, p, name, number, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 93 | _c.Call.Run(func(args mock.Arguments) { | ||
| 94 | var arg0 context.Context | 94 | var arg0 context.Context | ||
| 95 | if args[0] != nil { | 95 | if args[0] != nil { | ||
| @@ -107,9 +107,9 @@ func (_c *MergeRequests_AddComment_Call) Run(run func(ctx context.Context, p dom | |||||
| 107 | if args[3] != nil { | 107 | if args[3] != nil { | ||
| 108 | arg3 = args[3].(int64) | 108 | arg3 = args[3].(int64) | ||
| 109 | } | 109 | } | ||
| 110 | - | var arg4 app.AddCommentParams | 110 | + | var arg4 ports.AddCommentParams |
| 111 | if args[4] != nil { | 111 | if args[4] != nil { | ||
| 112 | - | arg4 = args[4].(app.AddCommentParams) | 112 | + | arg4 = args[4].(ports.AddCommentParams) |
| 113 | } | 113 | } | ||
| 114 | run( | 114 | run( | ||
| 115 | arg0, | 115 | arg0, | ||
| @@ -122,18 +122,18 @@ func (_c *MergeRequests_AddComment_Call) Run(run func(ctx context.Context, p dom | |||||
| 122 | return _c | 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 | _c.Call.Return(comment, err) | 126 | _c.Call.Return(comment, err) | ||
| 127 | return _c | 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 | _c.Call.Return(run) | 131 | _c.Call.Return(run) | ||
| 132 | return _c | 132 | return _c | ||
| 133 | } | 133 | } | ||
| 134 | 134 | ||||
| 135 | - | // Close provides a mock function for the type MergeRequests | 135 | + | // Close provides a mock function for the type MergeRequestService |
| 136 | - | func (_mock *MergeRequests) Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) { | 136 | + | func (_mock *MergeRequestService) Close(ctx context.Context, p domain.Principal, name domain.RepoName, number int64) (domain.MergeRequest, error) { |
| 137 | ret := _mock.Called(ctx, p, name, number) | 137 | ret := _mock.Called(ctx, p, name, number) | ||
| 138 | 138 | ||||
| 139 | if len(ret) == 0 { | 139 | if len(ret) == 0 { | ||
| @@ -158,8 +158,8 @@ func (_mock *MergeRequests) Close(ctx context.Context, p domain.Principal, name | |||||
| 158 | return r0, r1 | 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' | 161 | + | // MergeRequestService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' |
| 162 | - | type MergeRequests_Close_Call struct { | 162 | + | type MergeRequestService_Close_Call struct { |
| 163 | *mock.Call | 163 | *mock.Call | ||
| 164 | } | 164 | } | ||
| 165 | 165 | ||||
| @@ -168,11 +168,11 @@ type MergeRequests_Close_Call struct { | |||||
| 168 | // - p domain.Principal | 168 | // - p domain.Principal | ||
| 169 | // - name domain.RepoName | 169 | // - name domain.RepoName | ||
| 170 | // - number int64 | 170 | // - number int64 | ||
| 171 | - | func (_e *MergeRequests_Expecter) Close(ctx any, p any, name any, number any) *MergeRequests_Close_Call { | 171 | + | func (_e *MergeRequestService_Expecter) Close(ctx any, p any, name any, number any) *MergeRequestService_Close_Call { |
| 172 | - | return &MergeRequests_Close_Call{Call: _e.mock.On("Close", ctx, p, name, number)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 176 | _c.Call.Run(func(args mock.Arguments) { | ||
| 177 | var arg0 context.Context | 177 | var arg0 context.Context | ||
| 178 | if args[0] != nil { | 178 | if args[0] != nil { | ||
| @@ -200,18 +200,18 @@ func (_c *MergeRequests_Close_Call) Run(run func(ctx context.Context, p domain.P | |||||
| 200 | return _c | 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 | _c.Call.Return(mergeRequest, err) | 204 | _c.Call.Return(mergeRequest, err) | ||
| 205 | return _c | 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 | _c.Call.Return(run) | 209 | _c.Call.Return(run) | ||
| 210 | return _c | 210 | return _c | ||
| 211 | } | 211 | } | ||
| 212 | 212 | ||||
| 213 | - | // Create provides a mock function for the type MergeRequests | 213 | + | // Create provides a mock function for the type MergeRequestService |
| 214 | - | func (_mock *MergeRequests) Create(ctx context.Context, p domain.Principal, name domain.RepoName, params app.CreateMergeRequestParams) (domain.MergeRequest, error) { | 214 | + | func (_mock *MergeRequestService) Create(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.CreateMergeRequestParams) (domain.MergeRequest, error) { |
| 215 | ret := _mock.Called(ctx, p, name, params) | 215 | ret := _mock.Called(ctx, p, name, params) | ||
| 216 | 216 | ||||
| 217 | if len(ret) == 0 { | 217 | if len(ret) == 0 { | ||
| @@ -220,15 +220,15 @@ func (_mock *MergeRequests) Create(ctx context.Context, p domain.Principal, name | |||||
| 220 | 220 | ||||
| 221 | var r0 domain.MergeRequest | 221 | var r0 domain.MergeRequest | ||
| 222 | var r1 error | 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 | return returnFunc(ctx, p, name, params) | 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 | r0 = returnFunc(ctx, p, name, params) | 227 | r0 = returnFunc(ctx, p, name, params) | ||
| 228 | } else { | 228 | } else { | ||
| 229 | r0 = ret.Get(0).(domain.MergeRequest) | 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 | r1 = returnFunc(ctx, p, name, params) | 232 | r1 = returnFunc(ctx, p, name, params) | ||
| 233 | } else { | 233 | } else { | ||
| 234 | r1 = ret.Error(1) | 234 | r1 = ret.Error(1) | ||
| @@ -236,8 +236,8 @@ func (_mock *MergeRequests) Create(ctx context.Context, p domain.Principal, name | |||||
| 236 | return r0, r1 | 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' | 239 | + | // MergeRequestService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' |
| 240 | - | type MergeRequests_Create_Call struct { | 240 | + | type MergeRequestService_Create_Call struct { |
| 241 | *mock.Call | 241 | *mock.Call | ||
| 242 | } | 242 | } | ||
| 243 | 243 | ||||
| @@ -245,12 +245,12 @@ type MergeRequests_Create_Call struct { | |||||
| 245 | // - ctx context.Context | 245 | // - ctx context.Context | ||
| 246 | // - p domain.Principal | 246 | // - p domain.Principal | ||
| 247 | // - name domain.RepoName | 247 | // - name domain.RepoName | ||
| 248 | - | // - params app.CreateMergeRequestParams | 248 | + | // - params ports.CreateMergeRequestParams |
| 249 | - | func (_e *MergeRequests_Expecter) Create(ctx any, p any, name any, params any) *MergeRequests_Create_Call { | 249 | + | func (_e *MergeRequestService_Expecter) Create(ctx any, p any, name any, params any) *MergeRequestService_Create_Call { |
| 250 | - | return &MergeRequests_Create_Call{Call: _e.mock.On("Create", ctx, p, name, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 254 | _c.Call.Run(func(args mock.Arguments) { | ||
| 255 | var arg0 context.Context | 255 | var arg0 context.Context | ||
| 256 | if args[0] != nil { | 256 | if args[0] != nil { | ||
| @@ -264,9 +264,9 @@ func (_c *MergeRequests_Create_Call) Run(run func(ctx context.Context, p domain. | |||||
| 264 | if args[2] != nil { | 264 | if args[2] != nil { | ||
| 265 | arg2 = args[2].(domain.RepoName) | 265 | arg2 = args[2].(domain.RepoName) | ||
| 266 | } | 266 | } | ||
| 267 | - | var arg3 app.CreateMergeRequestParams | 267 | + | var arg3 ports.CreateMergeRequestParams |
| 268 | if args[3] != nil { | 268 | if args[3] != nil { | ||
| 269 | - | arg3 = args[3].(app.CreateMergeRequestParams) | 269 | + | arg3 = args[3].(ports.CreateMergeRequestParams) |
| 270 | } | 270 | } | ||
| 271 | run( | 271 | run( | ||
| 272 | arg0, | 272 | arg0, | ||
| @@ -278,33 +278,33 @@ func (_c *MergeRequests_Create_Call) Run(run func(ctx context.Context, p domain. | |||||
| 278 | return _c | 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 | _c.Call.Return(mergeRequest, err) | 282 | _c.Call.Return(mergeRequest, err) | ||
| 283 | return _c | 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 | _c.Call.Return(run) | 287 | _c.Call.Return(run) | ||
| 288 | return _c | 288 | return _c | ||
| 289 | } | 289 | } | ||
| 290 | 290 | ||||
| 291 | - | // Get provides a mock function for the type MergeRequests | 291 | + | // Get provides a mock function for the type MergeRequestService |
| 292 | - | func (_mock *MergeRequests) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (app.MergeRequestDetail, error) { | 292 | + | func (_mock *MergeRequestService) Get(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, sinceLastRead bool) (ports.MergeRequestDetail, error) { |
| 293 | ret := _mock.Called(ctx, p, name, number, sinceLastRead) | 293 | ret := _mock.Called(ctx, p, name, number, sinceLastRead) | ||
| 294 | 294 | ||||
| 295 | if len(ret) == 0 { | 295 | if len(ret) == 0 { | ||
| 296 | panic("no return value specified for Get") | 296 | panic("no return value specified for Get") | ||
| 297 | } | 297 | } | ||
| 298 | 298 | ||||
| 299 | - | var r0 app.MergeRequestDetail | 299 | + | var r0 ports.MergeRequestDetail |
| 300 | var r1 error | 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 | return returnFunc(ctx, p, name, number, sinceLastRead) | 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 | r0 = returnFunc(ctx, p, name, number, sinceLastRead) | 305 | r0 = returnFunc(ctx, p, name, number, sinceLastRead) | ||
| 306 | } else { | 306 | } else { | ||
| 307 | - | r0 = ret.Get(0).(app.MergeRequestDetail) | 307 | + | r0 = ret.Get(0).(ports.MergeRequestDetail) |
| 308 | } | 308 | } | ||
| 309 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, bool) error); ok { | 309 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, domain.RepoName, int64, bool) error); ok { | ||
| 310 | r1 = returnFunc(ctx, p, name, number, sinceLastRead) | 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 | return r0, r1 | 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' | 317 | + | // MergeRequestService_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' |
| 318 | - | type MergeRequests_Get_Call struct { | 318 | + | type MergeRequestService_Get_Call struct { |
| 319 | *mock.Call | 319 | *mock.Call | ||
| 320 | } | 320 | } | ||
| 321 | 321 | ||||
| @@ -325,11 +325,11 @@ type MergeRequests_Get_Call struct { | |||||
| 325 | // - name domain.RepoName | 325 | // - name domain.RepoName | ||
| 326 | // - number int64 | 326 | // - number int64 | ||
| 327 | // - sinceLastRead bool | 327 | // - sinceLastRead bool | ||
| 328 | - | func (_e *MergeRequests_Expecter) Get(ctx any, p any, name any, number any, sinceLastRead any) *MergeRequests_Get_Call { | 328 | + | func (_e *MergeRequestService_Expecter) Get(ctx any, p any, name any, number any, sinceLastRead any) *MergeRequestService_Get_Call { |
| 329 | - | return &MergeRequests_Get_Call{Call: _e.mock.On("Get", ctx, p, name, number, sinceLastRead)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 333 | _c.Call.Run(func(args mock.Arguments) { | ||
| 334 | var arg0 context.Context | 334 | var arg0 context.Context | ||
| 335 | if args[0] != nil { | 335 | if args[0] != nil { | ||
| @@ -362,35 +362,35 @@ func (_c *MergeRequests_Get_Call) Run(run func(ctx context.Context, p domain.Pri | |||||
| 362 | return _c | 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 | _c.Call.Return(mergeRequestDetail, err) | 366 | _c.Call.Return(mergeRequestDetail, err) | ||
| 367 | return _c | 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 | _c.Call.Return(run) | 371 | _c.Call.Return(run) | ||
| 372 | return _c | 372 | return _c | ||
| 373 | } | 373 | } | ||
| 374 | 374 | ||||
| 375 | - | // List provides a mock function for the type MergeRequests | 375 | + | // List provides a mock function for the type MergeRequestService |
| 376 | - | func (_mock *MergeRequests) List(ctx context.Context, p domain.Principal, name domain.RepoName, params app.ListMergeRequestsParams) (app.MergeRequestPage, error) { | 376 | + | func (_mock *MergeRequestService) List(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.ListMergeRequestsParams) (ports.MergeRequestPage, error) { |
| 377 | ret := _mock.Called(ctx, p, name, params) | 377 | ret := _mock.Called(ctx, p, name, params) | ||
| 378 | 378 | ||||
| 379 | if len(ret) == 0 { | 379 | if len(ret) == 0 { | ||
| 380 | panic("no return value specified for List") | 380 | panic("no return value specified for List") | ||
| 381 | } | 381 | } | ||
| 382 | 382 | ||||
| 383 | - | var r0 app.MergeRequestPage | 383 | + | var r0 ports.MergeRequestPage |
| 384 | var r1 error | 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 | return returnFunc(ctx, p, name, params) | 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 | r0 = returnFunc(ctx, p, name, params) | 389 | r0 = returnFunc(ctx, p, name, params) | ||
| 390 | } else { | 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 | r1 = returnFunc(ctx, p, name, params) | 394 | r1 = returnFunc(ctx, p, name, params) | ||
| 395 | } else { | 395 | } else { | ||
| 396 | r1 = ret.Error(1) | 396 | r1 = ret.Error(1) | ||
| @@ -398,8 +398,8 @@ func (_mock *MergeRequests) List(ctx context.Context, p domain.Principal, name d | |||||
| 398 | return r0, r1 | 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' | 401 | + | // MergeRequestService_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List' |
| 402 | - | type MergeRequests_List_Call struct { | 402 | + | type MergeRequestService_List_Call struct { |
| 403 | *mock.Call | 403 | *mock.Call | ||
| 404 | } | 404 | } | ||
| 405 | 405 | ||||
| @@ -407,12 +407,12 @@ type MergeRequests_List_Call struct { | |||||
| 407 | // - ctx context.Context | 407 | // - ctx context.Context | ||
| 408 | // - p domain.Principal | 408 | // - p domain.Principal | ||
| 409 | // - name domain.RepoName | 409 | // - name domain.RepoName | ||
| 410 | - | // - params app.ListMergeRequestsParams | 410 | + | // - params ports.ListMergeRequestsParams |
| 411 | - | func (_e *MergeRequests_Expecter) List(ctx any, p any, name any, params any) *MergeRequests_List_Call { | 411 | + | func (_e *MergeRequestService_Expecter) List(ctx any, p any, name any, params any) *MergeRequestService_List_Call { |
| 412 | - | return &MergeRequests_List_Call{Call: _e.mock.On("List", ctx, p, name, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 416 | _c.Call.Run(func(args mock.Arguments) { | ||
| 417 | var arg0 context.Context | 417 | var arg0 context.Context | ||
| 418 | if args[0] != nil { | 418 | if args[0] != nil { | ||
| @@ -426,9 +426,9 @@ func (_c *MergeRequests_List_Call) Run(run func(ctx context.Context, p domain.Pr | |||||
| 426 | if args[2] != nil { | 426 | if args[2] != nil { | ||
| 427 | arg2 = args[2].(domain.RepoName) | 427 | arg2 = args[2].(domain.RepoName) | ||
| 428 | } | 428 | } | ||
| 429 | - | var arg3 app.ListMergeRequestsParams | 429 | + | var arg3 ports.ListMergeRequestsParams |
| 430 | if args[3] != nil { | 430 | if args[3] != nil { | ||
| 431 | - | arg3 = args[3].(app.ListMergeRequestsParams) | 431 | + | arg3 = args[3].(ports.ListMergeRequestsParams) |
| 432 | } | 432 | } | ||
| 433 | run( | 433 | run( | ||
| 434 | arg0, | 434 | arg0, | ||
| @@ -440,18 +440,18 @@ func (_c *MergeRequests_List_Call) Run(run func(ctx context.Context, p domain.Pr | |||||
| 440 | return _c | 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 | _c.Call.Return(mergeRequestPage, err) | 444 | _c.Call.Return(mergeRequestPage, err) | ||
| 445 | return _c | 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 | _c.Call.Return(run) | 449 | _c.Call.Return(run) | ||
| 450 | return _c | 450 | return _c | ||
| 451 | } | 451 | } | ||
| 452 | 452 | ||||
| 453 | - | // MarkRead provides a mock function for the type MergeRequests | 453 | + | // MarkRead provides a mock function for the type MergeRequestService |
| 454 | - | func (_mock *MergeRequests) MarkRead(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error) { | 454 | + | func (_mock *MergeRequestService) MarkRead(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, head domain.ObjectID) (domain.ObjectID, error) { |
| 455 | ret := _mock.Called(ctx, p, name, number, head) | 455 | ret := _mock.Called(ctx, p, name, number, head) | ||
| 456 | 456 | ||||
| 457 | if len(ret) == 0 { | 457 | if len(ret) == 0 { | ||
| @@ -476,8 +476,8 @@ func (_mock *MergeRequests) MarkRead(ctx context.Context, p domain.Principal, na | |||||
| 476 | return r0, r1 | 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' | 479 | + | // MergeRequestService_MarkRead_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarkRead' |
| 480 | - | type MergeRequests_MarkRead_Call struct { | 480 | + | type MergeRequestService_MarkRead_Call struct { |
| 481 | *mock.Call | 481 | *mock.Call | ||
| 482 | } | 482 | } | ||
| 483 | 483 | ||||
| @@ -487,11 +487,11 @@ type MergeRequests_MarkRead_Call struct { | |||||
| 487 | // - name domain.RepoName | 487 | // - name domain.RepoName | ||
| 488 | // - number int64 | 488 | // - number int64 | ||
| 489 | // - head domain.ObjectID | 489 | // - head domain.ObjectID | ||
| 490 | - | func (_e *MergeRequests_Expecter) MarkRead(ctx any, p any, name any, number any, head any) *MergeRequests_MarkRead_Call { | 490 | + | func (_e *MergeRequestService_Expecter) MarkRead(ctx any, p any, name any, number any, head any) *MergeRequestService_MarkRead_Call { |
| 491 | - | return &MergeRequests_MarkRead_Call{Call: _e.mock.On("MarkRead", ctx, p, name, number, head)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 495 | _c.Call.Run(func(args mock.Arguments) { | ||
| 496 | var arg0 context.Context | 496 | var arg0 context.Context | ||
| 497 | if args[0] != nil { | 497 | if args[0] != nil { | ||
| @@ -524,35 +524,35 @@ func (_c *MergeRequests_MarkRead_Call) Run(run func(ctx context.Context, p domai | |||||
| 524 | return _c | 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 | _c.Call.Return(objectID, err) | 528 | _c.Call.Return(objectID, err) | ||
| 529 | return _c | 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 | _c.Call.Return(run) | 533 | _c.Call.Return(run) | ||
| 534 | return _c | 534 | return _c | ||
| 535 | } | 535 | } | ||
| 536 | 536 | ||||
| 537 | - | // Merge provides a mock function for the type MergeRequests | 537 | + | // Merge provides a mock function for the type MergeRequestService |
| 538 | - | func (_mock *MergeRequests) Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params app.MergeParams) (app.MergeResult, error) { | 538 | + | func (_mock *MergeRequestService) Merge(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, params ports.MergeParams) (ports.MergeResult, error) { |
| 539 | ret := _mock.Called(ctx, p, name, number, params) | 539 | ret := _mock.Called(ctx, p, name, number, params) | ||
| 540 | 540 | ||||
| 541 | if len(ret) == 0 { | 541 | if len(ret) == 0 { | ||
| 542 | panic("no return value specified for Merge") | 542 | panic("no return value specified for Merge") | ||
| 543 | } | 543 | } | ||
| 544 | 544 | ||||
| 545 | - | var r0 app.MergeResult | 545 | + | var r0 ports.MergeResult |
| 546 | var r1 error | 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 | return returnFunc(ctx, p, name, number, params) | 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 | r0 = returnFunc(ctx, p, name, number, params) | 551 | r0 = returnFunc(ctx, p, name, number, params) | ||
| 552 | } else { | 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 | r1 = returnFunc(ctx, p, name, number, params) | 556 | r1 = returnFunc(ctx, p, name, number, params) | ||
| 557 | } else { | 557 | } else { | ||
| 558 | r1 = ret.Error(1) | 558 | r1 = ret.Error(1) | ||
| @@ -560,8 +560,8 @@ func (_mock *MergeRequests) Merge(ctx context.Context, p domain.Principal, name | |||||
| 560 | return r0, r1 | 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' | 563 | + | // MergeRequestService_Merge_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Merge' |
| 564 | - | type MergeRequests_Merge_Call struct { | 564 | + | type MergeRequestService_Merge_Call struct { |
| 565 | *mock.Call | 565 | *mock.Call | ||
| 566 | } | 566 | } | ||
| 567 | 567 | ||||
| @@ -570,12 +570,12 @@ type MergeRequests_Merge_Call struct { | |||||
| 570 | // - p domain.Principal | 570 | // - p domain.Principal | ||
| 571 | // - name domain.RepoName | 571 | // - name domain.RepoName | ||
| 572 | // - number int64 | 572 | // - number int64 | ||
| 573 | - | // - params app.MergeParams | 573 | + | // - params ports.MergeParams |
| 574 | - | func (_e *MergeRequests_Expecter) Merge(ctx any, p any, name any, number any, params any) *MergeRequests_Merge_Call { | 574 | + | func (_e *MergeRequestService_Expecter) Merge(ctx any, p any, name any, number any, params any) *MergeRequestService_Merge_Call { |
| 575 | - | return &MergeRequests_Merge_Call{Call: _e.mock.On("Merge", ctx, p, name, number, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 579 | _c.Call.Run(func(args mock.Arguments) { | ||
| 580 | var arg0 context.Context | 580 | var arg0 context.Context | ||
| 581 | if args[0] != nil { | 581 | if args[0] != nil { | ||
| @@ -593,9 +593,9 @@ func (_c *MergeRequests_Merge_Call) Run(run func(ctx context.Context, p domain.P | |||||
| 593 | if args[3] != nil { | 593 | if args[3] != nil { | ||
| 594 | arg3 = args[3].(int64) | 594 | arg3 = args[3].(int64) | ||
| 595 | } | 595 | } | ||
| 596 | - | var arg4 app.MergeParams | 596 | + | var arg4 ports.MergeParams |
| 597 | if args[4] != nil { | 597 | if args[4] != nil { | ||
| 598 | - | arg4 = args[4].(app.MergeParams) | 598 | + | arg4 = args[4].(ports.MergeParams) |
| 599 | } | 599 | } | ||
| 600 | run( | 600 | run( | ||
| 601 | arg0, | 601 | arg0, | ||
| @@ -608,18 +608,18 @@ func (_c *MergeRequests_Merge_Call) Run(run func(ctx context.Context, p domain.P | |||||
| 608 | return _c | 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 | _c.Call.Return(mergeResult, err) | 612 | _c.Call.Return(mergeResult, err) | ||
| 613 | return _c | 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 | _c.Call.Return(run) | 617 | _c.Call.Return(run) | ||
| 618 | return _c | 618 | return _c | ||
| 619 | } | 619 | } | ||
| 620 | 620 | ||||
| 621 | - | // ResolveComment provides a mock function for the type MergeRequests | 621 | + | // ResolveComment provides a mock function for the type MergeRequestService |
| 622 | - | func (_mock *MergeRequests) ResolveComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool) (domain.Comment, error) { | 622 | + | func (_mock *MergeRequestService) ResolveComment(ctx context.Context, p domain.Principal, name domain.RepoName, number int64, commentID int64, resolved bool) (domain.Comment, error) { |
| 623 | ret := _mock.Called(ctx, p, name, number, commentID, resolved) | 623 | ret := _mock.Called(ctx, p, name, number, commentID, resolved) | ||
| 624 | 624 | ||||
| 625 | if len(ret) == 0 { | 625 | if len(ret) == 0 { | ||
| @@ -644,8 +644,8 @@ func (_mock *MergeRequests) ResolveComment(ctx context.Context, p domain.Princip | |||||
| 644 | return r0, r1 | 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' | 647 | + | // MergeRequestService_ResolveComment_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResolveComment' |
| 648 | - | type MergeRequests_ResolveComment_Call struct { | 648 | + | type MergeRequestService_ResolveComment_Call struct { |
| 649 | *mock.Call | 649 | *mock.Call | ||
| 650 | } | 650 | } | ||
| 651 | 651 | ||||
| @@ -656,11 +656,11 @@ type MergeRequests_ResolveComment_Call struct { | |||||
| 656 | // - number int64 | 656 | // - number int64 | ||
| 657 | // - commentID int64 | 657 | // - commentID int64 | ||
| 658 | // - resolved bool | 658 | // - resolved bool | ||
| 659 | - | func (_e *MergeRequests_Expecter) ResolveComment(ctx any, p any, name any, number any, commentID any, resolved any) *MergeRequests_ResolveComment_Call { | 659 | + | func (_e *MergeRequestService_Expecter) ResolveComment(ctx any, p any, name any, number any, commentID any, resolved any) *MergeRequestService_ResolveComment_Call { |
| 660 | - | return &MergeRequests_ResolveComment_Call{Call: _e.mock.On("ResolveComment", ctx, p, name, number, commentID, resolved)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 664 | _c.Call.Run(func(args mock.Arguments) { | ||
| 665 | var arg0 context.Context | 665 | var arg0 context.Context | ||
| 666 | if args[0] != nil { | 666 | if args[0] != nil { | ||
| @@ -698,12 +698,12 @@ func (_c *MergeRequests_ResolveComment_Call) Run(run func(ctx context.Context, p | |||||
| 698 | return _c | 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 | _c.Call.Return(comment, err) | 702 | _c.Call.Return(comment, err) | ||
| 703 | return _c | 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 | _c.Call.Return(run) | 707 | _c.Call.Return(run) | ||
| 708 | return _c | 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 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 15 | // The first argument is typically a *testing.T value. | ||
| 16 | - | func NewPushHooks(t interface { | 16 | + | func NewPushHookService(t interface { |
| 17 | mock.TestingT | 17 | mock.TestingT | ||
| 18 | Cleanup(func()) | 18 | Cleanup(func()) | ||
| 19 | - | }) *PushHooks { | 19 | + | }) *PushHookService { |
| 20 | if helper, ok := t.(interface{ Helper() }); ok { | 20 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 21 | helper.Helper() | 21 | helper.Helper() | ||
| 22 | } | 22 | } | ||
| 23 | 23 | ||||
| 24 | - | mock := &PushHooks{} | 24 | + | mock := &PushHookService{} |
| 25 | mock.Mock.Test(t) | 25 | mock.Mock.Test(t) | ||
| 26 | 26 | ||||
| 27 | t.Cleanup(func() { | 27 | t.Cleanup(func() { | ||
| @@ -34,21 +34,21 @@ func NewPushHooks(t interface { | |||||
| 34 | return mock | 34 | return mock | ||
| 35 | } | 35 | } | ||
| 36 | 36 | ||||
| 37 | - | // PushHooks is an autogenerated mock type for the PushHooks type | 37 | + | // PushHookService is an autogenerated mock type for the PushHookService type |
| 38 | - | type PushHooks struct { | 38 | + | type PushHookService struct { |
| 39 | mock.Mock | 39 | mock.Mock | ||
| 40 | } | 40 | } | ||
| 41 | 41 | ||||
| 42 | - | type PushHooks_Expecter struct { | 42 | + | type PushHookService_Expecter struct { |
| 43 | mock *mock.Mock | 43 | mock *mock.Mock | ||
| 44 | } | 44 | } | ||
| 45 | 45 | ||||
| 46 | - | func (_m *PushHooks) EXPECT() *PushHooks_Expecter { | 46 | + | func (_m *PushHookService) EXPECT() *PushHookService_Expecter { |
| 47 | - | return &PushHooks_Expecter{mock: &_m.Mock} | 47 | + | return &PushHookService_Expecter{mock: &_m.Mock} |
| 48 | } | 48 | } | ||
| 49 | 49 | ||||
| 50 | - | // Check provides a mock function for the type PushHooks | 50 | + | // Check provides a mock function for the type PushHookService |
| 51 | - | func (_mock *PushHooks) Check(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { | 51 | + | func (_mock *PushHookService) Check(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { |
| 52 | ret := _mock.Called(ctx, p, name, updates) | 52 | ret := _mock.Called(ctx, p, name, updates) | ||
| 53 | 53 | ||||
| 54 | if len(ret) == 0 { | 54 | if len(ret) == 0 { | ||
| @@ -64,8 +64,8 @@ func (_mock *PushHooks) Check(ctx context.Context, p domain.Principal, name doma | |||||
| 64 | return r0 | 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' | 67 | + | // PushHookService_Check_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Check' |
| 68 | - | type PushHooks_Check_Call struct { | 68 | + | type PushHookService_Check_Call struct { |
| 69 | *mock.Call | 69 | *mock.Call | ||
| 70 | } | 70 | } | ||
| 71 | 71 | ||||
| @@ -74,11 +74,11 @@ type PushHooks_Check_Call struct { | |||||
| 74 | // - p domain.Principal | 74 | // - p domain.Principal | ||
| 75 | // - name domain.RepoName | 75 | // - name domain.RepoName | ||
| 76 | // - updates []domain.RefUpdate | 76 | // - updates []domain.RefUpdate | ||
| 77 | - | func (_e *PushHooks_Expecter) Check(ctx any, p any, name any, updates any) *PushHooks_Check_Call { | 77 | + | func (_e *PushHookService_Expecter) Check(ctx any, p any, name any, updates any) *PushHookService_Check_Call { |
| 78 | - | return &PushHooks_Check_Call{Call: _e.mock.On("Check", ctx, p, name, updates)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 82 | _c.Call.Run(func(args mock.Arguments) { | ||
| 83 | var arg0 context.Context | 83 | var arg0 context.Context | ||
| 84 | if args[0] != nil { | 84 | if args[0] != nil { | ||
| @@ -106,18 +106,18 @@ func (_c *PushHooks_Check_Call) Run(run func(ctx context.Context, p domain.Princ | |||||
| 106 | return _c | 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 | _c.Call.Return(err) | 110 | _c.Call.Return(err) | ||
| 111 | return _c | 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 | _c.Call.Return(run) | 115 | _c.Call.Return(run) | ||
| 116 | return _c | 116 | return _c | ||
| 117 | } | 117 | } | ||
| 118 | 118 | ||||
| 119 | - | // Record provides a mock function for the type PushHooks | 119 | + | // Record provides a mock function for the type PushHookService |
| 120 | - | func (_mock *PushHooks) Record(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { | 120 | + | func (_mock *PushHookService) Record(ctx context.Context, p domain.Principal, name domain.RepoName, updates []domain.RefUpdate) error { |
| 121 | ret := _mock.Called(ctx, p, name, updates) | 121 | ret := _mock.Called(ctx, p, name, updates) | ||
| 122 | 122 | ||||
| 123 | if len(ret) == 0 { | 123 | if len(ret) == 0 { | ||
| @@ -133,8 +133,8 @@ func (_mock *PushHooks) Record(ctx context.Context, p domain.Principal, name dom | |||||
| 133 | return r0 | 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' | 136 | + | // PushHookService_Record_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Record' |
| 137 | - | type PushHooks_Record_Call struct { | 137 | + | type PushHookService_Record_Call struct { |
| 138 | *mock.Call | 138 | *mock.Call | ||
| 139 | } | 139 | } | ||
| 140 | 140 | ||||
| @@ -143,11 +143,11 @@ type PushHooks_Record_Call struct { | |||||
| 143 | // - p domain.Principal | 143 | // - p domain.Principal | ||
| 144 | // - name domain.RepoName | 144 | // - name domain.RepoName | ||
| 145 | // - updates []domain.RefUpdate | 145 | // - updates []domain.RefUpdate | ||
| 146 | - | func (_e *PushHooks_Expecter) Record(ctx any, p any, name any, updates any) *PushHooks_Record_Call { | 146 | + | func (_e *PushHookService_Expecter) Record(ctx any, p any, name any, updates any) *PushHookService_Record_Call { |
| 147 | - | return &PushHooks_Record_Call{Call: _e.mock.On("Record", ctx, p, name, updates)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 151 | _c.Call.Run(func(args mock.Arguments) { | ||
| 152 | var arg0 context.Context | 152 | var arg0 context.Context | ||
| 153 | if args[0] != nil { | 153 | if args[0] != nil { | ||
| @@ -175,12 +175,12 @@ func (_c *PushHooks_Record_Call) Run(run func(ctx context.Context, p domain.Prin | |||||
| 175 | return _c | 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 | _c.Call.Return(err) | 179 | _c.Call.Return(err) | ||
| 180 | return _c | 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 | _c.Call.Return(run) | 184 | _c.Call.Return(run) | ||
| 185 | return _c | 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 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 15 | // The first argument is typically a *testing.T value. | ||
| 16 | - | func NewPushes(t interface { | 16 | + | func NewPushService(t interface { |
| 17 | mock.TestingT | 17 | mock.TestingT | ||
| 18 | Cleanup(func()) | 18 | Cleanup(func()) | ||
| 19 | - | }) *Pushes { | 19 | + | }) *PushService { |
| 20 | if helper, ok := t.(interface{ Helper() }); ok { | 20 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 21 | helper.Helper() | 21 | helper.Helper() | ||
| 22 | } | 22 | } | ||
| 23 | 23 | ||||
| 24 | - | mock := &Pushes{} | 24 | + | mock := &PushService{} |
| 25 | mock.Mock.Test(t) | 25 | mock.Mock.Test(t) | ||
| 26 | 26 | ||||
| 27 | t.Cleanup(func() { | 27 | t.Cleanup(func() { | ||
| @@ -34,21 +34,21 @@ func NewPushes(t interface { | |||||
| 34 | return mock | 34 | return mock | ||
| 35 | } | 35 | } | ||
| 36 | 36 | ||||
| 37 | - | // Pushes is an autogenerated mock type for the Pushes type | 37 | + | // PushService is an autogenerated mock type for the PushService type |
| 38 | - | type Pushes struct { | 38 | + | type PushService struct { |
| 39 | mock.Mock | 39 | mock.Mock | ||
| 40 | } | 40 | } | ||
| 41 | 41 | ||||
| 42 | - | type Pushes_Expecter struct { | 42 | + | type PushService_Expecter struct { |
| 43 | mock *mock.Mock | 43 | mock *mock.Mock | ||
| 44 | } | 44 | } | ||
| 45 | 45 | ||||
| 46 | - | func (_m *Pushes) EXPECT() *Pushes_Expecter { | 46 | + | func (_m *PushService) EXPECT() *PushService_Expecter { |
| 47 | - | return &Pushes_Expecter{mock: &_m.Mock} | 47 | + | return &PushService_Expecter{mock: &_m.Mock} |
| 48 | } | 48 | } | ||
| 49 | 49 | ||||
| 50 | - | // Open provides a mock function for the type Pushes | 50 | + | // Open provides a mock function for the type PushService |
| 51 | - | func (_mock *Pushes) Open(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error { | 51 | + | func (_mock *PushService) Open(ctx context.Context, p domain.Principal, name domain.RepoName, create bool) error { |
| 52 | ret := _mock.Called(ctx, p, name, create) | 52 | ret := _mock.Called(ctx, p, name, create) | ||
| 53 | 53 | ||||
| 54 | if len(ret) == 0 { | 54 | if len(ret) == 0 { | ||
| @@ -64,8 +64,8 @@ func (_mock *Pushes) Open(ctx context.Context, p domain.Principal, name domain.R | |||||
| 64 | return r0 | 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' | 67 | + | // PushService_Open_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Open' |
| 68 | - | type Pushes_Open_Call struct { | 68 | + | type PushService_Open_Call struct { |
| 69 | *mock.Call | 69 | *mock.Call | ||
| 70 | } | 70 | } | ||
| 71 | 71 | ||||
| @@ -74,11 +74,11 @@ type Pushes_Open_Call struct { | |||||
| 74 | // - p domain.Principal | 74 | // - p domain.Principal | ||
| 75 | // - name domain.RepoName | 75 | // - name domain.RepoName | ||
| 76 | // - create bool | 76 | // - create bool | ||
| 77 | - | func (_e *Pushes_Expecter) Open(ctx any, p any, name any, create any) *Pushes_Open_Call { | 77 | + | func (_e *PushService_Expecter) Open(ctx any, p any, name any, create any) *PushService_Open_Call { |
| 78 | - | return &Pushes_Open_Call{Call: _e.mock.On("Open", ctx, p, name, create)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 82 | _c.Call.Run(func(args mock.Arguments) { | ||
| 83 | var arg0 context.Context | 83 | var arg0 context.Context | ||
| 84 | if args[0] != nil { | 84 | if args[0] != nil { | ||
| @@ -106,12 +106,12 @@ func (_c *Pushes_Open_Call) Run(run func(ctx context.Context, p domain.Principal | |||||
| 106 | return _c | 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 | _c.Call.Return(err) | 110 | _c.Call.Return(err) | ||
| 111 | return _c | 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 | _c.Call.Return(run) | 115 | _c.Call.Return(run) | ||
| 116 | return _c | 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 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 15 | // The first argument is typically a *testing.T value. | ||
| 16 | - | func NewRepos(t interface { | 16 | + | func NewRepoLookup(t interface { |
| 17 | mock.TestingT | 17 | mock.TestingT | ||
| 18 | Cleanup(func()) | 18 | Cleanup(func()) | ||
| 19 | - | }) *Repos { | 19 | + | }) *RepoLookup { |
| 20 | if helper, ok := t.(interface{ Helper() }); ok { | 20 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 21 | helper.Helper() | 21 | helper.Helper() | ||
| 22 | } | 22 | } | ||
| 23 | 23 | ||||
| 24 | - | mock := &Repos{} | 24 | + | mock := &RepoLookup{} |
| 25 | mock.Mock.Test(t) | 25 | mock.Mock.Test(t) | ||
| 26 | 26 | ||||
| 27 | t.Cleanup(func() { | 27 | t.Cleanup(func() { | ||
| @@ -34,21 +34,21 @@ func NewRepos(t interface { | |||||
| 34 | return mock | 34 | return mock | ||
| 35 | } | 35 | } | ||
| 36 | 36 | ||||
| 37 | - | // Repos is an autogenerated mock type for the Repos type | 37 | + | // RepoLookup is an autogenerated mock type for the RepoLookup type |
| 38 | - | type Repos struct { | 38 | + | type RepoLookup struct { |
| 39 | mock.Mock | 39 | mock.Mock | ||
| 40 | } | 40 | } | ||
| 41 | 41 | ||||
| 42 | - | type Repos_Expecter struct { | 42 | + | type RepoLookup_Expecter struct { |
| 43 | mock *mock.Mock | 43 | mock *mock.Mock | ||
| 44 | } | 44 | } | ||
| 45 | 45 | ||||
| 46 | - | func (_m *Repos) EXPECT() *Repos_Expecter { | 46 | + | func (_m *RepoLookup) EXPECT() *RepoLookup_Expecter { |
| 47 | - | return &Repos_Expecter{mock: &_m.Mock} | 47 | + | return &RepoLookup_Expecter{mock: &_m.Mock} |
| 48 | } | 48 | } | ||
| 49 | 49 | ||||
| 50 | - | // Get provides a mock function for the type Repos | 50 | + | // Get provides a mock function for the type RepoLookup |
| 51 | - | func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { | 51 | + | func (_mock *RepoLookup) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { |
| 52 | ret := _mock.Called(ctx, p, name) | 52 | ret := _mock.Called(ctx, p, name) | ||
| 53 | 53 | ||||
| 54 | if len(ret) == 0 { | 54 | if len(ret) == 0 { | ||
| @@ -73,8 +73,8 @@ func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.Rep | |||||
| 73 | return r0, r1 | 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' | 76 | + | // RepoLookup_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' |
| 77 | - | type Repos_Get_Call struct { | 77 | + | type RepoLookup_Get_Call struct { |
| 78 | *mock.Call | 78 | *mock.Call | ||
| 79 | } | 79 | } | ||
| 80 | 80 | ||||
| @@ -82,11 +82,11 @@ type Repos_Get_Call struct { | |||||
| 82 | // - ctx context.Context | 82 | // - ctx context.Context | ||
| 83 | // - p domain.Principal | 83 | // - p domain.Principal | ||
| 84 | // - name domain.RepoName | 84 | // - name domain.RepoName | ||
| 85 | - | func (_e *Repos_Expecter) Get(ctx any, p any, name any) *Repos_Get_Call { | 85 | + | func (_e *RepoLookup_Expecter) Get(ctx any, p any, name any) *RepoLookup_Get_Call { |
| 86 | - | return &Repos_Get_Call{Call: _e.mock.On("Get", ctx, p, name)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 90 | _c.Call.Run(func(args mock.Arguments) { | ||
| 91 | var arg0 context.Context | 91 | var arg0 context.Context | ||
| 92 | if args[0] != nil { | 92 | if args[0] != nil { | ||
| @@ -109,12 +109,12 @@ func (_c *Repos_Get_Call) Run(run func(ctx context.Context, p domain.Principal, | |||||
| 109 | return _c | 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 | _c.Call.Return(repo, err) | 113 | _c.Call.Return(repo, err) | ||
| 114 | return _c | 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 | _c.Call.Return(run) | 118 | _c.Call.Return(run) | ||
| 119 | return _c | 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 | import ( | 7 | import ( | ||
| 8 | "context" | 8 | "context" | ||
| 9 | 9 | ||||
| 10 | - | "bnema.dev/ermite/internal/app" | |||
| 11 | "bnema.dev/ermite/internal/domain" | 10 | "bnema.dev/ermite/internal/domain" | ||
| 11 | + | "bnema.dev/ermite/internal/ports" | |||
| 12 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 16 | // The first argument is typically a *testing.T value. | ||
| 17 | - | func NewRepos(t interface { | 17 | + | func NewRepoService(t interface { |
| 18 | mock.TestingT | 18 | mock.TestingT | ||
| 19 | Cleanup(func()) | 19 | Cleanup(func()) | ||
| 20 | - | }) *Repos { | 20 | + | }) *RepoService { |
| 21 | if helper, ok := t.(interface{ Helper() }); ok { | 21 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 22 | helper.Helper() | 22 | helper.Helper() | ||
| 23 | } | 23 | } | ||
| 24 | 24 | ||||
| 25 | - | mock := &Repos{} | 25 | + | mock := &RepoService{} |
| 26 | mock.Mock.Test(t) | 26 | mock.Mock.Test(t) | ||
| 27 | 27 | ||||
| 28 | t.Cleanup(func() { | 28 | t.Cleanup(func() { | ||
| @@ -35,21 +35,21 @@ func NewRepos(t interface { | |||||
| 35 | return mock | 35 | return mock | ||
| 36 | } | 36 | } | ||
| 37 | 37 | ||||
| 38 | - | // Repos is an autogenerated mock type for the Repos type | 38 | + | // RepoService is an autogenerated mock type for the RepoService type |
| 39 | - | type Repos struct { | 39 | + | type RepoService struct { |
| 40 | mock.Mock | 40 | mock.Mock | ||
| 41 | } | 41 | } | ||
| 42 | 42 | ||||
| 43 | - | type Repos_Expecter struct { | 43 | + | type RepoService_Expecter struct { |
| 44 | mock *mock.Mock | 44 | mock *mock.Mock | ||
| 45 | } | 45 | } | ||
| 46 | 46 | ||||
| 47 | - | func (_m *Repos) EXPECT() *Repos_Expecter { | 47 | + | func (_m *RepoService) EXPECT() *RepoService_Expecter { |
| 48 | - | return &Repos_Expecter{mock: &_m.Mock} | 48 | + | return &RepoService_Expecter{mock: &_m.Mock} |
| 49 | } | 49 | } | ||
| 50 | 50 | ||||
| 51 | - | // Create provides a mock function for the type Repos | 51 | + | // Create provides a mock function for the type RepoService |
| 52 | - | func (_mock *Repos) Create(ctx context.Context, p domain.Principal, params app.CreateParams) (domain.Repo, error) { | 52 | + | func (_mock *RepoService) Create(ctx context.Context, p domain.Principal, params ports.CreateRepoParams) (domain.Repo, error) { |
| 53 | ret := _mock.Called(ctx, p, params) | 53 | ret := _mock.Called(ctx, p, params) | ||
| 54 | 54 | ||||
| 55 | if len(ret) == 0 { | 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 | var r0 domain.Repo | 59 | var r0 domain.Repo | ||
| 60 | var r1 error | 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 | return returnFunc(ctx, p, params) | 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 | r0 = returnFunc(ctx, p, params) | 65 | r0 = returnFunc(ctx, p, params) | ||
| 66 | } else { | 66 | } else { | ||
| 67 | r0 = ret.Get(0).(domain.Repo) | 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 | r1 = returnFunc(ctx, p, params) | 70 | r1 = returnFunc(ctx, p, params) | ||
| 71 | } else { | 71 | } else { | ||
| 72 | r1 = ret.Error(1) | 72 | r1 = ret.Error(1) | ||
| @@ -74,20 +74,20 @@ func (_mock *Repos) Create(ctx context.Context, p domain.Principal, params app.C | |||||
| 74 | return r0, r1 | 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' | 77 | + | // RepoService_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' |
| 78 | - | type Repos_Create_Call struct { | 78 | + | type RepoService_Create_Call struct { |
| 79 | *mock.Call | 79 | *mock.Call | ||
| 80 | } | 80 | } | ||
| 81 | 81 | ||||
| 82 | // Create is a helper method to define mock.On call | 82 | // Create is a helper method to define mock.On call | ||
| 83 | // - ctx context.Context | 83 | // - ctx context.Context | ||
| 84 | // - p domain.Principal | 84 | // - p domain.Principal | ||
| 85 | - | // - params app.CreateParams | 85 | + | // - params ports.CreateRepoParams |
| 86 | - | func (_e *Repos_Expecter) Create(ctx any, p any, params any) *Repos_Create_Call { | 86 | + | func (_e *RepoService_Expecter) Create(ctx any, p any, params any) *RepoService_Create_Call { |
| 87 | - | return &Repos_Create_Call{Call: _e.mock.On("Create", ctx, p, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 91 | _c.Call.Run(func(args mock.Arguments) { | ||
| 92 | var arg0 context.Context | 92 | var arg0 context.Context | ||
| 93 | if args[0] != nil { | 93 | if args[0] != nil { | ||
| @@ -97,9 +97,9 @@ func (_c *Repos_Create_Call) Run(run func(ctx context.Context, p domain.Principa | |||||
| 97 | if args[1] != nil { | 97 | if args[1] != nil { | ||
| 98 | arg1 = args[1].(domain.Principal) | 98 | arg1 = args[1].(domain.Principal) | ||
| 99 | } | 99 | } | ||
| 100 | - | var arg2 app.CreateParams | 100 | + | var arg2 ports.CreateRepoParams |
| 101 | if args[2] != nil { | 101 | if args[2] != nil { | ||
| 102 | - | arg2 = args[2].(app.CreateParams) | 102 | + | arg2 = args[2].(ports.CreateRepoParams) |
| 103 | } | 103 | } | ||
| 104 | run( | 104 | run( | ||
| 105 | arg0, | 105 | arg0, | ||
| @@ -110,18 +110,18 @@ func (_c *Repos_Create_Call) Run(run func(ctx context.Context, p domain.Principa | |||||
| 110 | return _c | 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 | _c.Call.Return(repo, err) | 114 | _c.Call.Return(repo, err) | ||
| 115 | return _c | 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 | _c.Call.Return(run) | 119 | _c.Call.Return(run) | ||
| 120 | return _c | 120 | return _c | ||
| 121 | } | 121 | } | ||
| 122 | 122 | ||||
| 123 | - | // Delete provides a mock function for the type Repos | 123 | + | // Delete provides a mock function for the type RepoService |
| 124 | - | func (_mock *Repos) Delete(ctx context.Context, p domain.Principal, name domain.RepoName) error { | 124 | + | func (_mock *RepoService) Delete(ctx context.Context, p domain.Principal, name domain.RepoName) error { |
| 125 | ret := _mock.Called(ctx, p, name) | 125 | ret := _mock.Called(ctx, p, name) | ||
| 126 | 126 | ||||
| 127 | if len(ret) == 0 { | 127 | if len(ret) == 0 { | ||
| @@ -137,8 +137,8 @@ func (_mock *Repos) Delete(ctx context.Context, p domain.Principal, name domain. | |||||
| 137 | return r0 | 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' | 140 | + | // RepoService_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' |
| 141 | - | type Repos_Delete_Call struct { | 141 | + | type RepoService_Delete_Call struct { |
| 142 | *mock.Call | 142 | *mock.Call | ||
| 143 | } | 143 | } | ||
| 144 | 144 | ||||
| @@ -146,11 +146,11 @@ type Repos_Delete_Call struct { | |||||
| 146 | // - ctx context.Context | 146 | // - ctx context.Context | ||
| 147 | // - p domain.Principal | 147 | // - p domain.Principal | ||
| 148 | // - name domain.RepoName | 148 | // - name domain.RepoName | ||
| 149 | - | func (_e *Repos_Expecter) Delete(ctx any, p any, name any) *Repos_Delete_Call { | 149 | + | func (_e *RepoService_Expecter) Delete(ctx any, p any, name any) *RepoService_Delete_Call { |
| 150 | - | return &Repos_Delete_Call{Call: _e.mock.On("Delete", ctx, p, name)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 154 | _c.Call.Run(func(args mock.Arguments) { | ||
| 155 | var arg0 context.Context | 155 | var arg0 context.Context | ||
| 156 | if args[0] != nil { | 156 | if args[0] != nil { | ||
| @@ -173,18 +173,18 @@ func (_c *Repos_Delete_Call) Run(run func(ctx context.Context, p domain.Principa | |||||
| 173 | return _c | 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 | _c.Call.Return(err) | 177 | _c.Call.Return(err) | ||
| 178 | return _c | 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 | _c.Call.Return(run) | 182 | _c.Call.Return(run) | ||
| 183 | return _c | 183 | return _c | ||
| 184 | } | 184 | } | ||
| 185 | 185 | ||||
| 186 | - | // Get provides a mock function for the type Repos | 186 | + | // Get provides a mock function for the type RepoService |
| 187 | - | func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { | 187 | + | func (_mock *RepoService) Get(ctx context.Context, p domain.Principal, name domain.RepoName) (domain.Repo, error) { |
| 188 | ret := _mock.Called(ctx, p, name) | 188 | ret := _mock.Called(ctx, p, name) | ||
| 189 | 189 | ||||
| 190 | if len(ret) == 0 { | 190 | if len(ret) == 0 { | ||
| @@ -209,8 +209,8 @@ func (_mock *Repos) Get(ctx context.Context, p domain.Principal, name domain.Rep | |||||
| 209 | return r0, r1 | 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' | 212 | + | // RepoService_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' |
| 213 | - | type Repos_Get_Call struct { | 213 | + | type RepoService_Get_Call struct { |
| 214 | *mock.Call | 214 | *mock.Call | ||
| 215 | } | 215 | } | ||
| 216 | 216 | ||||
| @@ -218,11 +218,11 @@ type Repos_Get_Call struct { | |||||
| 218 | // - ctx context.Context | 218 | // - ctx context.Context | ||
| 219 | // - p domain.Principal | 219 | // - p domain.Principal | ||
| 220 | // - name domain.RepoName | 220 | // - name domain.RepoName | ||
| 221 | - | func (_e *Repos_Expecter) Get(ctx any, p any, name any) *Repos_Get_Call { | 221 | + | func (_e *RepoService_Expecter) Get(ctx any, p any, name any) *RepoService_Get_Call { |
| 222 | - | return &Repos_Get_Call{Call: _e.mock.On("Get", ctx, p, name)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 226 | _c.Call.Run(func(args mock.Arguments) { | ||
| 227 | var arg0 context.Context | 227 | var arg0 context.Context | ||
| 228 | if args[0] != nil { | 228 | if args[0] != nil { | ||
| @@ -245,33 +245,33 @@ func (_c *Repos_Get_Call) Run(run func(ctx context.Context, p domain.Principal, | |||||
| 245 | return _c | 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 | _c.Call.Return(repo, err) | 249 | _c.Call.Return(repo, err) | ||
| 250 | return _c | 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 | _c.Call.Return(run) | 254 | _c.Call.Return(run) | ||
| 255 | return _c | 255 | return _c | ||
| 256 | } | 256 | } | ||
| 257 | 257 | ||||
| 258 | - | // ListPage provides a mock function for the type Repos | 258 | + | // ListPage provides a mock function for the type RepoService |
| 259 | - | func (_mock *Repos) ListPage(ctx context.Context, p domain.Principal, size int, token string) (app.RepoPage, error) { | 259 | + | func (_mock *RepoService) ListPage(ctx context.Context, p domain.Principal, size int, token string) (ports.RepoPage, error) { |
| 260 | ret := _mock.Called(ctx, p, size, token) | 260 | ret := _mock.Called(ctx, p, size, token) | ||
| 261 | 261 | ||||
| 262 | if len(ret) == 0 { | 262 | if len(ret) == 0 { | ||
| 263 | panic("no return value specified for ListPage") | 263 | panic("no return value specified for ListPage") | ||
| 264 | } | 264 | } | ||
| 265 | 265 | ||||
| 266 | - | var r0 app.RepoPage | 266 | + | var r0 ports.RepoPage |
| 267 | var r1 error | 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 | return returnFunc(ctx, p, size, token) | 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 | r0 = returnFunc(ctx, p, size, token) | 272 | r0 = returnFunc(ctx, p, size, token) | ||
| 273 | } else { | 273 | } else { | ||
| 274 | - | r0 = ret.Get(0).(app.RepoPage) | 274 | + | r0 = ret.Get(0).(ports.RepoPage) |
| 275 | } | 275 | } | ||
| 276 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, int, string) error); ok { | 276 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Principal, int, string) error); ok { | ||
| 277 | r1 = returnFunc(ctx, p, size, token) | 277 | r1 = returnFunc(ctx, p, size, token) | ||
| @@ -281,8 +281,8 @@ func (_mock *Repos) ListPage(ctx context.Context, p domain.Principal, size int, | |||||
| 281 | return r0, r1 | 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' | 284 | + | // RepoService_ListPage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListPage' |
| 285 | - | type Repos_ListPage_Call struct { | 285 | + | type RepoService_ListPage_Call struct { |
| 286 | *mock.Call | 286 | *mock.Call | ||
| 287 | } | 287 | } | ||
| 288 | 288 | ||||
| @@ -291,11 +291,11 @@ type Repos_ListPage_Call struct { | |||||
| 291 | // - p domain.Principal | 291 | // - p domain.Principal | ||
| 292 | // - size int | 292 | // - size int | ||
| 293 | // - token string | 293 | // - token string | ||
| 294 | - | func (_e *Repos_Expecter) ListPage(ctx any, p any, size any, token any) *Repos_ListPage_Call { | 294 | + | func (_e *RepoService_Expecter) ListPage(ctx any, p any, size any, token any) *RepoService_ListPage_Call { |
| 295 | - | return &Repos_ListPage_Call{Call: _e.mock.On("ListPage", ctx, p, size, token)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 299 | _c.Call.Run(func(args mock.Arguments) { | ||
| 300 | var arg0 context.Context | 300 | var arg0 context.Context | ||
| 301 | if args[0] != nil { | 301 | if args[0] != nil { | ||
| @@ -323,18 +323,18 @@ func (_c *Repos_ListPage_Call) Run(run func(ctx context.Context, p domain.Princi | |||||
| 323 | return _c | 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 | _c.Call.Return(repoPage, err) | 327 | _c.Call.Return(repoPage, err) | ||
| 328 | return _c | 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 | _c.Call.Return(run) | 332 | _c.Call.Return(run) | ||
| 333 | return _c | 333 | return _c | ||
| 334 | } | 334 | } | ||
| 335 | 335 | ||||
| 336 | - | // Update provides a mock function for the type Repos | 336 | + | // Update provides a mock function for the type RepoService |
| 337 | - | func (_mock *Repos) Update(ctx context.Context, p domain.Principal, name domain.RepoName, params app.UpdateParams) (domain.Repo, error) { | 337 | + | func (_mock *RepoService) Update(ctx context.Context, p domain.Principal, name domain.RepoName, params ports.UpdateRepoParams) (domain.Repo, error) { |
| 338 | ret := _mock.Called(ctx, p, name, params) | 338 | ret := _mock.Called(ctx, p, name, params) | ||
| 339 | 339 | ||||
| 340 | if len(ret) == 0 { | 340 | if len(ret) == 0 { | ||
| @@ -343,15 +343,15 @@ func (_mock *Repos) Update(ctx context.Context, p domain.Principal, name domain. | |||||
| 343 | 343 | ||||
| 344 | var r0 domain.Repo | 344 | var r0 domain.Repo | ||
| 345 | var r1 error | 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 | return returnFunc(ctx, p, name, params) | 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 | r0 = returnFunc(ctx, p, name, params) | 350 | r0 = returnFunc(ctx, p, name, params) | ||
| 351 | } else { | 351 | } else { | ||
| 352 | r0 = ret.Get(0).(domain.Repo) | 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 | r1 = returnFunc(ctx, p, name, params) | 355 | r1 = returnFunc(ctx, p, name, params) | ||
| 356 | } else { | 356 | } else { | ||
| 357 | r1 = ret.Error(1) | 357 | r1 = ret.Error(1) | ||
| @@ -359,8 +359,8 @@ func (_mock *Repos) Update(ctx context.Context, p domain.Principal, name domain. | |||||
| 359 | return r0, r1 | 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' | 362 | + | // RepoService_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' |
| 363 | - | type Repos_Update_Call struct { | 363 | + | type RepoService_Update_Call struct { |
| 364 | *mock.Call | 364 | *mock.Call | ||
| 365 | } | 365 | } | ||
| 366 | 366 | ||||
| @@ -368,12 +368,12 @@ type Repos_Update_Call struct { | |||||
| 368 | // - ctx context.Context | 368 | // - ctx context.Context | ||
| 369 | // - p domain.Principal | 369 | // - p domain.Principal | ||
| 370 | // - name domain.RepoName | 370 | // - name domain.RepoName | ||
| 371 | - | // - params app.UpdateParams | 371 | + | // - params ports.UpdateRepoParams |
| 372 | - | func (_e *Repos_Expecter) Update(ctx any, p any, name any, params any) *Repos_Update_Call { | 372 | + | func (_e *RepoService_Expecter) Update(ctx any, p any, name any, params any) *RepoService_Update_Call { |
| 373 | - | return &Repos_Update_Call{Call: _e.mock.On("Update", ctx, p, name, params)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 377 | _c.Call.Run(func(args mock.Arguments) { | ||
| 378 | var arg0 context.Context | 378 | var arg0 context.Context | ||
| 379 | if args[0] != nil { | 379 | if args[0] != nil { | ||
| @@ -387,9 +387,9 @@ func (_c *Repos_Update_Call) Run(run func(ctx context.Context, p domain.Principa | |||||
| 387 | if args[2] != nil { | 387 | if args[2] != nil { | ||
| 388 | arg2 = args[2].(domain.RepoName) | 388 | arg2 = args[2].(domain.RepoName) | ||
| 389 | } | 389 | } | ||
| 390 | - | var arg3 app.UpdateParams | 390 | + | var arg3 ports.UpdateRepoParams |
| 391 | if args[3] != nil { | 391 | if args[3] != nil { | ||
| 392 | - | arg3 = args[3].(app.UpdateParams) | 392 | + | arg3 = args[3].(ports.UpdateRepoParams) |
| 393 | } | 393 | } | ||
| 394 | run( | 394 | run( | ||
| 395 | arg0, | 395 | arg0, | ||
| @@ -401,33 +401,33 @@ func (_c *Repos_Update_Call) Run(run func(ctx context.Context, p domain.Principa | |||||
| 401 | return _c | 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 | _c.Call.Return(repo, err) | 405 | _c.Call.Return(repo, err) | ||
| 406 | return _c | 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 | _c.Call.Return(run) | 410 | _c.Call.Return(run) | ||
| 411 | return _c | 411 | return _c | ||
| 412 | } | 412 | } | ||
| 413 | 413 | ||||
| 414 | - | // View provides a mock function for the type Repos | 414 | + | // View provides a mock function for the type RepoService |
| 415 | - | func (_mock *Repos) View(ctx context.Context, repo domain.Repo) (app.RepoView, error) { | 415 | + | func (_mock *RepoService) View(ctx context.Context, repo domain.Repo) (ports.RepoView, error) { |
| 416 | ret := _mock.Called(ctx, repo) | 416 | ret := _mock.Called(ctx, repo) | ||
| 417 | 417 | ||||
| 418 | if len(ret) == 0 { | 418 | if len(ret) == 0 { | ||
| 419 | panic("no return value specified for View") | 419 | panic("no return value specified for View") | ||
| 420 | } | 420 | } | ||
| 421 | 421 | ||||
| 422 | - | var r0 app.RepoView | 422 | + | var r0 ports.RepoView |
| 423 | var r1 error | 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 | return returnFunc(ctx, repo) | 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 | r0 = returnFunc(ctx, repo) | 428 | r0 = returnFunc(ctx, repo) | ||
| 429 | } else { | 429 | } else { | ||
| 430 | - | r0 = ret.Get(0).(app.RepoView) | 430 | + | r0 = ret.Get(0).(ports.RepoView) |
| 431 | } | 431 | } | ||
| 432 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Repo) error); ok { | 432 | if returnFunc, ok := ret.Get(1).(func(context.Context, domain.Repo) error); ok { | ||
| 433 | r1 = returnFunc(ctx, repo) | 433 | r1 = returnFunc(ctx, repo) | ||
| @@ -437,19 +437,19 @@ func (_mock *Repos) View(ctx context.Context, repo domain.Repo) (app.RepoView, e | |||||
| 437 | return r0, r1 | 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' | 440 | + | // RepoService_View_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'View' |
| 441 | - | type Repos_View_Call struct { | 441 | + | type RepoService_View_Call struct { |
| 442 | *mock.Call | 442 | *mock.Call | ||
| 443 | } | 443 | } | ||
| 444 | 444 | ||||
| 445 | // View is a helper method to define mock.On call | 445 | // View is a helper method to define mock.On call | ||
| 446 | // - ctx context.Context | 446 | // - ctx context.Context | ||
| 447 | // - repo domain.Repo | 447 | // - repo domain.Repo | ||
| 448 | - | func (_e *Repos_Expecter) View(ctx any, repo any) *Repos_View_Call { | 448 | + | func (_e *RepoService_Expecter) View(ctx any, repo any) *RepoService_View_Call { |
| 449 | - | return &Repos_View_Call{Call: _e.mock.On("View", ctx, repo)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 453 | _c.Call.Run(func(args mock.Arguments) { | ||
| 454 | var arg0 context.Context | 454 | var arg0 context.Context | ||
| 455 | if args[0] != nil { | 455 | if args[0] != nil { | ||
| @@ -467,12 +467,12 @@ func (_c *Repos_View_Call) Run(run func(ctx context.Context, repo domain.Repo)) | |||||
| 467 | return _c | 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 | _c.Call.Return(repoView, err) | 471 | _c.Call.Return(repoView, err) | ||
| 472 | return _c | 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 | _c.Call.Return(run) | 476 | _c.Call.Return(run) | ||
| 477 | return _c | 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 | mock "github.com/stretchr/testify/mock" | 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 | // The first argument is typically a *testing.T value. | 15 | // The first argument is typically a *testing.T value. | ||
| 16 | - | func NewSessionAuth(t interface { | 16 | + | func NewWebSessionService(t interface { |
| 17 | mock.TestingT | 17 | mock.TestingT | ||
| 18 | Cleanup(func()) | 18 | Cleanup(func()) | ||
| 19 | - | }) *SessionAuth { | 19 | + | }) *WebSessionService { |
| 20 | if helper, ok := t.(interface{ Helper() }); ok { | 20 | if helper, ok := t.(interface{ Helper() }); ok { | ||
| 21 | helper.Helper() | 21 | helper.Helper() | ||
| 22 | } | 22 | } | ||
| 23 | 23 | ||||
| 24 | - | mock := &SessionAuth{} | 24 | + | mock := &WebSessionService{} |
| 25 | mock.Mock.Test(t) | 25 | mock.Mock.Test(t) | ||
| 26 | 26 | ||||
| 27 | t.Cleanup(func() { | 27 | t.Cleanup(func() { | ||
| @@ -34,21 +34,21 @@ func NewSessionAuth(t interface { | |||||
| 34 | return mock | 34 | return mock | ||
| 35 | } | 35 | } | ||
| 36 | 36 | ||||
| 37 | - | // SessionAuth is an autogenerated mock type for the SessionAuth type | 37 | + | // WebSessionService is an autogenerated mock type for the WebSessionService type |
| 38 | - | type SessionAuth struct { | 38 | + | type WebSessionService struct { |
| 39 | mock.Mock | 39 | mock.Mock | ||
| 40 | } | 40 | } | ||
| 41 | 41 | ||||
| 42 | - | type SessionAuth_Expecter struct { | 42 | + | type WebSessionService_Expecter struct { |
| 43 | mock *mock.Mock | 43 | mock *mock.Mock | ||
| 44 | } | 44 | } | ||
| 45 | 45 | ||||
| 46 | - | func (_m *SessionAuth) EXPECT() *SessionAuth_Expecter { | 46 | + | func (_m *WebSessionService) EXPECT() *WebSessionService_Expecter { |
| 47 | - | return &SessionAuth_Expecter{mock: &_m.Mock} | 47 | + | return &WebSessionService_Expecter{mock: &_m.Mock} |
| 48 | } | 48 | } | ||
| 49 | 49 | ||||
| 50 | - | // Login provides a mock function for the type SessionAuth | 50 | + | // Login provides a mock function for the type WebSessionService |
| 51 | - | func (_mock *SessionAuth) Login(ctx context.Context, nonce string) (string, time.Duration, error) { | 51 | + | func (_mock *WebSessionService) Login(ctx context.Context, nonce string) (string, time.Duration, error) { |
| 52 | ret := _mock.Called(ctx, nonce) | 52 | ret := _mock.Called(ctx, nonce) | ||
| 53 | 53 | ||||
| 54 | if len(ret) == 0 { | 54 | if len(ret) == 0 { | ||
| @@ -79,19 +79,19 @@ func (_mock *SessionAuth) Login(ctx context.Context, nonce string) (string, time | |||||
| 79 | return r0, r1, r2 | 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' | 82 | + | // WebSessionService_Login_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Login' |
| 83 | - | type SessionAuth_Login_Call struct { | 83 | + | type WebSessionService_Login_Call struct { |
| 84 | *mock.Call | 84 | *mock.Call | ||
| 85 | } | 85 | } | ||
| 86 | 86 | ||||
| 87 | // Login is a helper method to define mock.On call | 87 | // Login is a helper method to define mock.On call | ||
| 88 | // - ctx context.Context | 88 | // - ctx context.Context | ||
| 89 | // - nonce string | 89 | // - nonce string | ||
| 90 | - | func (_e *SessionAuth_Expecter) Login(ctx any, nonce any) *SessionAuth_Login_Call { | 90 | + | func (_e *WebSessionService_Expecter) Login(ctx any, nonce any) *WebSessionService_Login_Call { |
| 91 | - | return &SessionAuth_Login_Call{Call: _e.mock.On("Login", ctx, nonce)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 95 | _c.Call.Run(func(args mock.Arguments) { | ||
| 96 | var arg0 context.Context | 96 | var arg0 context.Context | ||
| 97 | if args[0] != nil { | 97 | if args[0] != nil { | ||
| @@ -109,18 +109,18 @@ func (_c *SessionAuth_Login_Call) Run(run func(ctx context.Context, nonce string | |||||
| 109 | return _c | 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 | _c.Call.Return(token, lifetime, err) | 113 | _c.Call.Return(token, lifetime, err) | ||
| 114 | return _c | 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 | _c.Call.Return(run) | 118 | _c.Call.Return(run) | ||
| 119 | return _c | 119 | return _c | ||
| 120 | } | 120 | } | ||
| 121 | 121 | ||||
| 122 | - | // LoginLinkValid provides a mock function for the type SessionAuth | 122 | + | // LoginLinkValid provides a mock function for the type WebSessionService |
| 123 | - | func (_mock *SessionAuth) LoginLinkValid(nonce string) bool { | 123 | + | func (_mock *WebSessionService) LoginLinkValid(nonce string) bool { |
| 124 | ret := _mock.Called(nonce) | 124 | ret := _mock.Called(nonce) | ||
| 125 | 125 | ||||
| 126 | if len(ret) == 0 { | 126 | if len(ret) == 0 { | ||
| @@ -136,18 +136,18 @@ func (_mock *SessionAuth) LoginLinkValid(nonce string) bool { | |||||
| 136 | return r0 | 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' | 139 | + | // WebSessionService_LoginLinkValid_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LoginLinkValid' |
| 140 | - | type SessionAuth_LoginLinkValid_Call struct { | 140 | + | type WebSessionService_LoginLinkValid_Call struct { |
| 141 | *mock.Call | 141 | *mock.Call | ||
| 142 | } | 142 | } | ||
| 143 | 143 | ||||
| 144 | // LoginLinkValid is a helper method to define mock.On call | 144 | // LoginLinkValid is a helper method to define mock.On call | ||
| 145 | // - nonce string | 145 | // - nonce string | ||
| 146 | - | func (_e *SessionAuth_Expecter) LoginLinkValid(nonce any) *SessionAuth_LoginLinkValid_Call { | 146 | + | func (_e *WebSessionService_Expecter) LoginLinkValid(nonce any) *WebSessionService_LoginLinkValid_Call { |
| 147 | - | return &SessionAuth_LoginLinkValid_Call{Call: _e.mock.On("LoginLinkValid", nonce)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 151 | _c.Call.Run(func(args mock.Arguments) { | ||
| 152 | var arg0 string | 152 | var arg0 string | ||
| 153 | if args[0] != nil { | 153 | if args[0] != nil { | ||
| @@ -160,18 +160,18 @@ func (_c *SessionAuth_LoginLinkValid_Call) Run(run func(nonce string)) *SessionA | |||||
| 160 | return _c | 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 | _c.Call.Return(b) | 164 | _c.Call.Return(b) | ||
| 165 | return _c | 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 | _c.Call.Return(run) | 169 | _c.Call.Return(run) | ||
| 170 | return _c | 170 | return _c | ||
| 171 | } | 171 | } | ||
| 172 | 172 | ||||
| 173 | - | // Verify provides a mock function for the type SessionAuth | 173 | + | // Verify provides a mock function for the type WebSessionService |
| 174 | - | func (_mock *SessionAuth) Verify(ctx context.Context, token string) (context.Context, bool, error) { | 174 | + | func (_mock *WebSessionService) Verify(ctx context.Context, token string) (context.Context, bool, error) { |
| 175 | ret := _mock.Called(ctx, token) | 175 | ret := _mock.Called(ctx, token) | ||
| 176 | 176 | ||||
| 177 | if len(ret) == 0 { | 177 | if len(ret) == 0 { | ||
| @@ -204,19 +204,19 @@ func (_mock *SessionAuth) Verify(ctx context.Context, token string) (context.Con | |||||
| 204 | return r0, r1, r2 | 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' | 207 | + | // WebSessionService_Verify_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Verify' |
| 208 | - | type SessionAuth_Verify_Call struct { | 208 | + | type WebSessionService_Verify_Call struct { |
| 209 | *mock.Call | 209 | *mock.Call | ||
| 210 | } | 210 | } | ||
| 211 | 211 | ||||
| 212 | // Verify is a helper method to define mock.On call | 212 | // Verify is a helper method to define mock.On call | ||
| 213 | // - ctx context.Context | 213 | // - ctx context.Context | ||
| 214 | // - token string | 214 | // - token string | ||
| 215 | - | func (_e *SessionAuth_Expecter) Verify(ctx any, token any) *SessionAuth_Verify_Call { | 215 | + | func (_e *WebSessionService_Expecter) Verify(ctx any, token any) *WebSessionService_Verify_Call { |
| 216 | - | return &SessionAuth_Verify_Call{Call: _e.mock.On("Verify", ctx, token)} | 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 | _c.Call.Run(func(args mock.Arguments) { | 220 | _c.Call.Run(func(args mock.Arguments) { | ||
| 221 | var arg0 context.Context | 221 | var arg0 context.Context | ||
| 222 | if args[0] != nil { | 222 | if args[0] != nil { | ||
| @@ -234,12 +234,12 @@ func (_c *SessionAuth_Verify_Call) Run(run func(ctx context.Context, token strin | |||||
| 234 | return _c | 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 | _c.Call.Return(owner, ok, err) | 238 | _c.Call.Return(owner, ok, err) | ||
| 239 | return _c | 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 | _c.Call.Return(run) | 243 | _c.Call.Return(run) | ||
| 244 | return _c | 244 | return _c | ||
| 245 | } | 245 | } | ||
M internal/ports/ports.go +9 -2
| @@ -1,7 +1,14 @@ | |||||
| 1 | // SPDX-License-Identifier: AGPL-3.0-or-later | 1 | // SPDX-License-Identifier: AGPL-3.0-or-later | ||
| 2 | 2 | ||||
| 3 | - | // Package ports declares the interfaces the use cases need from the outside | 3 | + | // Package ports declares every interface that crosses a layer, and the |
| 4 | - | // world. Adapters implement them; cmd wires them. | 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 | package ports | 12 | package ports | ||
| 6 | 13 | ||||
| 7 | import ( | 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 | + | } | |||