| ... | ... | @@ -496,6 +496,91 @@ it.effect("coalesces concurrent ref pages into one repository snapshot", () => |
| 496 | 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 | 584 | it.effect("retries an in-flight ref snapshot invalidated by a mutation", () => |
| 500 | 585 | Effect.scoped( |
| 501 | 586 | Effect.gen(function* () { |