@mark1russell7/harness 0.15.1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as ProxyHop, A as ImageSource, At as Subject, B as LoadStream, C as Hop, Ct as RunTopology, D as HopWrite, Dt as ShippedImage, E as HopSignal, Et as Shipped, F as LineCount, Ft as isHopPlace, G as Outcomes, H as MiddleboxExpectation, I as LineMatch, It as latestEndOf, J as PausePrediction, K as Pair, L as LoadBand, M as Kafka, Mt as Topology, N as KafkaPause, Nt as Toxic, O as HostSysctl, Ot as Stage, P as KernelRecord, Pt as WsProbe, Q as ProbeEvent, R as LoadPlan, S as GroupRole, St as RunStream, T as HopPlace, Tt as SentinelStage, U as MiddleboxForm, V as MiddleboxEvent, W as Observer, X as PortsPrediction, Y as PinnedImage, Z as Prediction, _ as Fault, _t as RunFabric, a as ClientCapability, at as Reconnects, b as GroupPlace, bt as RunPause, c as ClusterClientAt, ct as ReplicaSet, d as CountBand, dt as RequestPrediction, et as ProxyTime, f as Drill, ft as RouterHop, g as FabricManifest, gt as RunDrill, h as Fabric, ht as RunBackup, i as Client, it as QueuePrediction, j as Jitter, jt as Target, k as HttpProbe, kt as StageBand, l as ClusterStage, lt as ReplicaSetStage, m as DriverStep, mt as Run, n as CLIENT_CAPABILITIES, nt as QueueConnection, o as ClientImage, ot as Recovers, p as DriverBand, pt as RttRange, q as PauseBand, r as Cell, rt as QueueEnd, s as Cluster, st as Reference, t as BuildImage, tt as QueueBand, u as ConntrackPrediction, ut as Replies, v as FaultPlace, vt as RunGroup, w as HopEvent, wt as SentinelEvent, x as GroupPrediction, xt as RunRoute, y as Group, yt as RunPart, z as LoadPrediction } from "./cell-biffSiEJ.js";
1
+ import { $ as ProbeEvent, A as HttpProbe, At as StageBand, B as LoadPrediction, C as GroupRole, Ct as RunStream, D as HopSignal, Dt as Shipped, E as HopPlace, Et as SentinelStage, F as KernelRecord, Ft as WsProbe, G as Observer, H as MiddleboxEvent, I as LineCount, It as environmentProblems, J as PauseBand, K as Outcomes, L as LineMatch, Lt as isHopPlace, M as Jitter, Mt as Target, N as Kafka, Nt as Topology, O as HopWrite, Ot as ShippedImage, P as KafkaPause, Pt as Toxic, Q as Prediction, R as LoadBand, Rt as latestEndOf, S as GroupPrediction, St as RunRoute, T as HopEvent, Tt as SentinelEvent, U as MiddleboxExpectation, V as LoadStream, W as MiddleboxForm, X as PinnedImage, Y as PausePrediction, Z as PortsPrediction, _ as FabricManifest, _t as RunDrill, a as ClientCapability, at as QueuePrediction, b as Group, bt as RunPart, c as ClusterClientAt, ct as Reference, d as CountBand, dt as Replies, et as ProxyHop, f as Drill, ft as RequestPrediction, g as Fabric, gt as RunBackup, h as DriverStep, ht as Run, i as Client, it as QueueEnd, j as ImageSource, jt as Subject, k as HostSysctl, kt as Stage, l as ClusterStage, lt as ReplicaSet, m as DriverBand, mt as RttRange, n as CLIENT_CAPABILITIES, nt as QueueBand, o as ClientImage, ot as Reconnects, p as DrillRoom, pt as RouterHop, q as Pair, r as Cell, rt as QueueConnection, s as Cluster, st as Recovers, t as BuildImage, tt as ProxyTime, u as ConntrackPrediction, ut as ReplicaSetStage, v as Fault, vt as RunFabric, w as Hop, wt as RunTopology, x as GroupPlace, xt as RunPause, y as FaultPlace, yt as RunGroup, z as LoadPlan } from "./cell-BmqDPjz3.js";
2
2
  import { Quantity } from "@mark1russell7/quantity";
3
3
  import { LoadMeasure, Schedule } from "@mark1russell7/rigor-chaos";
4
4
  import { StartedTestContainer } from "testcontainers";
@@ -451,6 +451,17 @@ export declare const measurePause: (run: Run, prediction: PausePrediction) => Me
451
451
  export declare const SEED_DOCUMENT = 65536;
452
452
  /** This count is how far the lost writes can be from the writes after the last backup: the writes in flight at the fault. */
453
453
  export declare const LOSS_MARGIN = 2;
454
+ /**
455
+ * This function gives the most disk that a drill needs, from the disk that it can use. The peak comes
456
+ * before the fault. Then each member holds the data and its oplog, and the backup host holds the
457
+ * dump. The seed goes through the oplog, thus each oplog holds the data up to its own size. The
458
+ * slices are small: the writes of one client in a few seconds.
459
+ */
460
+ export declare const roomNeeded: (drill: Drill, members: number, disk: Quantity) => Quantity;
461
+ /** This function gives MemAvailable from the text of `/proc/meminfo`. */
462
+ export declare const memAvailableOf: (meminfo: string) => Quantity;
463
+ /** This function gives the reason that a drill has no room on its runner, or null. A record from before SYS-97 has no room, and it is not void for this reason. */
464
+ export declare const roomVoidOf: (room: DrillRoom | undefined) => string | null;
454
465
  /** This function gives the time of a drill from the start of the backups to the fault, in seconds. */
455
466
  export declare const drillSpan: (drill: Drill) => number;
456
467
  /**
@@ -1464,9 +1475,11 @@ export declare const targetImageOf: (target: Target) => Promise<string>;
1464
1475
  * A lab in a guest of QEMU writes E4 (`substrateHere`). The other layers do not have a runner at this
1465
1476
  * time.
1466
1477
  */
1467
- type Layer = "E0" | "E1" | "E2" | "E3" | "E4" | "E5" | "E6";
1478
+ export declare const LAYERS: readonly ["E0", "E1", "E2", "E3", "E4", "E5", "E6"];
1479
+ type Layer = (typeof LAYERS)[number];
1468
1480
  /** A cloud is where the runner operates. GitHub can schedule a standard Linux job on Azure or on AWS. */
1469
- type Cloud = "azure" | "aws" | "unknown";
1481
+ export declare const CLOUDS: readonly ["azure", "aws", "unknown"];
1482
+ type Cloud = (typeof CLOUDS)[number];
1470
1483
  /** A host is what a process reads about its own machine. */
1471
1484
  interface Host {
1472
1485
  /** This text is the kernel release. */
@@ -2699,6 +2712,12 @@ export declare const QUIET_MS = 250;
2699
2712
  export declare const LINGER_MS = 1e3;
2700
2713
  /** This function divides a count of runs across environments, as equally as possible. */
2701
2714
  export declare const spread: (runs: number, environments: number) => number[];
2715
+ /**
2716
+ * This function gives the count of runs of each new environment of a cell, for `runs` more runs. A
2717
+ * pair cell has an environment for each run, because its run promotes the standby. Other cells
2718
+ * go across their environments, and at least one for each environment at the same time.
2719
+ */
2720
+ export declare const environmentCounts: (cell: Cell, runs: number) => number[];
2702
2721
  /**
2703
2722
  * This function does the runs of a cell. They go across new environments, and each environment records
2704
2723
  * its manifest. Then the verdict judges the runs. A median across the edge of the band extends
@@ -2710,5 +2729,5 @@ export declare const spread: (runs: number, environments: number) => number[];
2710
2729
  */
2711
2730
  export declare const runCell: (cell: Cell, say?: (line: string) => void) => Promise<CellResult>;
2712
2731
  //#endregion
2713
- export { type Agent, type BuildImage, type BuildRecord, CLIENT_CAPABILITIES, type CallReading, type Cell, type CellResult, type Client, type ClientCapability, type ClientImage, type ClockPair, type Cloud, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type ConntrackPrediction, type ConntrackReading, type ContextFile, type CountBand, type Crossings, type Cut, type Decision, type Drill, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type EstimateVerdict, type Fabric, type FabricLab, type FabricManifest, type FabricParts, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type Hop, type HopEvent, type HopPlace, type HopSignal, type HopWrite, type Host, type HostSetting, type HostSysctl, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type Jitter, type Kafka, type KafkaLab, type KafkaMember, type KafkaPause, type KernelRecord, type Lab, type Layer, type LeafViews, type LineCount, type LineMatch, type LoadBand, type LoadJudgement, type LoadPlan, type LoadPrediction, type LoadSpread, type LoadStream, type LoadVerdict, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type OplogRead, type OplogTime, type Outcome, type Outcomes, type Pair, type PairSets, type Pairing, type PartitionView, type PauseBand, type PauseCommit, type PausePrediction, type PauseReading, type Pinnable, type PinnedImage, type PortsPrediction, type PortsReading, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type QueueBand, type QueueConnection, type QueueConnectionReading, type QueueEnd, type QueuePrediction, type QueueReading, type ReconnectReading, type ReconnectVerdict, type Reconnects, type RecordCode, type Recovers, type RecoveryMeasured, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouteLine, type RouterHop, type RttRange, type Run, type RunBackup, type RunDrill, type RunEstimate, type RunFabric, type RunGroup, type RunLoad, type RunPart, type RunPause, type RunRoute, type RunStream, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type Sibling, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type StallReading, type Stamp, type Status, type StatusRow, type Subject, type Substrate, type SubstrateSource, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, isHopPlace, latestEndOf };
2732
+ export { type Agent, type BuildImage, type BuildRecord, CLIENT_CAPABILITIES, type CallReading, type Cell, type CellResult, type Client, type ClientCapability, type ClientImage, type ClockPair, type Cloud, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type ConntrackPrediction, type ConntrackReading, type ContextFile, type CountBand, type Crossings, type Cut, type Decision, type Drill, type DrillRoom, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type EstimateVerdict, type Fabric, type FabricLab, type FabricManifest, type FabricParts, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type Hop, type HopEvent, type HopPlace, type HopSignal, type HopWrite, type Host, type HostSetting, type HostSysctl, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type Jitter, type Kafka, type KafkaLab, type KafkaMember, type KafkaPause, type KernelRecord, type Lab, type Layer, type LeafViews, type LineCount, type LineMatch, type LoadBand, type LoadJudgement, type LoadPlan, type LoadPrediction, type LoadSpread, type LoadStream, type LoadVerdict, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type OplogRead, type OplogTime, type Outcome, type Outcomes, type Pair, type PairSets, type Pairing, type PartitionView, type PauseBand, type PauseCommit, type PausePrediction, type PauseReading, type Pinnable, type PinnedImage, type PortsPrediction, type PortsReading, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type QueueBand, type QueueConnection, type QueueConnectionReading, type QueueEnd, type QueuePrediction, type QueueReading, type ReconnectReading, type ReconnectVerdict, type Reconnects, type RecordCode, type Recovers, type RecoveryMeasured, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouteLine, type RouterHop, type RttRange, type Run, type RunBackup, type RunDrill, type RunEstimate, type RunFabric, type RunGroup, type RunLoad, type RunPart, type RunPause, type RunRoute, type RunStream, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type Sibling, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type StallReading, type Stamp, type Status, type StatusRow, type Subject, type Substrate, type SubstrateSource, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, environmentProblems, isHopPlace, latestEndOf };
2714
2733
  //# sourceMappingURL=index.d.ts.map
package/build/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as unlockedManifests, B as isHopPlace, C as programOf, D as subjectProblems, E as subjectClient, F as jarVersions, H as requestFirst, I as locksOf, L as npmVersions, M as LOCK_NAMES, N as cargoVersions, O as targetImageOf, P as goVersions, R as versionsOf, S as planOf, T as shippedSource, V as latestEndOf, _ as kafkaClientImage, a as SHIPPED_NAMES, b as nodeHttpImage, c as buildRecordOf, d as harnessImage, f as harnessVersion, g as inContext, h as imageProblems, i as SHIPPED_CLIENTS, j as unpinnedBases, k as targetSourceOf, l as goHttpImage, m as imageOf, n as PINNED, o as amqpClientImage, p as hikariClientImage, r as REPOSITORY, s as basesOf, t as CLIENT_NAMES, u as grpcClientImage, v as mongoClientImage, w as routerImage, x as pgClientImage, y as nodeClientImage, z as CLIENT_CAPABILITIES } from "./image-BxVTFZ1o.js";
1
+ import { A as unlockedManifests, B as environmentProblems, C as programOf, D as subjectProblems, E as subjectClient, F as jarVersions, H as latestEndOf, I as locksOf, L as npmVersions, M as LOCK_NAMES, N as cargoVersions, O as targetImageOf, P as goVersions, R as versionsOf, S as planOf, T as shippedSource, U as requestFirst, V as isHopPlace, _ as kafkaClientImage, a as SHIPPED_NAMES, b as nodeHttpImage, c as buildRecordOf, d as harnessImage, f as harnessVersion, g as inContext, h as imageProblems, i as SHIPPED_CLIENTS, j as unpinnedBases, k as targetSourceOf, l as goHttpImage, m as imageOf, n as PINNED, o as amqpClientImage, p as hikariClientImage, r as REPOSITORY, s as basesOf, t as CLIENT_NAMES, u as grpcClientImage, v as mongoClientImage, w as routerImage, x as pgClientImage, y as nodeClientImage, z as CLIENT_CAPABILITIES } from "./image-B8yh_FF7.js";
2
2
  import { quantity, valueIn } from "@mark1russell7/quantity";
3
3
  import { median, medianInterval as medianInterval$1, quantile, quantileSorted } from "@mark1russell7/rigor-statistics";
4
4
  import { rungVerdict } from "@mark1russell7/rigor-bench";
@@ -2050,6 +2050,36 @@ const SEED_DOCUMENT = 65536;
2050
2050
  const LOSS_MARGIN = 2;
2051
2051
  /** This time is how long a script waits for a server to stop, in tenths of a second. */
2052
2052
  const STOP_TENTHS = 600;
2053
+ /** These are the bounds of the oplog that mongod makes at its first start with no `--oplogSize`. It is 5% of the free disk, from 990 MB to 50 GB. */
2054
+ const OPLOG_SHARE = .05;
2055
+ const OPLOG_FLOOR = 1038090240;
2056
+ const OPLOG_CEILING = 53687091200;
2057
+ /**
2058
+ * This function gives the most disk that a drill needs, from the disk that it can use. The peak comes
2059
+ * before the fault. Then each member holds the data and its oplog, and the backup host holds the
2060
+ * dump. The seed goes through the oplog, thus each oplog holds the data up to its own size. The
2061
+ * slices are small: the writes of one client in a few seconds.
2062
+ */
2063
+ const roomNeeded = (drill, members, disk) => {
2064
+ const data = drill.tenants * valueIn(drill.perTenant, "B");
2065
+ const oplog = Math.min(OPLOG_CEILING, Math.max(OPLOG_FLOOR, OPLOG_SHARE * valueIn(disk, "B")));
2066
+ return {
2067
+ value: Math.ceil((members + 1) * data + members * Math.min(data, oplog)),
2068
+ unit: "B"
2069
+ };
2070
+ };
2071
+ /** This function gives MemAvailable from the text of `/proc/meminfo`. */
2072
+ const memAvailableOf = (meminfo) => {
2073
+ const found = /^MemAvailable:\s+(\d+) kB$/m.exec(meminfo);
2074
+ if (found === null) throw new Error("/proc/meminfo has no line MemAvailable");
2075
+ return {
2076
+ value: Number(found[1]) * 1024,
2077
+ unit: "B"
2078
+ };
2079
+ };
2080
+ const gigabytes = (size) => `${(valueIn(size, "B") / 1e9).toFixed(1)} GB`;
2081
+ /** This function gives the reason that a drill has no room on its runner, or null. A record from before SYS-97 has no room, and it is not void for this reason. */
2082
+ const roomVoidOf = (room) => room === void 0 || valueIn(room.disk, "B") >= valueIn(room.need, "B") ? null : `the runner has ${gigabytes(room.disk)} of disk for the drill, and the drill needs ${gigabytes(room.need)}: the data on each member, the dump and the oplogs`;
2053
2083
  /** This function gives the time of a drill from the start of the backups to the fault, in seconds. */
2054
2084
  const drillSpan = (drill) => drill.slices * valueIn(drill.sliceEvery, "s") + valueIn(drill.age, "s");
2055
2085
  /**
@@ -2516,6 +2546,12 @@ const measureGroup = (cell, run) => {
2516
2546
  noticed: null,
2517
2547
  finding: null
2518
2548
  };
2549
+ const room = cell.drill === void 0 ? null : roomVoidOf(run.group?.drill?.room);
2550
+ if (room !== null) return {
2551
+ ...silent,
2552
+ void: room,
2553
+ group: empty
2554
+ };
2519
2555
  if (ready === void 0) return {
2520
2556
  ...silent,
2521
2557
  void: "the client never became ready",
@@ -3732,6 +3768,27 @@ const openFabric = async (parts) => {
3732
3768
  };
3733
3769
  //#endregion
3734
3770
  //#region src/substrate.ts
3771
+ /**
3772
+ * A layer is a rung of the laboratory (`docs/S7.md`). E1 is containers on one kernel, and E2 is a
3773
+ * cluster of containers on one kernel. A lab with `Topology.fabric` writes E3: routers in containers.
3774
+ * A lab in a guest of QEMU writes E4 (`substrateHere`). The other layers do not have a runner at this
3775
+ * time.
3776
+ */
3777
+ const LAYERS = [
3778
+ "E0",
3779
+ "E1",
3780
+ "E2",
3781
+ "E3",
3782
+ "E4",
3783
+ "E5",
3784
+ "E6"
3785
+ ];
3786
+ /** A cloud is where the runner operates. GitHub can schedule a standard Linux job on Azure or on AWS. */
3787
+ const CLOUDS = [
3788
+ "azure",
3789
+ "aws",
3790
+ "unknown"
3791
+ ];
3735
3792
  /** GitHub announced Linux jobs on AWS on this date. Each earlier hosted job ran on Azure. */
3736
3793
  const AWS_FROM = "2026-10-28";
3737
3794
  /** This function gives the cloud of a DMI vendor. A kernel name does not tell: one image can start on each cloud. */
@@ -6566,6 +6623,35 @@ const sizeOf = async (lab, path) => {
6566
6623
  unit: "B"
6567
6624
  };
6568
6625
  };
6626
+ /**
6627
+ * This function reads the room of the runner before the seed. Each container writes to the same disk
6628
+ * of the runner, thus the free disk of the backup host is the free disk of the lab. The seed first
6629
+ * removes the data of the run before, thus the files of the members count as room too.
6630
+ */
6631
+ const roomOf = async (lab, drill) => {
6632
+ const [free] = (await lab.vault([
6633
+ "df",
6634
+ "-B1",
6635
+ "--output=avail",
6636
+ VAULT
6637
+ ])).trim().split("\n").slice(-1);
6638
+ let held = 0;
6639
+ for (const name of lab.set.members) held += Number((await lab.exec(name, [
6640
+ "du",
6641
+ "-sb",
6642
+ "/data/db"
6643
+ ])).split(/\s+/)[0]);
6644
+ const disk = {
6645
+ value: Number(free) + held,
6646
+ unit: "B"
6647
+ };
6648
+ if (!Number.isFinite(disk.value)) throw new Error(`no free disk in the output of df: ${free}`);
6649
+ return {
6650
+ disk,
6651
+ memory: memAvailableOf(await lab.vault(["cat", "/proc/meminfo"])),
6652
+ need: roomNeeded(drill, lab.set.members.length, disk)
6653
+ };
6654
+ };
6569
6655
  /** This function takes the dump with its oplog, and each slice of the oplog at its interval. It gives each backup in sequence. */
6570
6656
  const backupsOf = async (lab, drill, primary, writer) => {
6571
6657
  const host = `${lab.members[primary].ip}:${lab.set.port}`;
@@ -6730,10 +6816,40 @@ const drillOnce = async (lab, cell, environment, index) => {
6730
6816
  "-c",
6731
6817
  `rm -rf ${VAULT} && mkdir -p ${VAULT}`
6732
6818
  ]);
6819
+ const tool = (await lab.vault(["mongodump", "--version"])).split("\n")[0].trim();
6820
+ const room = await roomOf(lab, drill);
6821
+ if (roomVoidOf(room) !== null) return {
6822
+ environment,
6823
+ index,
6824
+ events: [],
6825
+ fault: null,
6826
+ kernel: [],
6827
+ netns: lab.netns.client,
6828
+ targetNetns: lab.members[primary].netns,
6829
+ lost: 0,
6830
+ group: {
6831
+ members: lab.members,
6832
+ sentinels: {},
6833
+ primary,
6834
+ at: primary,
6835
+ timeline: [],
6836
+ after: primary,
6837
+ holds: null,
6838
+ drill: {
6839
+ tool,
6840
+ seed: "generated",
6841
+ backups: [],
6842
+ before: "",
6843
+ after: null,
6844
+ restored: null,
6845
+ second: null,
6846
+ room
6847
+ }
6848
+ }
6849
+ };
6733
6850
  const seeded = await lab.script(primary, seedScript(drill, set.members.length));
6734
6851
  if (!seeded.includes("\"ok\":true")) throw new Error(`the seed failed: ${seeded}`);
6735
6852
  const before = hashOf(await lab.script(primary, HASH_SCRIPT));
6736
- const tool = (await lab.vault(["mongodump", "--version"])).split("\n")[0].trim();
6737
6853
  const from = lab.kernel.length;
6738
6854
  const logFrom = lab.log.length;
6739
6855
  const lostBefore = droppedSoFar$3(lab.kernel);
@@ -6801,7 +6917,8 @@ const drillOnce = async (lab, cell, environment, index) => {
6801
6917
  before,
6802
6918
  after: hash,
6803
6919
  restored,
6804
- second
6920
+ second,
6921
+ room
6805
6922
  }
6806
6923
  }
6807
6924
  };
@@ -7561,6 +7678,19 @@ const clusterOnce = async (lab, cell, environment, index) => {
7561
7678
  * not in the namespace that the prober watches. The record of a run is the lines of the client and
7562
7679
  * the whole partition, read to its high watermark after the group converged.
7563
7680
  */
7681
+ /**
7682
+ * This function gives the record of the Kafka client for a manifest: its image, its source and its
7683
+ * build record. The pins check refuses a record of a built client without its build record.
7684
+ */
7685
+ const kafkaClientRecord = (image) => {
7686
+ const source = shippedSource("kafka");
7687
+ return {
7688
+ kind: "image",
7689
+ image,
7690
+ source,
7691
+ ...buildOf(source)
7692
+ };
7693
+ };
7564
7694
  /** This path is the class path of the Kafka image: the JVM expands the star itself. */
7565
7695
  const CLASS_PATH = "/opt/harness/kafka/classes:/opt/harness/kafka/lib/*";
7566
7696
  /** This option is the heap of the client and of the admin. It has no source: the two hold a producer or a read of one partition. */
@@ -7960,12 +8090,10 @@ const openKafkaLab = async (kafka) => {
7960
8090
  "apk",
7961
8091
  "info",
7962
8092
  "-v"
7963
- ])).split("\n").sort()
7964
- },
7965
- client: {
7966
- kind: "image",
7967
- image: clientImage
8093
+ ])).split("\n").sort(),
8094
+ ...harnessRecord()
7968
8095
  },
8096
+ client: kafkaClientRecord(clientImage),
7969
8097
  netns: {
7970
8098
  client: clientNetns,
7971
8099
  target: members[kafka.brokers[0]].netns
@@ -8731,6 +8859,12 @@ const once = async (lab, cell, environment, index, dry = false) => {
8731
8859
  /** This function divides a count of runs across environments, as equally as possible. */
8732
8860
  const spread = (runs, environments) => Array.from({ length: environments }, (_, at) => Math.floor(runs / environments) + (at < runs % environments ? 1 : 0)).filter((count) => count > 0);
8733
8861
  /**
8862
+ * This function gives the count of runs of each new environment of a cell, for `runs` more runs. A
8863
+ * pair cell has an environment for each run, because its run promotes the standby. Other cells
8864
+ * go across their environments, and at least one for each environment at the same time.
8865
+ */
8866
+ const environmentCounts = (cell, runs) => spread(runs, cell.pair !== void 0 ? runs : Math.max(cell.environments, Math.max(1, cell.concurrency ?? 1)));
8867
+ /**
8734
8868
  * This function tells if the fault of a cell ends its environment. A server that stopped cannot serve
8735
8869
  * the next run. Also, a cell can say that its fault changes the environment (`fresh`).
8736
8870
  */
@@ -8867,6 +9001,7 @@ const inReplicaSetEnvironment = async (cell, environment, count, say) => {
8867
9001
  * run. The run promotes the standby, thus a pair cell has an environment for each run.
8868
9002
  */
8869
9003
  const inPairEnvironment = async (cell, environment, count, say) => {
9004
+ if (count !== 1) throw new Error(`${cell.name}: a pair environment has one run, not ${count}: the run promotes the standby`);
8870
9005
  const lab = await openLab(cell.target, cell.client ?? cell.probe.driver?.name ?? "tcp", cell.topology);
8871
9006
  try {
8872
9007
  await lab.warm();
@@ -8959,6 +9094,8 @@ const inKafkaEnvironment = async (cell, environment, count, say) => {
8959
9094
  * Each environment does a warm-up first, and the result keeps it apart from the counted runs.
8960
9095
  */
8961
9096
  const runCell = async (cell, say = () => {}) => {
9097
+ const problems = environmentProblems(cell);
9098
+ if (problems.length > 0) throw new Error(problems.join(", "));
8962
9099
  const started = (/* @__PURE__ */ new Date()).toISOString();
8963
9100
  const manifests = [];
8964
9101
  const runs = [];
@@ -8967,7 +9104,7 @@ const runCell = async (cell, say = () => {}) => {
8967
9104
  let target = cell.runs;
8968
9105
  let next = 0;
8969
9106
  for (;;) {
8970
- const counts = spread(target - runs.length, Math.max(cell.environments, concurrency));
9107
+ const counts = environmentCounts(cell, target - runs.length);
8971
9108
  for (let at = 0; at < counts.length; at += concurrency) {
8972
9109
  const batch = counts.slice(at, at + concurrency).map((count) => ({
8973
9110
  count,
@@ -9003,6 +9140,6 @@ const runCell = async (cell, say = () => {}) => {
9003
9140
  }
9004
9141
  };
9005
9142
  //#endregion
9006
- export { AWS_FROM, CLIENT_CAPABILITIES, CLIENT_NAMES, CLOSED_TOLERANCE, CLUSTER_STAGES, CONVERGE_MS, DAEMONS, DEBUG, DIRTY, DROP_HANDLING, FABRIC_CLIENT, FABRIC_DEVICE, FABRIC_TARGET, FRR_IMAGE, GIVES_AWAY, HASH_SCRIPT, INJECT, INSERT, KAFKA_TAIL_MS, KEPT, LINGER_MS, LISTING, LOAD_FORMAT, LOAD_PATH, LOCK_NAMES, LOSS_MARGIN, MEMBER_MARKS, MONITOR_DOWN, NODE_MARKS, NOISE, PINNED, PUMP, PUMP_SLACK, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, REPOSITORY, RESTART, ROUTERS, SCHEDULE_PATH, SEED_DOCUMENT, SHIPPED_CLIENTS, SHIPPED_NAMES, STAGES, STANDBY_READY, STATUS_SCRIPT, STEPS, STEP_DOWN, amqpClientImage, basesOf, bootstrapOf, brokerEnv, buildOf, buildRecordOf, callOf, cancelsOf, cargoVersions, clockOffsetOf, closeOrExit, cloudOf, clusterArgs, clusterConf, clusterCutOf, clusterHostsOf, clusterOnce, clusterStagesOf, clusterViewOf, commitProblems, comparable, controllerEnv, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, drillOnce, drillSpan, dropFinding, dropOf, endpointAfter, envOf, errorsOf, estimateOf, estimateVerdict, exitOf, fieldOf, fieldsOf, firstUnanswered, frrConf, goHttpImage, goVersions, groupOnce, groupVerdictOf, grpcClientImage, harnessImage, harnessRecord, harnessVersion, hashOf, highestHeld, hikariClientImage, hzOf, imageOf, imageProblems, inContext, infoOf, initiateScript, isFenceLine, isHopPlace, jarVersions, jitterOf, jitterOfLines, judge, kafkaArgs, kafkaClientImage, kafkaCutOf, kafkaOnce, kafkaPauseOnce, kafkaViewOf, lagsOf, laterMove, latestEndOf, leafLacks, leftAfter, loadOf, loadPlanOf, loadVerdict, locksOf, logNameOf, logTimeOf, manifestProblems, matches, measure, measureConntrack, measureDriver, measureGroup, measurePause, measurePorts, measureQueue, medianInterval, memberCommand, memberConfig, memberLineOf, mongoClientImage, monotonicAt, monotonicOf, namesGroup, nodeClientImage, nodeCommand, nodeHttpImage, nodeIdOf, nodeLineOf, nodeNameOf, nodesOnMonotonic, noiseOf, npmVersions, numbersOf, onMonotonic, openClusterLab, openFabric, openGroupLab, openKafkaLab, openLab, openReplicaSetLab, openStandby, pairArgs, pairOnce, pairingOf, pairingsOf, pauseReady, peersOf, pgClientImage, pingsOf, plainOf, planOf, poolOf, programLines, programOf, quantileOf, readCpu, readHost, readOplog, reconnectFinding, reconnectOf, recordProblems, recoveryFindings, recoveryOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, restamped, routeLine, routerImage, routesOf, runCell, seedScript, sentinelConfig, sessionsOf, shippedClientRecord, shippedSource, sliceQuery, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, standaloneCommand, standbyCommand, statusViewOf, stealShare, stopScript, streamsLoadOf, subjectClient, subjectProblems, subscriptionsOf, substrateHere, substrateKey, substrateOf, substrateOn, targetImageOf, targetSourceOf, templated, toolJsonOf, topicOf, topologyOf, toxicBody, unlockedManifests, unpinnedBases, unpoolable, verdictOf, versionsOf, viewOf, writesOf };
9143
+ export { AWS_FROM, CLIENT_CAPABILITIES, CLIENT_NAMES, CLOSED_TOLERANCE, CLOUDS, CLUSTER_STAGES, CONVERGE_MS, DAEMONS, DEBUG, DIRTY, DROP_HANDLING, FABRIC_CLIENT, FABRIC_DEVICE, FABRIC_TARGET, FRR_IMAGE, GIVES_AWAY, HASH_SCRIPT, INJECT, INSERT, KAFKA_TAIL_MS, KEPT, LAYERS, LINGER_MS, LISTING, LOAD_FORMAT, LOAD_PATH, LOCK_NAMES, LOSS_MARGIN, MEMBER_MARKS, MONITOR_DOWN, NODE_MARKS, NOISE, PINNED, PUMP, PUMP_SLACK, QUIET_MS, RELATIVE, REPLICA_SET_STAGES, REPOSITORY, RESTART, ROUTERS, SCHEDULE_PATH, SEED_DOCUMENT, SHIPPED_CLIENTS, SHIPPED_NAMES, STAGES, STANDBY_READY, STATUS_SCRIPT, STEPS, STEP_DOWN, amqpClientImage, basesOf, bootstrapOf, brokerEnv, buildOf, buildRecordOf, callOf, cancelsOf, cargoVersions, clockOffsetOf, closeOrExit, cloudOf, clusterArgs, clusterConf, clusterCutOf, clusterHostsOf, clusterOnce, clusterStagesOf, clusterViewOf, commitProblems, comparable, controllerEnv, crossingsOf, cutOf, deadlineOf, delayVoids, deviceOf, drillOnce, drillSpan, dropFinding, dropOf, endpointAfter, envOf, environmentCounts, environmentProblems, errorsOf, estimateOf, estimateVerdict, exitOf, fieldOf, fieldsOf, firstUnanswered, frrConf, goHttpImage, goVersions, groupOnce, groupVerdictOf, grpcClientImage, harnessImage, harnessRecord, harnessVersion, hashOf, highestHeld, hikariClientImage, hzOf, imageOf, imageProblems, inContext, infoOf, initiateScript, isFenceLine, isHopPlace, jarVersions, jitterOf, jitterOfLines, judge, kafkaArgs, kafkaClientImage, kafkaCutOf, kafkaOnce, kafkaPauseOnce, kafkaViewOf, lagsOf, laterMove, latestEndOf, leafLacks, leftAfter, loadOf, loadPlanOf, loadVerdict, locksOf, logNameOf, logTimeOf, manifestProblems, matches, measure, measureConntrack, measureDriver, measureGroup, measurePause, measurePorts, measureQueue, medianInterval, memAvailableOf, memberCommand, memberConfig, memberLineOf, mongoClientImage, monotonicAt, monotonicOf, namesGroup, nodeClientImage, nodeCommand, nodeHttpImage, nodeIdOf, nodeLineOf, nodeNameOf, nodesOnMonotonic, noiseOf, npmVersions, numbersOf, onMonotonic, openClusterLab, openFabric, openGroupLab, openKafkaLab, openLab, openReplicaSetLab, openStandby, pairArgs, pairOnce, pairingOf, pairingsOf, pauseReady, peersOf, pgClientImage, pingsOf, plainOf, planOf, poolOf, programLines, programOf, quantileOf, readCpu, readHost, readOplog, reconnectFinding, reconnectOf, recordProblems, recoveryFindings, recoveryOf, referenceOf, reorderingOf, replicaSetArgs, replicaSetOnce, replicaSetStagesOf, requestOf, requestWords, restamped, roomNeeded, roomVoidOf, routeLine, routerImage, routesOf, runCell, seedScript, sentinelConfig, sessionsOf, shippedClientRecord, shippedSource, sliceQuery, socketAt, socketOf, socketsOf, spread, spreadOf, stagesOf, standaloneCommand, standbyCommand, statusViewOf, stealShare, stopScript, streamsLoadOf, subjectClient, subjectProblems, subscriptionsOf, substrateHere, substrateKey, substrateOf, substrateOn, targetImageOf, targetSourceOf, templated, toolJsonOf, topicOf, topologyOf, toxicBody, unlockedManifests, unpinnedBases, unpoolable, verdictOf, versionsOf, viewOf, writesOf };
9007
9144
 
9008
9145
  //# sourceMappingURL=index.js.map