@rotorsoft/act-tck 1.0.0 → 1.2.0
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/dist/.tsbuildinfo +1 -1
- package/dist/@types/store-tck.d.ts +8 -0
- package/dist/@types/store-tck.d.ts.map +1 -1
- package/dist/index.cjs +368 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +379 -6
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -235,7 +235,7 @@ var import_vitest3 = require("vitest");
|
|
|
235
235
|
var runStoreTck = (options) => {
|
|
236
236
|
(0, import_vitest3.describe)(`TCK / Store / ${options.name}`, () => {
|
|
237
237
|
let store;
|
|
238
|
-
const caps = options.capabilities
|
|
238
|
+
const caps = { ...options.capabilities };
|
|
239
239
|
(0, import_vitest3.beforeAll)(async () => {
|
|
240
240
|
store = await options.factory();
|
|
241
241
|
await store.drop();
|
|
@@ -1545,6 +1545,373 @@ var runStoreTck = (options) => {
|
|
|
1545
1545
|
}
|
|
1546
1546
|
});
|
|
1547
1547
|
});
|
|
1548
|
+
import_vitest3.describe.skipIf(!caps.restore)("restore (capability)", () => {
|
|
1549
|
+
beforeEach(async () => {
|
|
1550
|
+
await store.drop();
|
|
1551
|
+
await store.seed();
|
|
1552
|
+
});
|
|
1553
|
+
const asSource = (events) => (async function* () {
|
|
1554
|
+
for (const e of events) yield e;
|
|
1555
|
+
})();
|
|
1556
|
+
const event = (originalId, stream, version, name, created, data = {}) => ({
|
|
1557
|
+
id: originalId,
|
|
1558
|
+
name,
|
|
1559
|
+
data,
|
|
1560
|
+
stream,
|
|
1561
|
+
version,
|
|
1562
|
+
created,
|
|
1563
|
+
meta: { correlation: "restore-tck", causation: {} }
|
|
1564
|
+
});
|
|
1565
|
+
const restore = async (source, opts = {}) => {
|
|
1566
|
+
const cache = new import_act.InMemoryCache();
|
|
1567
|
+
const app = (0, import_act.act)().build({ scoped: { store, cache } });
|
|
1568
|
+
try {
|
|
1569
|
+
return await app.restore(source, opts);
|
|
1570
|
+
} finally {
|
|
1571
|
+
await cache.dispose();
|
|
1572
|
+
}
|
|
1573
|
+
};
|
|
1574
|
+
(0, import_vitest3.it)("returns kept=0 on an empty source", async () => {
|
|
1575
|
+
const result = await restore(asSource([]));
|
|
1576
|
+
(0, import_vitest3.expect)(result.kept).toBe(0);
|
|
1577
|
+
(0, import_vitest3.expect)(result.duration_ms).toBeGreaterThanOrEqual(0);
|
|
1578
|
+
(0, import_vitest3.expect)(result.dropped).toEqual({
|
|
1579
|
+
closed_streams: 0,
|
|
1580
|
+
snapshots: 0,
|
|
1581
|
+
empty_streams: 0
|
|
1582
|
+
});
|
|
1583
|
+
const events = await collect(store, { limit: 10 });
|
|
1584
|
+
(0, import_vitest3.expect)(events).toHaveLength(0);
|
|
1585
|
+
});
|
|
1586
|
+
(0, import_vitest3.it)("rebuilds a single stream and preserves `created` verbatim", async () => {
|
|
1587
|
+
const s = `restore-single-${uid()}`;
|
|
1588
|
+
const t0 = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
1589
|
+
const t1 = /* @__PURE__ */ new Date("2020-01-02T00:00:00.000Z");
|
|
1590
|
+
const t2 = /* @__PURE__ */ new Date("2020-01-03T00:00:00.000Z");
|
|
1591
|
+
const events = [
|
|
1592
|
+
event(1, s, 0, "Incremented", t0, { amount: 1 }),
|
|
1593
|
+
event(2, s, 1, "Incremented", t1, { amount: 2 }),
|
|
1594
|
+
event(3, s, 2, "Decremented", t2, { amount: 1 })
|
|
1595
|
+
];
|
|
1596
|
+
const result = await restore(asSource(events));
|
|
1597
|
+
(0, import_vitest3.expect)(result.kept).toBe(3);
|
|
1598
|
+
const back = [];
|
|
1599
|
+
await store.query(
|
|
1600
|
+
(e) => {
|
|
1601
|
+
back.push(e);
|
|
1602
|
+
},
|
|
1603
|
+
{ stream: s, stream_exact: true }
|
|
1604
|
+
);
|
|
1605
|
+
(0, import_vitest3.expect)(back).toHaveLength(3);
|
|
1606
|
+
(0, import_vitest3.expect)(
|
|
1607
|
+
back.map((e) => ({
|
|
1608
|
+
stream: e.stream,
|
|
1609
|
+
version: e.version,
|
|
1610
|
+
name: e.name,
|
|
1611
|
+
created: e.created.toISOString(),
|
|
1612
|
+
data: e.data
|
|
1613
|
+
}))
|
|
1614
|
+
).toEqual([
|
|
1615
|
+
{
|
|
1616
|
+
stream: s,
|
|
1617
|
+
version: 0,
|
|
1618
|
+
name: "Incremented",
|
|
1619
|
+
created: t0.toISOString(),
|
|
1620
|
+
data: { amount: 1 }
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
stream: s,
|
|
1624
|
+
version: 1,
|
|
1625
|
+
name: "Incremented",
|
|
1626
|
+
created: t1.toISOString(),
|
|
1627
|
+
data: { amount: 2 }
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
stream: s,
|
|
1631
|
+
version: 2,
|
|
1632
|
+
name: "Decremented",
|
|
1633
|
+
created: t2.toISOString(),
|
|
1634
|
+
data: { amount: 1 }
|
|
1635
|
+
}
|
|
1636
|
+
]);
|
|
1637
|
+
});
|
|
1638
|
+
(0, import_vitest3.it)("rebuilds multiple streams interleaved", async () => {
|
|
1639
|
+
const a = `restore-multi-a-${uid()}`;
|
|
1640
|
+
const b = `restore-multi-b-${uid()}`;
|
|
1641
|
+
const t = /* @__PURE__ */ new Date("2020-06-01T00:00:00.000Z");
|
|
1642
|
+
const events = [
|
|
1643
|
+
event(1, a, 0, "Incremented", t, { amount: 10 }),
|
|
1644
|
+
event(2, b, 0, "Incremented", t, { amount: 20 }),
|
|
1645
|
+
event(3, a, 1, "Decremented", t, { amount: 5 }),
|
|
1646
|
+
event(4, b, 1, "Incremented", t, { amount: 30 })
|
|
1647
|
+
];
|
|
1648
|
+
const result = await restore(asSource(events));
|
|
1649
|
+
(0, import_vitest3.expect)(result.kept).toBe(4);
|
|
1650
|
+
const aBack = [];
|
|
1651
|
+
const bBack = [];
|
|
1652
|
+
await store.query(
|
|
1653
|
+
(e) => {
|
|
1654
|
+
aBack.push(e);
|
|
1655
|
+
},
|
|
1656
|
+
{ stream: a, stream_exact: true }
|
|
1657
|
+
);
|
|
1658
|
+
await store.query(
|
|
1659
|
+
(e) => {
|
|
1660
|
+
bBack.push(e);
|
|
1661
|
+
},
|
|
1662
|
+
{ stream: b, stream_exact: true }
|
|
1663
|
+
);
|
|
1664
|
+
(0, import_vitest3.expect)(aBack.map((e) => e.version)).toEqual([0, 1]);
|
|
1665
|
+
(0, import_vitest3.expect)(bBack.map((e) => e.version)).toEqual([0, 1]);
|
|
1666
|
+
});
|
|
1667
|
+
(0, import_vitest3.it)("preserves Date `created` verbatim", async () => {
|
|
1668
|
+
const s = `restore-isoc-${uid()}`;
|
|
1669
|
+
const iso = "2021-07-15T12:34:56.789Z";
|
|
1670
|
+
await restore(
|
|
1671
|
+
asSource([
|
|
1672
|
+
{
|
|
1673
|
+
id: 1,
|
|
1674
|
+
stream: s,
|
|
1675
|
+
version: 0,
|
|
1676
|
+
name: "Incremented",
|
|
1677
|
+
data: { amount: 1 },
|
|
1678
|
+
created: new Date(iso),
|
|
1679
|
+
meta: { correlation: "restore-tck", causation: {} }
|
|
1680
|
+
}
|
|
1681
|
+
])
|
|
1682
|
+
);
|
|
1683
|
+
const back = [];
|
|
1684
|
+
await store.query(
|
|
1685
|
+
(e) => {
|
|
1686
|
+
back.push(e);
|
|
1687
|
+
},
|
|
1688
|
+
{ stream: s, stream_exact: true }
|
|
1689
|
+
);
|
|
1690
|
+
(0, import_vitest3.expect)(back).toHaveLength(1);
|
|
1691
|
+
(0, import_vitest3.expect)(back[0].created.toISOString()).toBe(iso);
|
|
1692
|
+
});
|
|
1693
|
+
(0, import_vitest3.it)("wipes pre-existing events before inserting", async () => {
|
|
1694
|
+
const old = `restore-old-${uid()}`;
|
|
1695
|
+
await store.commit(
|
|
1696
|
+
old,
|
|
1697
|
+
[inc(1), inc(2)],
|
|
1698
|
+
makeMeta({ stream: old })
|
|
1699
|
+
);
|
|
1700
|
+
const fresh = `restore-fresh-${uid()}`;
|
|
1701
|
+
const t = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
1702
|
+
await restore(
|
|
1703
|
+
asSource([event(1, fresh, 0, "Incremented", t, { amount: 99 })])
|
|
1704
|
+
);
|
|
1705
|
+
const oldBack = await collect(store, {
|
|
1706
|
+
stream: old,
|
|
1707
|
+
stream_exact: true
|
|
1708
|
+
});
|
|
1709
|
+
(0, import_vitest3.expect)(oldBack).toHaveLength(0);
|
|
1710
|
+
const freshBack = await collect(store, {
|
|
1711
|
+
stream: fresh,
|
|
1712
|
+
stream_exact: true
|
|
1713
|
+
});
|
|
1714
|
+
(0, import_vitest3.expect)(freshBack).toHaveLength(1);
|
|
1715
|
+
});
|
|
1716
|
+
(0, import_vitest3.it)("clears subscription/stream-position metadata", async () => {
|
|
1717
|
+
const sub = `restore-sub-${uid()}`;
|
|
1718
|
+
await store.subscribe([{ stream: sub, source: "anything" }]);
|
|
1719
|
+
const collectStreams = async () => {
|
|
1720
|
+
const out = [];
|
|
1721
|
+
await store.query_streams((p) => {
|
|
1722
|
+
out.push(p.stream);
|
|
1723
|
+
});
|
|
1724
|
+
return out;
|
|
1725
|
+
};
|
|
1726
|
+
const before = await collectStreams();
|
|
1727
|
+
(0, import_vitest3.expect)(before.includes(sub)).toBe(true);
|
|
1728
|
+
await restore(asSource([]));
|
|
1729
|
+
const after = await collectStreams();
|
|
1730
|
+
(0, import_vitest3.expect)(after.includes(sub)).toBe(false);
|
|
1731
|
+
});
|
|
1732
|
+
(0, import_vitest3.it)("preserves snapshot events through restore", async () => {
|
|
1733
|
+
const s = `restore-snap-${uid()}`;
|
|
1734
|
+
const t = /* @__PURE__ */ new Date("2020-04-01T00:00:00.000Z");
|
|
1735
|
+
await restore(
|
|
1736
|
+
asSource([
|
|
1737
|
+
{
|
|
1738
|
+
id: 1,
|
|
1739
|
+
stream: s,
|
|
1740
|
+
version: 0,
|
|
1741
|
+
name: import_act.SNAP_EVENT,
|
|
1742
|
+
data: { count: 42 },
|
|
1743
|
+
created: t,
|
|
1744
|
+
meta: { correlation: "snap", causation: {} }
|
|
1745
|
+
}
|
|
1746
|
+
])
|
|
1747
|
+
);
|
|
1748
|
+
const back = await collect(store, {
|
|
1749
|
+
stream: s,
|
|
1750
|
+
stream_exact: true,
|
|
1751
|
+
with_snaps: true
|
|
1752
|
+
});
|
|
1753
|
+
(0, import_vitest3.expect)(back).toHaveLength(1);
|
|
1754
|
+
(0, import_vitest3.expect)(back[0].name).toBe(import_act.SNAP_EVENT);
|
|
1755
|
+
});
|
|
1756
|
+
(0, import_vitest3.it)("rewrites causation refs through the old\u2192new id map", async () => {
|
|
1757
|
+
const s = `restore-caus-${uid()}`;
|
|
1758
|
+
const t = /* @__PURE__ */ new Date("2020-08-01T00:00:00.000Z");
|
|
1759
|
+
const events = [
|
|
1760
|
+
{
|
|
1761
|
+
id: 5,
|
|
1762
|
+
stream: s,
|
|
1763
|
+
version: 0,
|
|
1764
|
+
name: "Incremented",
|
|
1765
|
+
data: { amount: 1 },
|
|
1766
|
+
created: t,
|
|
1767
|
+
meta: { correlation: "c", causation: {} }
|
|
1768
|
+
},
|
|
1769
|
+
{
|
|
1770
|
+
id: 7,
|
|
1771
|
+
stream: s,
|
|
1772
|
+
version: 1,
|
|
1773
|
+
name: "Incremented",
|
|
1774
|
+
data: { amount: 2 },
|
|
1775
|
+
created: t,
|
|
1776
|
+
meta: {
|
|
1777
|
+
correlation: "c",
|
|
1778
|
+
causation: {
|
|
1779
|
+
event: { id: 5, name: "Incremented", stream: s }
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
id: 9,
|
|
1785
|
+
stream: s,
|
|
1786
|
+
version: 2,
|
|
1787
|
+
name: "Decremented",
|
|
1788
|
+
data: { amount: 1 },
|
|
1789
|
+
created: t,
|
|
1790
|
+
meta: {
|
|
1791
|
+
correlation: "c",
|
|
1792
|
+
causation: {
|
|
1793
|
+
event: { id: 7, name: "Incremented", stream: s }
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
];
|
|
1798
|
+
await restore(asSource(events));
|
|
1799
|
+
const back = [];
|
|
1800
|
+
await store.query(
|
|
1801
|
+
(e) => {
|
|
1802
|
+
back.push(e);
|
|
1803
|
+
},
|
|
1804
|
+
{ stream: s, stream_exact: true }
|
|
1805
|
+
);
|
|
1806
|
+
(0, import_vitest3.expect)(back).toHaveLength(3);
|
|
1807
|
+
(0, import_vitest3.expect)(back[0].meta.causation.event).toBeUndefined();
|
|
1808
|
+
(0, import_vitest3.expect)(back[1].meta.causation.event?.id).toBe(back[0].id);
|
|
1809
|
+
(0, import_vitest3.expect)(back[2].meta.causation.event?.id).toBe(back[1].id);
|
|
1810
|
+
});
|
|
1811
|
+
(0, import_vitest3.it)("leaves causation refs unmapped when the target isn't in the source", async () => {
|
|
1812
|
+
const s = `restore-orphan-${uid()}`;
|
|
1813
|
+
const t = /* @__PURE__ */ new Date("2020-09-01T00:00:00.000Z");
|
|
1814
|
+
await restore(
|
|
1815
|
+
asSource([
|
|
1816
|
+
{
|
|
1817
|
+
id: 1,
|
|
1818
|
+
stream: s,
|
|
1819
|
+
version: 0,
|
|
1820
|
+
name: "Incremented",
|
|
1821
|
+
data: { amount: 1 },
|
|
1822
|
+
created: t,
|
|
1823
|
+
meta: {
|
|
1824
|
+
correlation: "c",
|
|
1825
|
+
causation: {
|
|
1826
|
+
event: { id: 999, name: "Phantom", stream: "ghost" }
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
])
|
|
1831
|
+
);
|
|
1832
|
+
const back = [];
|
|
1833
|
+
await store.query(
|
|
1834
|
+
(e) => {
|
|
1835
|
+
back.push(e);
|
|
1836
|
+
},
|
|
1837
|
+
{ stream: s, stream_exact: true }
|
|
1838
|
+
);
|
|
1839
|
+
(0, import_vitest3.expect)(back[0].meta.causation.event?.id).toBe(999);
|
|
1840
|
+
});
|
|
1841
|
+
(0, import_vitest3.it)("rolls back atomically when the source throws mid-iteration", async () => {
|
|
1842
|
+
const original = `restore-pre-${uid()}`;
|
|
1843
|
+
const committed = await store.commit(
|
|
1844
|
+
original,
|
|
1845
|
+
[inc(1), inc(2), inc(3)],
|
|
1846
|
+
makeMeta({ stream: original })
|
|
1847
|
+
);
|
|
1848
|
+
const explosive = (async function* () {
|
|
1849
|
+
yield event(
|
|
1850
|
+
1,
|
|
1851
|
+
`restore-explode-${uid()}`,
|
|
1852
|
+
0,
|
|
1853
|
+
"Incremented",
|
|
1854
|
+
/* @__PURE__ */ new Date(),
|
|
1855
|
+
{ amount: 1 }
|
|
1856
|
+
);
|
|
1857
|
+
throw new Error("boom");
|
|
1858
|
+
})();
|
|
1859
|
+
await (0, import_vitest3.expect)(restore(explosive)).rejects.toThrow("boom");
|
|
1860
|
+
const back = [];
|
|
1861
|
+
await store.query(
|
|
1862
|
+
(e) => {
|
|
1863
|
+
back.push(e);
|
|
1864
|
+
},
|
|
1865
|
+
{ stream: original, stream_exact: true }
|
|
1866
|
+
);
|
|
1867
|
+
(0, import_vitest3.expect)(back).toHaveLength(3);
|
|
1868
|
+
(0, import_vitest3.expect)(back.map((e) => e.id)).toEqual(committed.map((c) => c.id));
|
|
1869
|
+
});
|
|
1870
|
+
(0, import_vitest3.it)("drop_snapshots: skips SNAP_EVENT rows and counts them", async () => {
|
|
1871
|
+
const s = `restore-drop-snap-${uid()}`;
|
|
1872
|
+
const t = /* @__PURE__ */ new Date("2020-10-01T00:00:00.000Z");
|
|
1873
|
+
const result = await restore(
|
|
1874
|
+
asSource([
|
|
1875
|
+
event(1, s, 0, "Incremented", t, { amount: 1 }),
|
|
1876
|
+
{
|
|
1877
|
+
id: 2,
|
|
1878
|
+
stream: s,
|
|
1879
|
+
version: 1,
|
|
1880
|
+
name: import_act.SNAP_EVENT,
|
|
1881
|
+
data: { count: 1 },
|
|
1882
|
+
created: t,
|
|
1883
|
+
meta: { correlation: "snap", causation: {} }
|
|
1884
|
+
},
|
|
1885
|
+
event(3, s, 2, "Incremented", t, { amount: 2 })
|
|
1886
|
+
]),
|
|
1887
|
+
{ drop_snapshots: true }
|
|
1888
|
+
);
|
|
1889
|
+
(0, import_vitest3.expect)(result.kept).toBe(2);
|
|
1890
|
+
(0, import_vitest3.expect)(result.dropped.snapshots).toBe(1);
|
|
1891
|
+
const back = await collect(store, {
|
|
1892
|
+
stream: s,
|
|
1893
|
+
stream_exact: true,
|
|
1894
|
+
with_snaps: true
|
|
1895
|
+
});
|
|
1896
|
+
(0, import_vitest3.expect)(back).toHaveLength(2);
|
|
1897
|
+
(0, import_vitest3.expect)(
|
|
1898
|
+
back.every((e) => e.name !== import_act.SNAP_EVENT)
|
|
1899
|
+
).toBe(true);
|
|
1900
|
+
});
|
|
1901
|
+
(0, import_vitest3.it)("on_progress fires once per event (caller throttles)", async () => {
|
|
1902
|
+
const calls = [];
|
|
1903
|
+
const s = `restore-progress-${uid()}`;
|
|
1904
|
+
const t = /* @__PURE__ */ new Date("2021-02-01T00:00:00.000Z");
|
|
1905
|
+
await restore(
|
|
1906
|
+
asSource([
|
|
1907
|
+
event(1, s, 0, "Incremented", t, { amount: 1 }),
|
|
1908
|
+
event(2, s, 1, "Incremented", t, { amount: 2 })
|
|
1909
|
+
]),
|
|
1910
|
+
{ on_progress: (p) => calls.push(p.processed) }
|
|
1911
|
+
);
|
|
1912
|
+
(0, import_vitest3.expect)(calls).toEqual([1, 2]);
|
|
1913
|
+
});
|
|
1914
|
+
});
|
|
1548
1915
|
if (caps.notify) {
|
|
1549
1916
|
(0, import_vitest3.describe)("notify (capability)", () => {
|
|
1550
1917
|
(0, import_vitest3.it)("delivers a notification when a different instance commits", async () => {
|