| ... | @@ -496,6 +496,91 @@ it.effect("coalesces concurrent ref pages into one repository snapshot", () => | ... | @@ -496,6 +496,91 @@ it.effect("coalesces concurrent ref pages into one repository snapshot", () => |
| 496 | ).pipe(Effect.provide(layerServerConfig.pipe(Layer.provideMerge(NodeServices.layer)))), | 496 | ).pipe(Effect.provide(layerServerConfig.pipe(Layer.provideMerge(NodeServices.layer)))), |
| 497 | ); | 497 | ); |
| 498 | | 498 | |
| | 499 | describe("pull output beyond the output cap", () => { |
| | 500 | // A fast-forward that prints over 1 MB takes thousands of files, so the real pull's output is |
| | 501 | // padded past the cap instead. |
| | 502 | const withPaddedPull = (stream: "stdout" | "stderr") => |
| | 503 | Effect.gen(function* () { |
| | 504 | const delegate = yield* ChildProcessSpawner.ChildProcessSpawner; |
| | 505 | const padding = new Uint8Array(1_000_001).fill(0x20); |
| | 506 | const paddingSpawner = ChildProcessSpawner.make((command) => |
| | 507 | Effect.gen(function* () { |
| | 508 | const handle = yield* delegate.spawn(command); |
| | 509 | const isPull = |
| | 510 | ChildProcess.isStandardCommand(command) && |
| | 511 | command.args.includes("pull") && |
| | 512 | command.args.includes("--ff-only"); |
| | 513 | return isPull |
| | 514 | ? ChildProcessSpawner.makeHandle({ |
| | 515 | ...handle, |
| | 516 | [stream]: Stream.concat(handle[stream], Stream.make(padding)), |
| | 517 | }) |
| | 518 | : handle; |
| | 519 | }), |
| | 520 | ); |
| | 521 | return yield* makeGitVcsDriverCore().pipe( |
| | 522 | Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, paddingSpawner), |
| | 523 | ); |
| | 524 | }); |
| | 525 | |
| | 526 | const cloneBehindRemote = Effect.gen(function* () { |
| | 527 | const cwd = yield* makeTmpDir(); |
| | 528 | const remote = yield* makeTmpDir("git-vcs-driver-remote-"); |
| | 529 | const updater = yield* makeTmpDir("git-vcs-driver-updater-"); |
| | 530 | const { initialBranch } = yield* initRepoWithCommit(cwd); |
| | 531 | yield* git(remote, ["init", "--bare"]); |
| | 532 | yield* git(cwd, ["remote", "add", "origin", remote]); |
| | 533 | yield* git(cwd, ["push", "-u", "origin", initialBranch]); |
| | 534 | yield* git(updater, ["clone", remote, "."]); |
| | 535 | yield* git(updater, ["config", "user.email", "test@test.com"]); |
| | 536 | yield* git(updater, ["config", "user.name", "Test"]); |
| | 537 | yield* writeTextFile(updater, "remote.txt", "remote\n"); |
| | 538 | yield* git(updater, ["add", "remote.txt"]); |
| | 539 | yield* git(updater, ["commit", "-m", "remote commit"]); |
| | 540 | yield* git(updater, ["push", "origin", initialBranch]); |
| | 541 | return { cwd, remoteHead: yield* git(updater, ["rev-parse", "HEAD"]) }; |
| | 542 | }); |
| | 543 | |
| | 544 | it.effect.each(["stdout", "stderr"] as const)( |
| | 545 | "reports a fast-forward whose %s passes the cap as pulled", |
| | 546 | (stream) => |
| | 547 | Effect.scoped( |
| | 548 | Effect.gen(function* () { |
| | 549 | const driver = yield* withPaddedPull(stream); |
| | 550 | yield* Effect.gen(function* () { |
| | 551 | const { cwd, remoteHead } = yield* cloneBehindRemote; |
| | 552 | |
| | 553 | const result = yield* driver.pullCurrentBranch(cwd); |
| | 554 | |
| | 555 | assert.equal(result.status, "pulled"); |
| | 556 | assert.equal(yield* git(cwd, ["rev-parse", "HEAD"]), remoteHead); |
| | 557 | }).pipe(Effect.provideService(GitVcsDriver.GitVcsDriver, driver)); |
| | 558 | }), |
| | 559 | ).pipe(Effect.provide(layerServerConfig.pipe(Layer.provideMerge(NodeServices.layer)))), |
| | 560 | ); |
| | 561 | |
| | 562 | it.effect("still fails a pull that Git rejects, whatever its output size", () => |
| | 563 | Effect.scoped( |
| | 564 | Effect.gen(function* () { |
| | 565 | const driver = yield* withPaddedPull("stderr"); |
| | 566 | yield* Effect.gen(function* () { |
| | 567 | const { cwd } = yield* cloneBehindRemote; |
| | 568 | // A local commit the remote lacks: `pull --ff-only` cannot fast-forward and exits 128. |
| | 569 | yield* writeTextFile(cwd, "local.txt", "local\n"); |
| | 570 | yield* git(cwd, ["add", "local.txt"]); |
| | 571 | yield* git(cwd, ["commit", "-m", "local commit"]); |
| | 572 | |
| | 573 | const error = yield* Effect.flip(driver.pullCurrentBranch(cwd)); |
| | 574 | |
| | 575 | assert.equal(error.operation, "GitVcsDriver.pullCurrentBranch.pull"); |
| | 576 | assert.equal(error.exitCode, 128); |
| | 577 | assert.notInclude(error.detail, "exceeded"); |
| | 578 | }).pipe(Effect.provideService(GitVcsDriver.GitVcsDriver, driver)); |
| | 579 | }), |
| | 580 | ).pipe(Effect.provide(layerServerConfig.pipe(Layer.provideMerge(NodeServices.layer)))), |
| | 581 | ); |
| | 582 | }); |
| | 583 | |
| 499 | it.effect("retries an in-flight ref snapshot invalidated by a mutation", () => | 584 | it.effect("retries an in-flight ref snapshot invalidated by a mutation", () => |
| 500 | Effect.scoped( | 585 | Effect.scoped( |
| 501 | Effect.gen(function* () { | 586 | Effect.gen(function* () { |