test(app): give the concurrent push test one receive-pack slot per push
TestAC4PostReceiveAttribution pushes 4 repositories at once, but the default receive-pack slots are max(2, GOMAXPROCS/2): on a 2-4 CPU runner two pushes were refused with "server busy". A test-only wiring option sets the slots to the number of pushes.
2 files · +18 -12
M internal/app/e2e_test.go +5 -3
| @@ -324,11 +324,13 @@ func TestAC4HooksUnknownTokenAndMissingBinary(t *testing.T) { | |||
| 324 | 324 | } | |
| 325 | 325 | ||
| 326 | 326 | func TestAC4PostReceiveAttribution(t *testing.T) { | |
| 327 | - | h := newHarness(t, harnessOpts{}) | |
| 327 | + | // Four repositories, pushed at the same time with different refs. The | |
| 328 | + | // default receive-pack slots follow GOMAXPROCS (2 on a small runner), so | |
| 329 | + | // the test sets enough for every push to run at once. | |
| 330 | + | const n = 4 | |
| 331 | + | h := newHarnessWith(t, harnessOpts{}, func(o *options) { o.receivePacks = n }) | |
| 328 | 332 | events := h.forge.Bus.Subscribe(h.ctx) | |
| 329 | 333 | ||
| 330 | - | // Two repositories, pushed at the same time with different refs. | |
| 331 | - | const n = 4 | |
| 332 | 334 | type job struct { | |
| 333 | 335 | repo, branch string | |
| 334 | 336 | wt string | |
| @@ -324,11 +324,13 @@ func TestAC4HooksUnknownTokenAndMissingBinary(t *testing.T) { | |||||
| 324 | } | 324 | } | ||
| 325 | 325 | ||||
| 326 | func TestAC4PostReceiveAttribution(t *testing.T) { | 326 | func TestAC4PostReceiveAttribution(t *testing.T) { | ||
| 327 | - | h := newHarness(t, harnessOpts{}) | 327 | + | // Four repositories, pushed at the same time with different refs. The |
| 328 | + | // default receive-pack slots follow GOMAXPROCS (2 on a small runner), so | |||
| 329 | + | // the test sets enough for every push to run at once. | |||
| 330 | + | const n = 4 | |||
| 331 | + | h := newHarnessWith(t, harnessOpts{}, func(o *options) { o.receivePacks = n }) | |||
| 328 | events := h.forge.Bus.Subscribe(h.ctx) | 332 | events := h.forge.Bus.Subscribe(h.ctx) | ||
| 329 | 333 | ||||
| 330 | - | // Two repositories, pushed at the same time with different refs. | |||
| 331 | - | const n = 4 | |||
| 332 | type job struct { | 334 | type job struct { | ||
| 333 | repo, branch string | 335 | repo, branch string | ||
| 334 | wt string | 336 | wt string | ||
M internal/app/forge.go +13 -9
| @@ -63,6 +63,9 @@ type options struct { | |||
| 63 | 63 | // archivesPerClient overrides the archives one client downloads at once | |
| 64 | 64 | // when positive. | |
| 65 | 65 | archivesPerClient int | |
| 66 | + | // receivePacks overrides the git-receive-pack backends running at once | |
| 67 | + | // when positive (the default follows GOMAXPROCS). | |
| 68 | + | receivePacks int | |
| 66 | 69 | // remote replaces the lister of github.com refs (tests never reach the | |
| 67 | 70 | // network). | |
| 68 | 71 | remoteLister ports.GitRemote | |
| @@ -420,15 +423,16 @@ func newForge(ctx context.Context, cfg config.Config, opts options) (_ *forge, e | |||
| 420 | 423 | }) | |
| 421 | 424 | ||
| 422 | 425 | gh := githttp.New(githttp.Config{ | |
| 423 | - | Auth: f.Auth, | |
| 424 | - | Repos: f.Repos, | |
| 425 | - | Pushes: f.Pushes, | |
| 426 | - | Backend: git, | |
| 427 | - | Owner: cfg.Owner, | |
| 428 | - | Hooks: f.hooks, | |
| 429 | - | TrustedProxies: cfg.TrustedProxies, | |
| 430 | - | Limiter: limiter, | |
| 431 | - | MaxBodyBytes: maxBody, | |
| 426 | + | Auth: f.Auth, | |
| 427 | + | Repos: f.Repos, | |
| 428 | + | Pushes: f.Pushes, | |
| 429 | + | Backend: git, | |
| 430 | + | Owner: cfg.Owner, | |
| 431 | + | Hooks: f.hooks, | |
| 432 | + | TrustedProxies: cfg.TrustedProxies, | |
| 433 | + | Limiter: limiter, | |
| 434 | + | MaxBodyBytes: maxBody, | |
| 435 | + | MaxReceivePacks: opts.receivePacks, | |
| 432 | 436 | }) | |
| 433 | 437 | routes := make([]httpserver.Route, 0, 2*len(githttp.Patterns)+len(githubapi.Patterns)+len(oidchttp.Patterns)+len(web.Patterns)) | |
| 434 | 438 | for _, p := range githttp.Patterns { | |
| @@ -63,6 +63,9 @@ type options struct { | |||||
| 63 | // archivesPerClient overrides the archives one client downloads at once | 63 | // archivesPerClient overrides the archives one client downloads at once | ||
| 64 | // when positive. | 64 | // when positive. | ||
| 65 | archivesPerClient int | 65 | archivesPerClient int | ||
| 66 | + | // receivePacks overrides the git-receive-pack backends running at once | |||
| 67 | + | // when positive (the default follows GOMAXPROCS). | |||
| 68 | + | receivePacks int | |||
| 66 | // remote replaces the lister of github.com refs (tests never reach the | 69 | // remote replaces the lister of github.com refs (tests never reach the | ||
| 67 | // network). | 70 | // network). | ||
| 68 | remoteLister ports.GitRemote | 71 | remoteLister ports.GitRemote | ||
| @@ -420,15 +423,16 @@ func newForge(ctx context.Context, cfg config.Config, opts options) (_ *forge, e | |||||
| 420 | }) | 423 | }) | ||
| 421 | 424 | ||||
| 422 | gh := githttp.New(githttp.Config{ | 425 | gh := githttp.New(githttp.Config{ | ||
| 423 | - | Auth: f.Auth, | 426 | + | Auth: f.Auth, |
| 424 | - | Repos: f.Repos, | 427 | + | Repos: f.Repos, |
| 425 | - | Pushes: f.Pushes, | 428 | + | Pushes: f.Pushes, |
| 426 | - | Backend: git, | 429 | + | Backend: git, |
| 427 | - | Owner: cfg.Owner, | 430 | + | Owner: cfg.Owner, |
| 428 | - | Hooks: f.hooks, | 431 | + | Hooks: f.hooks, |
| 429 | - | TrustedProxies: cfg.TrustedProxies, | 432 | + | TrustedProxies: cfg.TrustedProxies, |
| 430 | - | Limiter: limiter, | 433 | + | Limiter: limiter, |
| 431 | - | MaxBodyBytes: maxBody, | 434 | + | MaxBodyBytes: maxBody, |
| 435 | + | MaxReceivePacks: opts.receivePacks, | |||
| 432 | }) | 436 | }) | ||
| 433 | routes := make([]httpserver.Route, 0, 2*len(githttp.Patterns)+len(githubapi.Patterns)+len(oidchttp.Patterns)+len(web.Patterns)) | 437 | routes := make([]httpserver.Route, 0, 2*len(githttp.Patterns)+len(githubapi.Patterns)+len(oidchttp.Patterns)+len(web.Patterns)) | ||
| 434 | for _, p := range githttp.Patterns { | 438 | for _, p := range githttp.Patterns { | ||