From c7e0dd3902c9384f4bfc64d2f4a7b80c8a4a69bf Mon Sep 17 00:00:00 2001 From: "Mark S. Miller" Date: Fri, 7 Oct 2022 19:46:32 -0700 Subject: [PATCH] fix: test-collections passes --- .../src/liveslots/collectionManager.js | 38 +++++++++----- .../SwingSet/test/stores/test-collections.js | 52 +++++++++++++------ packages/store/src/index.js | 2 + 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/packages/SwingSet/src/liveslots/collectionManager.js b/packages/SwingSet/src/liveslots/collectionManager.js index e4319adede58..4f7ee406b6df 100644 --- a/packages/SwingSet/src/liveslots/collectionManager.js +++ b/packages/SwingSet/src/liveslots/collectionManager.js @@ -14,6 +14,8 @@ import { isEncodedRemotable, makeCopySet, makeCopyMap, + mustCompress, + decompress, } from '@agoric/store'; import { Far, passStyleOf } from '@endo/marshal'; import { decodeToJustin } from '@endo/marshal/src/marshal-justin.js'; @@ -214,7 +216,7 @@ export function makeCollectionManager( return storeKindInfo[kindName].kindID; } - // Not that it's only used for this purpose, what should it be called? + // Now that it's only used for this purpose, what should it be called? // TODO Should we be using the new encodeBigInt scheme instead, anyway? const BIGINT_TAG_LEN = 10; @@ -258,8 +260,22 @@ export function makeCollectionManager( const dbKeyPrefix = `vc.${collectionID}.`; let currentGenerationNumber = 0; - const keyLabel = `key type for collection ${label}`; - const valueLabel = `value type for collection ${label}`; + const keyLabel = `invalid key type for collection ${q(label)}`; + const valueLabel = `invalid value type for collection ${q(label)}`; + + const serializeValue = value => { + if (valueShape === undefined) { + return serialize(value); + } + return serialize(mustCompress(value, valueShape, valueLabel)); + }; + + const unserializeValue = data => { + if (valueShape === undefined) { + return unserialize(data); + } + return decompress(unserialize(data), valueShape); + }; function prefix(dbEntryKey) { return `${dbKeyPrefix}${dbEntryKey}`; @@ -335,11 +351,10 @@ export function makeCollectionManager( } function get(key) { - matches(key, keyShape) || - assert.fail(X`invalid key type for collection ${q(label)}`); + fit(key, keyShape, keyLabel); const result = syscall.vatstoreGet(keyToDBKey(key)); if (result) { - return unserialize(JSON.parse(result)); + return unserializeValue(JSON.parse(result)); } assert.fail(X`key ${key} not found in collection ${q(label)}`); } @@ -362,7 +377,7 @@ export function makeCollectionManager( fit(value, valueShape, valueLabel); } currentGenerationNumber += 1; - const serializedValue = serialize(value); + const serializedValue = serializeValue(value); assertAcceptableSyscallCapdataSize([serializedValue]); if (durable) { serializedValue.slots.forEach((vref, slotIndex) => { @@ -394,7 +409,7 @@ export function makeCollectionManager( if (valueShape !== undefined) { fit(value, valueShape, valueLabel); } - const after = serialize(harden(value)); + const after = serializeValue(harden(value)); assertAcceptableSyscallCapdataSize([after]); if (durable) { after.slots.forEach((vref, i) => { @@ -412,8 +427,7 @@ export function makeCollectionManager( } function deleteInternal(key) { - matches(key, keyShape) || - assert.fail(X`invalid key type for collection ${q(label)}`); + fit(key, keyShape, keyLabel); const dbKey = keyToDBKey(key); const rawValue = syscall.vatstoreGet(dbKey); assert(rawValue, X`key ${key} not found in collection ${q(label)}`); @@ -472,7 +486,7 @@ export function makeCollectionManager( if (dbKey < end) { priorDBKey = dbKey; if (ignoreKeys) { - const value = unserialize(JSON.parse(dbValue)); + const value = unserializeValue(JSON.parse(dbValue)); if (matches(value, valuePatt)) { yield [undefined, value]; } @@ -484,7 +498,7 @@ export function makeCollectionManager( } else { const key = dbKeyToKey(dbKey); if (matches(key, keyPatt)) { - const value = unserialize(JSON.parse(dbValue)); + const value = unserializeValue(JSON.parse(dbValue)); if (matches(value, valuePatt)) { yield [key, value]; } diff --git a/packages/SwingSet/test/stores/test-collections.js b/packages/SwingSet/test/stores/test-collections.js index 0750dc99a3bb..c70604412404 100644 --- a/packages/SwingSet/test/stores/test-collections.js +++ b/packages/SwingSet/test/stores/test-collections.js @@ -174,7 +174,9 @@ test('constrain map key shape', t => { t.is(stringsOnly.get('skey'), 'this should work'); t.throws( () => stringsOnly.init(29, 'this should not work'), - m('invalid key type for collection "map key strings only"'), + m( + 'invalid key type for collection "map key strings only": number 29 - Must be a string', + ), ); const noStrings = makeScalarBigMapStore('map key no strings', { @@ -184,27 +186,31 @@ test('constrain map key shape', t => { noStrings.init(true, 'boolean ok'); t.throws( () => noStrings.init('foo', 'string not ok?'), - m('invalid key type for collection "map key no strings"'), + m( + 'invalid key type for collection "map key no strings": "foo" - Must fail negated pattern: "[match:string]"', + ), ); t.is(noStrings.get(47), 'number ok'); t.is(noStrings.get(true), 'boolean ok'); t.falsy(noStrings.has('foo')); t.throws( () => noStrings.get('foo'), - m('invalid key type for collection "map key no strings"'), + m( + 'invalid key type for collection "map key no strings": "foo" - Must fail negated pattern: "[match:string]"', + ), ); const only47 = makeScalarBigMapStore('map key only 47', { keyShape: 47 }); only47.init(47, 'this number ok'); t.throws( () => only47.init(29, 'this number not ok?'), - m('invalid key type for collection "map key only 47"'), + m('invalid key type for collection "map key only 47": 29 - Must be: 47'), ); t.is(only47.get(47), 'this number ok'); t.falsy(only47.has(29)); t.throws( () => only47.get(29), - m('invalid key type for collection "map key only 47"'), + m('invalid key type for collection "map key only 47": 29 - Must be: 47'), ); const lt47 = makeScalarBigMapStore('map key less than 47', { @@ -213,13 +219,17 @@ test('constrain map key shape', t => { lt47.init(29, 'this number ok'); t.throws( () => lt47.init(53, 'this number not ok?'), - m('invalid key type for collection "map key less than 47"'), + m( + 'invalid key type for collection "map key less than 47": 53 - Must be < 47', + ), ); t.is(lt47.get(29), 'this number ok'); t.falsy(lt47.has(53)); t.throws( () => lt47.get(53), - m('invalid key type for collection "map key less than 47"'), + m( + 'invalid key type for collection "map key less than 47": 53 - Must be < 47', + ), ); lt47.init(11, 'lower value'); lt47.init(46, 'higher value'); @@ -235,7 +245,9 @@ test('constrain map value shape', t => { t.is(stringsOnly.get('sval'), 'string value'); t.throws( () => stringsOnly.init('nval', 29), - m('invalid value type for collection "map value strings only"'), + m( + 'invalid value type for collection "map value strings only": number 29 - Must be a string', + ), ); const noStrings = makeScalarBigMapStore('map value no strings', { @@ -245,7 +257,9 @@ test('constrain map value shape', t => { noStrings.init('bkey', true); t.throws( () => noStrings.init('skey', 'string not ok?'), - m('invalid value type for collection "map value no strings"'), + m( + 'invalid value type for collection "map value no strings": "string not ok?" - Must fail negated pattern: "[match:string]"', + ), ); t.is(noStrings.get('nkey'), 47); t.is(noStrings.get('bkey'), true); @@ -257,7 +271,9 @@ test('constrain map value shape', t => { only47.init('47key', 47); t.throws( () => only47.init('29key', 29), - m('invalid value type for collection "map value only 47"'), + m( + 'invalid value type for collection "map value only 47": 29 - Must be: 47', + ), ); t.is(only47.get('47key'), 47); t.falsy(only47.has('29key')); @@ -268,7 +284,9 @@ test('constrain map value shape', t => { lt47.init('29key', 29); t.throws( () => lt47.init('53key', 53), - m('invalid value type for collection "map value less than 47"'), + m( + 'invalid value type for collection "map value less than 47": 53 - Must be < 47', + ), ); t.is(lt47.get('29key'), 29); t.falsy(lt47.has('53key')); @@ -288,7 +306,9 @@ test('constrain set key shape', t => { t.truthy(stringsOnly.has('skey')); t.throws( () => stringsOnly.add(29), - m('invalid key type for collection "strings only set"'), + m( + 'invalid key type for collection "strings only set": number 29 - Must be a string', + ), ); const noStrings = makeScalarBigSetStore('no strings set', { @@ -298,7 +318,9 @@ test('constrain set key shape', t => { noStrings.add(true); t.throws( () => noStrings.add('foo?'), - m('invalid key type for collection "no strings set"'), + m( + 'invalid key type for collection "no strings set": "foo?" - Must fail negated pattern: "[match:string]"', + ), ); t.truthy(noStrings.has(47)); t.truthy(noStrings.has(true)); @@ -311,7 +333,7 @@ test('constrain set key shape', t => { t.falsy(only47.has(29)); t.throws( () => only47.add(29), - m('invalid key type for collection "only 47 set"'), + m('invalid key type for collection "only 47 set": 29 - Must be: 47'), ); const lt47 = makeScalarBigSetStore('less than 47 set', { @@ -320,7 +342,7 @@ test('constrain set key shape', t => { lt47.add(29); t.throws( () => lt47.add(53), - m('invalid key type for collection "less than 47 set"'), + m('invalid key type for collection "less than 47 set": 53 - Must be < 47'), ); t.truthy(lt47.has(29)); t.falsy(lt47.has(53)); diff --git a/packages/store/src/index.js b/packages/store/src/index.js index bf5b306f4bd3..ec9cd6f8223d 100755 --- a/packages/store/src/index.js +++ b/packages/store/src/index.js @@ -56,6 +56,8 @@ export { fit, } from './patterns/patternMatchers.js'; +export { compress, mustCompress, decompress } from './patterns/compress.js'; + export { defendPrototype, initEmpty,