diff --git a/shells/dev-shell/index.js b/shells/dev-shell/index.js index d72140e03ad..ed6f97a38ca 100644 --- a/shells/dev-shell/index.js +++ b/shells/dev-shell/index.js @@ -7,28 +7,25 @@ * subject to an additional IP rights grant found at * http://polymer.github.io/PATENTS.txt */ + import './file-pane.js'; import './output-pane.js'; import '../configuration/whitelisted.js'; import '../lib/platform/loglevel-web.js'; -import {Runtime} from '../../build/runtime/runtime.js'; -import {RamDiskStorageDriverProvider} from '../../build/runtime/storage/drivers/ramdisk.js'; -import {SimpleVolatileMemoryProvider} from '../../build/runtime/storage/drivers/volatile.js'; -import {DirectStorageEndpointManager} from '../../build/runtime/storage/direct-storage-endpoint-manager.js'; -import {Loader} from '../../build/platform/loader.js'; import {Arc} from '../../build/runtime/arc.js'; -import {IdGenerator} from '../../build/runtime/id.js'; -import {pecIndustry} from '../../build/platform/pec-industry-web.js'; +import {Runtime} from '../../build/runtime/runtime.js'; import {RecipeResolver} from '../../build/runtime/recipe-resolver.js'; import {devtoolsArcInspectorFactory} from '../../build/devtools-connector/devtools-arc-inspector.js'; -import {SlotComposer} from '../../build/runtime/slot-composer.js'; import {SlotObserver} from '../lib/xen-renderer.js'; -import '../../build/services/random-service.js'; - +// how to reach arcs root from our URL/CWD const root = '../..'; -const urlMap = Runtime.mapFromRootPath(root); + +// extra params for created arcs +const extraArcParams = { + inspectorFactory: devtoolsArcInspectorFactory +}; // import DOM node references const { @@ -41,21 +38,19 @@ const { helpButton } = window; -let memoryProvider; init(); function init() { - memoryProvider = new SimpleVolatileMemoryProvider(); - RamDiskStorageDriverProvider.register(memoryProvider); - + // prepare ui filePane.init(execute, toggleFilesButton, exportFilesButton); executeButton.addEventListener('click', execute); helpButton.addEventListener('click', showHelp); popupContainer.addEventListener('click', () => popupContainer.style.display = 'none'); - + // scan window parameters const params = new URLSearchParams(window.location.search); + // set logLevel window.logLevel = (params.get('log') !== null) ? 1 : 0; - + // seed manifest as requested const manifestParam = params.get('m') || params.get('manifest'); if (manifestParam) { filePane.seedManifest(manifestParam.split(';').map(m => `import '${m}'`)); @@ -76,101 +71,103 @@ recipe h0: copy DataStore P data: reads h0`; - const exampleParticle = `\ defineParticle(({SimpleParticle, html, log}) => { return class extends SimpleParticle { get template() { log(\`Add '?log' to the URL to enable particle logging\`); - return html\`{{num}} : {{str}}\`; + return \`
{{num}} : {{str}}
\`; } render({data}) { return data ? {num: data.num, str: data.txt} : {}; } }; });`; - filePane.seedExample(exampleManifest, exampleParticle); } } function execute() { - wrappedExecute().catch(e => outputPane.showError('Unhandled exception', e.stack)); + wrappedExecute().catch(e => { + outputPane.showError('Unhandled exception', e.stack); + console.error(e); + }); } async function wrappedExecute() { + // clear ui document.dispatchEvent(new Event('clear-arcs-explorer')); outputPane.reset(); - - const loader = new Loader(urlMap, filePane.getFileMap()); - // TODO(sjmiles): should be a static method - loader.flushCaches(); - - const pecFactory = pecIndustry(loader); - - let manifest; + // establish a runtime using custom parameters + const runtime = new Runtime({rootPath: root, staticMap: filePane.getFileMap()}); + runtime.loader.flushCaches(); + // attempt to parse the context manifest try { - const options = {loader, fileName: './manifest', throwImportErrors: true, memoryProvider}; - manifest = await Runtime.parseManifest(filePane.getManifest(), options); + runtime.context = await runtime.parse(filePane.getManifest(), {fileName: './manifest', throwImportErrors: true}); } catch (e) { outputPane.showError('Error in Manifest.parse', e); return; } - - if (manifest.allRecipes.length == 0) { + // check for existence of recipes + if (runtime.context.allRecipes.length == 0) { outputPane.showError('No recipes found in Manifest.parse'); } - + // instantiate an arc for each recipe in context let arcIndex = 1; - for (const recipe of manifest.allRecipes) { - const id = IdGenerator.newSession().newArcId('arc' + arcIndex++); - const arcPanel = outputPane.addArcPanel(id); + for (const recipe of runtime.context.allRecipes) { + createRecipeArc(recipe, runtime, arcIndex++); + } +} - const errors = new Map(); - if (!recipe.normalize({errors})) { - arcPanel.showError('Error in recipe.normalize', [...errors.values()].join('\n')); - continue; - } +async function createRecipeArc(recipe, runtime, index) { + // ask runtime to assemble arc parameter boilerplate (argument is the arc name) + const params = runtime.buildArcParams(`arc${index}`); + // construct the arc + const arc = new Arc({...params, extraArcParams}); + // establish a UI Surface + const arcPanel = outputPane.addArcPanel(params.id); + // attach a renderer (SlotObserver and a DOM node) to the composer + params.slotComposer.observeSlots(new SlotObserver(arcPanel.shadowRoot)); + // attach arc to bespoke shell ui + arcPanel.attachArc(arc); + arc.arcPanel = arcPanel; + try { + normalizeRecipe(arc, recipe); + const resolvedRecipe = await resolveRecipe(arc, recipe); + await instantiateRecipe(arc, resolvedRecipe); + } catch (x) { + arcPanel.showError('recipe error', x); + return; + } + // display description + await arcPanel.arcInstantiated(await Runtime.getArcDescription(arc)); +} - const slotComposer = new SlotComposer(); - slotComposer.observeSlots(new SlotObserver(arcPanel.shadowRoot)); - - const arc = new Arc({ - id, - context: manifest, - pecFactories: [pecFactory], - slotComposer, - loader, - storageManager: new DirectStorageEndpointManager(), - inspectorFactory: devtoolsArcInspectorFactory - }); - arcPanel.attachArc(arc); - - recipe.normalize(); - - let resolvedRecipe = null; - if (recipe.isResolved()) { - resolvedRecipe = recipe; - } else { - const resolver = new RecipeResolver(arc); - const options = {errors: new Map()}; - resolvedRecipe = await resolver.resolve(recipe, options); - if (!resolvedRecipe) { - arcPanel.showError('Error in RecipeResolver', `${ - [...options.errors.entries()].join('\n') - }.\n${recipe.toString()}`); - continue; - } - } +function normalizeRecipe(arc, recipe) { + const errors = new Map(); + if (!recipe.normalize({errors})) { + throw `Error in recipe.normalize: ${[...errors.values()].join('\n')}`; + } +} - try { - await arc.instantiate(resolvedRecipe); - } catch (e) { - arcPanel.showError('Error in arc.instantiate', e); - continue; +async function resolveRecipe(arc, recipe) { + let resolved = recipe; + if (!recipe.isResolved()) { + const errors = new Map(); + const resolver = new RecipeResolver(arc); + resolved = await resolver.resolve(recipe, {errors}); + if (!resolved) { + throw `Error in RecipeResolver: ${[...errors.entries()].join('\n')}.\n${recipe.toString()}`; } - const description = await Runtime.getArcDescription(arc); - await arcPanel.arcInstantiated(description); + } + return resolved; +} + +async function instantiateRecipe(arc, recipe) { + try { + await arc.instantiate(recipe); + } catch (e) { + throw `Error in arc.instantiate: ${e}`; } } diff --git a/shells/tests/arcs/ts/runtime/arc-test.ts b/shells/tests/arcs/ts/runtime/arc-test.ts index 0535cef22d2..33a3efacd7e 100644 --- a/shells/tests/arcs/ts/runtime/arc-test.ts +++ b/shells/tests/arcs/ts/runtime/arc-test.ts @@ -24,13 +24,9 @@ import {handleForStoreInfo, CollectionEntityType} from '../../../../../build/run import '../../../../lib/arcs-ui/dist/install-ui-classes.js'; describe('Arc', () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('deserializing a serialized arc with a Transformation produces that arc', async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + runtime.context = await runtime.parse(` import 'src/runtime/tests/artifacts/Common/Multiplexer.manifest' import 'src/runtime/tests/artifacts/test-particles.manifest' @@ -42,17 +38,15 @@ describe('Arc', () => { annotation: consumes slot0 list: reads handle0 - `, {loader, fileName: ''}); + `); - const recipe = manifest.recipes[0]; - const slotComposer = new SlotComposer(); - const id = Id.fromString('test2'); - const storageKey = new VolatileStorageKey(id, ''); - const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({id, storageKey, context: manifest, slotComposer, loader: new Loader(), storageService}); + const params = runtime.buildArcParams('test2'); + const arc = new Arc(params); - const barType = manifest.findTypeByName('Bar') as EntityType; + const barType = runtime.context.findTypeByName('Bar') as EntityType; let store = await arc.createStore(barType.collectionOf(), undefined, 'test:1'); + + const recipe = runtime.context.recipes[0]; recipe.handles[0].mapToStorage(store); assert(recipe.normalize()); @@ -64,7 +58,8 @@ describe('Arc', () => { const serialization = await arc.serialize(); arc.dispose(); - const newArc = await Arc.deserialize({serialization, loader, slotComposer, fileName: './manifest.manifest', context: manifest, storageService}); + const {loader, context, slotComposer, storageService, driverFactory} = params; + const newArc = await Arc.deserialize({serialization, loader, slotComposer, fileName: './manifest.manifest', context, storageService, driverFactory}); await newArc.idle; store = newArc.findStoreById(store.id) as StoreInfo; const handle = await handleForStoreInfo(store, newArc); @@ -123,7 +118,6 @@ describe('Arc', () => { current = next; } - const slotComposer = new SlotComposer(); const loader = new Loader(null, { ...sources, 'Z.js': `defineParticle(({UiParticle}) => { @@ -132,7 +126,8 @@ describe('Arc', () => { }; });`, }); - const context = await Manifest.parse(` + const runtime = new Runtime({loader}); + runtime.context = await runtime.parse(` particle A in 'A.js' root: consumes Slot @@ -141,9 +136,8 @@ describe('Arc', () => { A root: consumes root `); - const id = IdGenerator.newSession().newArcId('arcid'); - const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({id, loader, slotComposer, context, storageService}); + const opts = runtime.buildArcParams('arcid'); + const arc = new Arc(opts); const [recipe] = arc.context.recipes; recipe.normalize(); @@ -151,10 +145,9 @@ describe('Arc', () => { }); it('handles serialization/deserialization of empty arcs handles', async () => { - const id = ArcId.newForTest('test'); - const loader = new Loader(); - - const manifest = await Manifest.parse(` + //const id = ArcId.newForTest('test'); + const runtime = new Runtime(); + runtime.context = await runtime.parse(` schema FavoriteFood food: Text @@ -167,20 +160,20 @@ describe('Arc', () => { foods: create #favoriteFoods FavoriteFoodPicker foods: foods - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `); - const storageKey = new VolatileStorageKey(id, ''); - const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({id, storageKey, loader: new Loader(), context: manifest, storageService}); + const opts = runtime.buildArcParams('test'); + //opts.id = id; + const arc = new Arc(opts); assert.isNotNull(arc); - const favoriteFoodClass = Entity.createEntityClass(manifest.findSchemaByName('FavoriteFood'), null); + const favoriteFoodClass = Entity.createEntityClass(runtime.context.findSchemaByName('FavoriteFood'), null); assert.isNotNull(favoriteFoodClass); - const recipe = manifest.recipes[0]; + const recipe = runtime.context.recipes[0]; assert.isNotNull(recipe); - const favoriteFoodType = manifest.findTypeByName('FavoriteFood'); + const favoriteFoodType = runtime.context.findTypeByName('FavoriteFood'); assert.isNotNull(favoriteFoodType, 'FavoriteFood type is found'); const options = {errors: new Map()}; @@ -190,10 +183,8 @@ describe('Arc', () => { await arc.instantiate(recipe); const serialization = await arc.serialize(); - - const slotComposer = new SlotComposer(); - - const newArc = await Arc.deserialize({serialization, loader, slotComposer, context: manifest, fileName: 'foo.manifest', storageService}); + const {loader, slotComposer, context, storageService, driverFactory} = opts; + const newArc = await Arc.deserialize({serialization, loader, slotComposer, context, fileName: 'foo.manifest', storageService, driverFactory}); assert.strictEqual(newArc.stores.length, 1); assert.strictEqual(newArc.activeRecipe.toString(), `@active\n${arc.activeRecipe.toString()}`); assert.strictEqual(newArc.id.idTreeAsString(), 'test'); diff --git a/shells/tests/arcs/ts/runtime/hotreload-integration-test.ts b/shells/tests/arcs/ts/runtime/hotreload-integration-test.ts index 1869c272be5..48fb0cec327 100644 --- a/shells/tests/arcs/ts/runtime/hotreload-integration-test.ts +++ b/shells/tests/arcs/ts/runtime/hotreload-integration-test.ts @@ -17,7 +17,7 @@ import '../../../../lib/arcs-ui/dist/install-ui-classes.js'; describe('Hot Code Reload for JS Particle', async () => { it('updates model and template', async () =>{ const context = await Manifest.parse(` - particle A in 'A.js' + particle A in './A.js' root: consumes Slot recipe @@ -25,7 +25,7 @@ describe('Hot Code Reload for JS Particle', async () => { A root: consumes slot0`); const loader = new Loader(null, { - 'A.js': `defineParticle(({UiParticle}) => { + './A.js': `defineParticle(({UiParticle}) => { return class extends UiParticle { get template() { return 'Hello {{name}}, old age: {{age}}'; } @@ -49,7 +49,7 @@ describe('Hot Code Reload for JS Particle', async () => { //assert.deepStrictEqual(slotConsumer.getRendering().model, {name: 'Jack', age: '10'}); //assert.deepStrictEqual(slotConsumer._content.template, `Hello {{name}}, old age: {{age}}`); - loader.staticMap['A.js'] = `defineParticle(({UiParticle}) => { + loader.staticMap['./A.js'] = `defineParticle(({UiParticle}) => { return class extends UiParticle { get template() { return 'Hello {{name}}, new age: {{age}}'; } diff --git a/shells/tests/arcs/ts/runtime/multiplexer-integration-test.ts b/shells/tests/arcs/ts/runtime/multiplexer-integration-test.ts index e601c788201..2a7c0291b26 100644 --- a/shells/tests/arcs/ts/runtime/multiplexer-integration-test.ts +++ b/shells/tests/arcs/ts/runtime/multiplexer-integration-test.ts @@ -114,8 +114,6 @@ describe('Multiplexer', () => { const entity = Entity.identify(entityClass, '4', null); await postsHandle2.add(entity); await arc.idle; - - Runtime.resetDrivers(); }); // TODO(sjmiles): probably should be in particles/tests/* because of Multiplexer.js diff --git a/shells/tests/arcs/ts/runtime/plan-consumer-test.ts b/shells/tests/arcs/ts/runtime/plan-consumer-test.ts index f87cb05ac7f..2f96bc62cf7 100644 --- a/shells/tests/arcs/ts/runtime/plan-consumer-test.ts +++ b/shells/tests/arcs/ts/runtime/plan-consumer-test.ts @@ -33,14 +33,6 @@ async function storeResults(consumer: PlanConsumer, suggestions: Suggestion[]) { } describe('plan consumer', () => { - beforeEach(() => { - Runtime.resetDrivers(); - }); - - afterEach(() => { - Runtime.resetDrivers(); - }); - it('consumes', async () => { const manifestText = ` import './shells/tests/artifacts/Products/Products.recipes' diff --git a/shells/tests/arcs/ts/runtime/products-test.ts b/shells/tests/arcs/ts/runtime/products-test.ts index 66867b00353..921e91ef1dd 100644 --- a/shells/tests/arcs/ts/runtime/products-test.ts +++ b/shells/tests/arcs/ts/runtime/products-test.ts @@ -18,11 +18,6 @@ import {StoreInfo} from '../../../../../build/runtime/storage/store-info.js'; import '../../../../lib/arcs-ui/dist/install-ui-classes.js'; describe('products test', () => { - - afterEach(() => { - Runtime.resetDrivers(); - }); - const manifestFilename = './shells/tests/artifacts/ProductsTestNg.arcs'; const verifyFilteredBook = async (arc: Arc) => { diff --git a/shells/tests/arcs/ts/runtime/slot-composer-test.ts b/shells/tests/arcs/ts/runtime/slot-composer-test.ts index 675ea4c6267..9ded4517195 100644 --- a/shells/tests/arcs/ts/runtime/slot-composer-test.ts +++ b/shells/tests/arcs/ts/runtime/slot-composer-test.ts @@ -58,11 +58,6 @@ async function initSlotComposer(recipeStr) { } describe('slot composer', () => { - - afterEach(() => { - Runtime.resetDrivers(); - }); - it('initialize recipe and render slots', async () => { const manifestStr = ` particle A in 'a.js' diff --git a/shells/tests/arcs/ts/runtime/transformation-slots-test.ts b/shells/tests/arcs/ts/runtime/transformation-slots-test.ts index d003760fd44..8467b03e768 100644 --- a/shells/tests/arcs/ts/runtime/transformation-slots-test.ts +++ b/shells/tests/arcs/ts/runtime/transformation-slots-test.ts @@ -16,10 +16,6 @@ import {StrategyTestHelper} from '../../../../../build/planning/testing/strategy import '../../../../lib/arcs-ui/dist/install-ui-classes.js'; describe('transformation slots', () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('combines hosted particles provided singleton slots into transformation provided set slot', async () => { const runtime = new Runtime(); runtime.context = await runtime.parseFile('./shells/tests/artifacts/provide-hosted-particle-slots.manifest'); diff --git a/src/planning/plan/tests/plan-consumer-test.ts b/src/planning/plan/tests/plan-consumer-test.ts index b0c2e6df6d0..6c877969c5a 100644 --- a/src/planning/plan/tests/plan-consumer-test.ts +++ b/src/planning/plan/tests/plan-consumer-test.ts @@ -35,15 +35,6 @@ async function storeResults(consumer: PlanConsumer, suggestions: Suggestion[]) { } describe('plan consumer', () => { - - beforeEach(() => { - Runtime.resetDrivers(); - }); - - afterEach(() => { - Runtime.resetDrivers(); - }); - it('filters suggestions by modality', async () => { const initConsumer = async (modality) => { const addRecipe = (particles) => { @@ -97,17 +88,14 @@ ${addRecipe(['ParticleTouch', 'ParticleBoth'])} assert.lengthOf(domSuggestions, 2); assert.deepEqual(domSuggestions.map(s => s.plan.particles.map(p => p.name)), [['ParticleDom'], ['ParticleDom', 'ParticleBoth']]); - Runtime.resetDrivers(); const consumerVr = await initConsumer(Modality.vr); assert.isEmpty(consumerVr.getCurrentSuggestions()); - Runtime.resetDrivers(); const consumerTouch = await initConsumer(Modality.domTouch); const touchSuggestions = consumerTouch.getCurrentSuggestions(); assert.lengthOf(touchSuggestions, 2); assert.deepEqual(touchSuggestions.map(s => s.plan.particles.map(p => p.name)), [['ParticleTouch'], ['ParticleTouch', 'ParticleBoth']]); - Runtime.resetDrivers(); }); }); diff --git a/src/planning/plan/tests/plan-producer-test.ts b/src/planning/plan/tests/plan-producer-test.ts index 4f3411cdc26..fd83d37377f 100644 --- a/src/planning/plan/tests/plan-producer-test.ts +++ b/src/planning/plan/tests/plan-producer-test.ts @@ -10,8 +10,6 @@ import {assert} from '../../../platform/chai-web.js'; import {Arc} from '../../../runtime/arc.js'; import {ArcId} from '../../../runtime/id.js'; -import {Loader} from '../../../platform/loader.js'; -import {Manifest} from '../../../runtime/manifest.js'; import {Runtime} from '../../../runtime/runtime.js'; import {storageKeyPrefixForTest, storageKeyForTest} from '../../../runtime/testing/handle-for-test.js'; import {PlanProducer} from '../../plan/plan-producer.js'; @@ -79,13 +77,6 @@ class TestPlanProducer extends PlanProducer { // Run test suite for each storageKeyBase describe('plan producer', () => { - beforeEach(() => { - Runtime.resetDrivers(); - }); - - afterEach(() => { - Runtime.resetDrivers(); - }); async function createProducer() { const runtime = new Runtime(); diff --git a/src/planning/plan/tests/planificator-test.ts b/src/planning/plan/tests/planificator-test.ts index 5c84f1bc2fc..bc8ffdbc38f 100644 --- a/src/planning/plan/tests/planificator-test.ts +++ b/src/planning/plan/tests/planificator-test.ts @@ -18,7 +18,6 @@ import {TestVolatileMemoryProvider} from '../../../runtime/testing/test-volatile import {Planificator} from '../../plan/planificator.js'; import {PlanningResult} from '../../plan/planning-result.js'; import {floatingPromiseToAudit} from '../../../utils/lib-utils.js'; -import {DriverFactory} from '../../../runtime/storage/drivers/driver-factory.js'; import {storageKeyPrefixForTest, storageKeyForTest} from '../../../runtime/testing/handle-for-test.js'; import {MockFirebaseStorageKey} from '../../../runtime/storage/testing/mock-firebase.js'; import {DirectStorageEndpointManager} from '../../../runtime/storage/direct-storage-endpoint-manager.js'; @@ -48,29 +47,22 @@ describe('planificator', () => { describe.skip('remote planificator', () => { // TODO: support arc storage key be in PouchDB as well. let arcStorageKey; + let runtime; - let memoryProvider; + //let memoryProvider; beforeEach(() => { - Runtime.resetDrivers(); arcStorageKey = storageKeyPrefixForTest(); - memoryProvider = new TestVolatileMemoryProvider(); - RamDiskStorageDriverProvider.register(memoryProvider); - }); - - afterEach(() => { - Runtime.resetDrivers(); + runtime = new Runtime(); }); async function createArc(options, storageKey) { const {manifestString, manifestFilename} = options; - const loader = new Loader(); - const context = manifestString - ? await Manifest.parse(manifestString, {loader, fileName: '', memoryProvider}) - : await Manifest.load(manifestFilename, loader, {memoryProvider}); - const storageService = new DirectStorageEndpointManager(); - const runtime = new Runtime({loader, context, memoryProvider, storageService}); + runtime.context = manifestString + ? await runtime.parse(manifestString) + : await runtime.parseFile(manifestFilename); return runtime.newArc('demo', storageKey); } + async function createConsumePlanificator(manifestFilename) { const arc = await createArc({manifestFilename}, arcStorageKey); const storageKeyBase = storageKeyForTest(arc.id); @@ -105,7 +97,8 @@ describe.skip('remote planificator', () => { fileName: '', pecFactories: undefined, context: consumePlanificator.arc.context, - storageService + storageService, + driverFactory: runtime.driverFactory }); // producePlanificator = new Planificator( diff --git a/src/planning/plan/tests/planning-result-test.ts b/src/planning/plan/tests/planning-result-test.ts index 622fa33ad81..a5347651a63 100644 --- a/src/planning/plan/tests/planning-result-test.ts +++ b/src/planning/plan/tests/planning-result-test.ts @@ -22,19 +22,12 @@ import {StrategyTestHelper} from '../../testing/strategy-test-helper.js'; import {VolatileStorageDriverProvider} from '../../../runtime/storage/drivers/volatile.js'; describe('planning result', () => { - beforeEach(() => { - Runtime.resetDrivers(); - }); - afterEach(() => { - Runtime.resetDrivers(); - }); - it('serializes and deserializes Products recipes', async () => { const runtime = new Runtime(); runtime.context = await runtime.parseFile('./src/runtime/tests/artifacts/Products/Products.recipes'); const arc = runtime.newArc('demo', storageKeyPrefixForTest()); - VolatileStorageDriverProvider.register(arc); + VolatileStorageDriverProvider.register(runtime, arc); const suggestions = await StrategyTestHelper.planForArc(runtime, arc); assert.isNotEmpty(suggestions); @@ -93,14 +86,6 @@ describe('planning result', () => { }); describe('planning result merge', () => { - beforeEach(() => { - Runtime.resetDrivers(); - }); - - afterEach(() => { - Runtime.resetDrivers(); - }); - const commonManifestStr = ` schema Thing foo: Text diff --git a/src/planning/plan/tests/test-environment-test.ts b/src/planning/plan/tests/test-environment-test.ts index 04efd83b5af..bf36b33e1dc 100644 --- a/src/planning/plan/tests/test-environment-test.ts +++ b/src/planning/plan/tests/test-environment-test.ts @@ -8,7 +8,6 @@ * http://polymer.github.io/PATENTS.txt */ import {registerSystemExceptionHandler, removeSystemExceptionHandler, defaultSystemExceptionHandler} from '../../../runtime/arc-exceptions.js'; -import {Runtime} from '../../../runtime/runtime.js'; let exceptions: Error[] = []; @@ -24,5 +23,4 @@ afterEach(function() { // Error function not yet included in mocha typescript declarations... this.test['error'](exception); } - Runtime.resetDrivers(); }); diff --git a/src/planning/recipe-index.ts b/src/planning/recipe-index.ts index 9593afa7d97..a19eb40d2e1 100644 --- a/src/planning/recipe-index.ts +++ b/src/planning/recipe-index.ts @@ -94,12 +94,13 @@ export class RecipeIndex { const trace = Tracing.start({cat: 'indexing', name: 'RecipeIndex::constructor', overview: true}); const idGenerator = IdGenerator.newSession(); const arcStub = new Arc({ + stub: true, id: idGenerator.newArcId('index-stub'), context: new Manifest({id: idGenerator.newArcId('empty-context')}), - loader: arc.loader, slotComposer: new SlotComposer({noRoot: true}), - stub: true, - storageService: arc.storageService + loader: arc.loader, + storageService: arc.storageService, + driverFactory: arc.driverFactory }); const strategizer = new Strategizer( [ diff --git a/src/planning/strategies/tests/coalesce-recipes-test.ts b/src/planning/strategies/tests/coalesce-recipes-test.ts index fb4b6d5d308..9aeacecc027 100644 --- a/src/planning/strategies/tests/coalesce-recipes-test.ts +++ b/src/planning/strategies/tests/coalesce-recipes-test.ts @@ -14,12 +14,6 @@ import {StrategyTestHelper} from '../../testing/strategy-test-helper.js'; import {Runtime} from '../../../runtime/runtime.js'; describe('CoalesceRecipes', () => { - beforeEach(() => { - }); - afterEach(() => { - Runtime.resetDrivers(); - }); - async function tryCoalesceRecipes(manifestStr: string) { const runtime = new Runtime(); const manifest = await runtime.parse(manifestStr); diff --git a/src/planning/strategies/tests/search-tokens-to-handles-test.ts b/src/planning/strategies/tests/search-tokens-to-handles-test.ts index f108c13ac9a..6f4599a31dc 100644 --- a/src/planning/strategies/tests/search-tokens-to-handles-test.ts +++ b/src/planning/strategies/tests/search-tokens-to-handles-test.ts @@ -20,10 +20,6 @@ describe('SearchTokensToHandles', () => { beforeEach(() => { runtime = new Runtime(); }); - afterEach(() => { - Runtime.resetDrivers(); - }); - it('finds local handle by tags', async () => { const manifest = await runtime.parse(` schema Thing diff --git a/src/planning/tests/planner-test.ts b/src/planning/tests/planner-test.ts index 57833f5e74e..4916f844eff 100644 --- a/src/planning/tests/planner-test.ts +++ b/src/planning/tests/planner-test.ts @@ -38,7 +38,6 @@ async function planFromManifest(manifest, {arcFactory, testSteps}: {arcFactory?, planner.init(arc, options); const result = await testSteps(planner); - Runtime.resetDrivers(); return result; } @@ -565,12 +564,6 @@ ${recipeManifest} }); describe('Type variable resolution', () => { - beforeEach(() => { - }); - afterEach(() => { - Runtime.resetDrivers(); - }); - const loadAndPlan = async manifestStr => { const runtime = new Runtime({loader: new NullLoader()}); const manifest = await runtime.parse(manifestStr); diff --git a/src/runtime/arc.ts b/src/runtime/arc.ts index 3148e2d66eb..d5b7e31ca8d 100644 --- a/src/runtime/arc.ts +++ b/src/runtime/arc.ts @@ -14,7 +14,8 @@ import {FakePecFactory} from './fake-pec-factory.js'; import {Id, IdGenerator} from './id.js'; import {Loader} from '../platform/loader.js'; import {Capabilities} from './capabilities.js'; -import {CapabilitiesResolver} from './capabilities-resolver.js'; +import {_CapabilitiesResolver} from './capabilities-resolver.js'; +import {StorageKeyParser} from './storage/storage-key-parser.js'; import {Dictionary, Runnable, compareComparables, Mutex} from '../utils/lib-utils.js'; import {Manifest} from './manifest.js'; import {MessagePort} from './message-channel.js'; @@ -26,20 +27,18 @@ import {SlotComposer} from './slot-composer.js'; import {CollectionType, EntityType, InterfaceInfo, InterfaceType, TupleType, ReferenceType, SingletonType, Type, TypeVariable} from '../types/lib-types.js'; import {PecFactory} from './particle-execution-context.js'; -import {VolatileMemory, VolatileStorageDriverProvider, VolatileStorageKey} from './storage/drivers/volatile.js'; -import {DriverFactory} from './storage/drivers/driver-factory.js'; -import {Exists} from './storage/drivers/driver.js'; import {StorageKey} from './storage/storage-key.js'; import {ArcSerializer, ArcInterface} from './arc-serializer.js'; import {ReferenceModeStorageKey} from './storage/reference-mode-storage-key.js'; import {SystemTrace} from '../tracelib/systrace.js'; -import {StorageKeyParser} from './storage/storage-key-parser.js'; +import {StorageService} from './storage/storage-service.js'; import {SingletonInterfaceHandle, handleForStoreInfo, TypeToCRDTTypeRecord} from './storage/storage.js'; import {StoreInfo} from './storage/store-info.js'; -import {CRDTTypeRecord} from '../crdt/lib-crdt.js'; import {ActiveStore} from './storage/active-store.js'; +import {Exists} from './storage/drivers/driver.js'; +import {DriverFactory} from './storage/drivers/driver-factory.js'; +import {VolatileMemory, VolatileStorageDriverProvider, VolatileStorageKey} from './storage/drivers/volatile.js'; import {ProxyCallback, ProxyMessageType} from './storage/store-interface.js'; -import {StorageService} from './storage/storage-service.js'; export type ArcOptions = Readonly<{ id: Id; @@ -54,25 +53,28 @@ export type ArcOptions = Readonly<{ stub?: boolean; inspectorFactory?: ArcInspectorFactory; ports?: MessagePort[]; - capabilitiesResolver?: CapabilitiesResolver; + capabilitiesResolver?: _CapabilitiesResolver; modality?: Modality; + driverFactory: DriverFactory; }>; type DeserializeArcOptions = Readonly<{ serialization: string; + fileName: string; + context: Manifest; storageService: StorageService; pecFactories?: PecFactory[]; slotComposer?: SlotComposer; loader: Loader; - fileName: string; - context: Manifest; inspectorFactory?: ArcInspectorFactory; + driverFactory: DriverFactory; }>; @SystemTrace export class Arc implements ArcInterface { private readonly _context: Manifest; private readonly pecFactories: PecFactory[]; + //private readonly driverFactory: DriverFactory; public readonly isSpeculative: boolean; public readonly isInnerArc: boolean; public readonly isStub: boolean; @@ -85,7 +87,7 @@ export class Arc implements ArcInterface { // storage keys for referenced handles private storeInfoById: Dictionary> = {}; public readonly storageKey?: StorageKey; - private readonly capabilitiesResolver?: CapabilitiesResolver; + private readonly capabilitiesResolver?: _CapabilitiesResolver; // Map from each store ID to a set of tags. public for debug access public readonly storeTagsById: Dictionary> = {}; // Map from each store to its description (originating in the manifest). @@ -102,22 +104,22 @@ export class Arc implements ArcInterface { readonly peh: ParticleExecutionHost; public readonly storageService: StorageService; + public driverFactory: DriverFactory; // Volatile storage local to this Arc instance. readonly volatileMemory = new VolatileMemory(); private readonly volatileStorageDriverProvider: VolatileStorageDriverProvider; - constructor({id, context, storageService, pecFactories, slotComposer, loader, storageKey, speculative, innerArc, stub, capabilitiesResolver, inspectorFactory, modality} : ArcOptions) { + constructor({id, context, storageService, pecFactories, slotComposer, loader, storageKey, speculative, innerArc, stub, capabilitiesResolver, inspectorFactory, modality, driverFactory} : ArcOptions) { this._context = context; this.modality = modality; + this.driverFactory = driverFactory; // TODO: pecFactories should not be optional. update all callers and fix here. this.pecFactories = pecFactories && pecFactories.length > 0 ? pecFactories.slice() : [FakePecFactory(loader).bind(null)]; - // TODO(sjmiles): currently some UiBrokers need to recover arc from composer in order to forward events if (slotComposer && !slotComposer['arc']) { slotComposer['arc'] = this; } - this.id = id; this.isSpeculative = !!speculative; // undefined => false this.isInnerArc = !!innerArc; // undefined => false @@ -128,10 +130,10 @@ export class Arc implements ArcInterface { this.storageKey = storageKey; const ports = this.pecFactories.map(f => f(this.generateID(), this.idGenerator)); this.peh = new ParticleExecutionHost({slotComposer, arc: this, ports}); - this.volatileStorageDriverProvider = new VolatileStorageDriverProvider(this); - DriverFactory.register(this.volatileStorageDriverProvider); - this.capabilitiesResolver = capabilitiesResolver; this.storageService = storageService; + this.capabilitiesResolver = capabilitiesResolver; + this.volatileStorageDriverProvider = new VolatileStorageDriverProvider(this); + driverFactory.register(this.volatileStorageDriverProvider); } get loader(): Loader { @@ -171,7 +173,7 @@ export class Arc implements ArcInterface { this.peh.slotComposer.dispose(); } - DriverFactory.unregister(this.volatileStorageDriverProvider); + //this.driverFactory.unregister(this.volatileStorageDriverProvider); } // Returns a promise that spins sending a single `AwaitIdle` message until it @@ -232,7 +234,18 @@ export class Arc implements ArcInterface { createInnerArc(transformationParticle: Particle): Arc { const id = this.generateID('inner'); - const innerArc = new Arc({id, storageService: this.storageService, pecFactories: this.pecFactories, slotComposer: this.peh.slotComposer, loader: this._loader, context: this.context, innerArc: true, speculative: this.isSpeculative, inspectorFactory: this.inspectorFactory}); + const innerArc = new Arc({ + id, + storageService: this.storageService, + pecFactories: this.pecFactories, + slotComposer: this.peh.slotComposer, + loader: this._loader, + context: this.context, + innerArc: true, + speculative: this.isSpeculative, + inspectorFactory: this.inspectorFactory, + driverFactory: this.driverFactory + }); let particleInnerArcs = this.innerArcsByParticle.get(transformationParticle); if (!particleInnerArcs) { @@ -255,11 +268,11 @@ export class Arc implements ArcInterface { throw new Error('persistSerialization unimplemented, pending synthetic type support in new storage stack'); } - static async deserialize({serialization, pecFactories, slotComposer, loader, fileName, context, inspectorFactory, storageService}: DeserializeArcOptions): Promise { + static async deserialize({serialization, pecFactories, slotComposer, loader, fileName, context, inspectorFactory, storageService, driverFactory}: DeserializeArcOptions): Promise { const manifest = await Manifest.parse(serialization, {loader, fileName, context}); const id = Id.fromString(manifest.meta.name); - const storageKey = StorageKeyParser.parse(manifest.meta.storageKey); - const arc = new Arc({id, storageKey, slotComposer, pecFactories, loader, context, inspectorFactory, storageService}); + const storageKey = StorageKeyParser['parse'](manifest.meta.storageKey); + const arc = new Arc({id, storageKey, slotComposer, pecFactories, loader, context, inspectorFactory, storageService, driverFactory}); await Promise.all(manifest.stores.map(async storeStub => { const tags = [...manifest.storeTagsById[storeStub.id]]; @@ -359,14 +372,17 @@ export class Arc implements ArcInterface { // Makes a copy of the arc used for speculative execution. async cloneForSpeculativeExecution(): Promise { - const arc = new Arc({id: this.generateID(), - pecFactories: this.pecFactories, - context: this.context, - loader: this._loader, - speculative: true, - innerArc: this.isInnerArc, - inspectorFactory: this.inspectorFactory, - storageService: this.storageService}); + const arc = new Arc({ + id: this.generateID(), + pecFactories: this.pecFactories, + context: this.context, + loader: this._loader, + speculative: true, + innerArc: this.isInnerArc, + inspectorFactory: this.inspectorFactory, + storageService: this.storageService, + driverFactory: this.driverFactory + }); const storeMap: Map, StoreInfo> = new Map(); for (const storeInfo of this.stores) { // TODO(alicej): Should we be able to clone a StoreMux as well? diff --git a/src/runtime/capabilities-resolver.ts b/src/runtime/capabilities-resolver.ts index 6b48e23e401..4407d9013cc 100644 --- a/src/runtime/capabilities-resolver.ts +++ b/src/runtime/capabilities-resolver.ts @@ -12,37 +12,39 @@ import {assert} from '../platform/assert-web.js'; import {Dictionary} from '../utils/lib-utils.js'; import {StorageKey} from './storage/storage-key.js'; import {Type} from '../types/lib-types.js'; +import {ArcId} from './id.js'; +import {Flags} from './flags.js'; import {Capabilities} from './capabilities.js'; import {ReferenceModeStorageKey} from './storage/reference-mode-storage-key.js'; -import {Flags} from './flags.js'; -import {StorageKeyFactory, FactorySelector, ContainerStorageKeyOptions, BackingStorageKeyOptions, +import {StorageKeyFactory, + FactorySelector, + ContainerStorageKeyOptions, + BackingStorageKeyOptions, SimpleCapabilitiesSelector} from './storage-key-factory.js'; -import {ArcId} from './id.js'; export type CapabilitiesResolverOptions = Readonly<{ arcId: ArcId; }>; -export class CapabilitiesResolver { - private static defaultStorageKeyFactories: Dictionary = {}; - private static readonly defaultSelector = new SimpleCapabilitiesSelector(); - +export class _CapabilitiesResolver { + private defaultStorageKeyFactories: Dictionary = {}; + private readonly defaultSelector = new SimpleCapabilitiesSelector(); private readonly factories: Dictionary = {}; - constructor(public readonly options: CapabilitiesResolverOptions & { + constructor(public readonly options?: CapabilitiesResolverOptions & { factories?: StorageKeyFactory[], selector? : FactorySelector}) { - for (const factory of (options.factories || [])) { + for (const factory of (options?.factories || [])) { assert(!this.factories[factory.protocol], `Duplicated factory for '${factory.protocol}'.`); this.factories[factory.protocol] = factory; } - for (const factory of Object.values(CapabilitiesResolver.defaultStorageKeyFactories)) { + for (const factory of Object.values(this.defaultStorageKeyFactories)) { if (!this.factories[factory.protocol]) { this.factories[factory.protocol] = factory; } } } - get selector() { return this.options.selector || CapabilitiesResolver.defaultSelector; } + get selector() { return this.options.selector || this.defaultSelector; } async createStorageKey(capabilities: Capabilities, type: Type, handleId: string): Promise { const factory = this.selectStorageKeyFactory(capabilities, handleId); @@ -54,39 +56,41 @@ export class CapabilitiesResolver { return factory.supports(capabilities); }); if (selectedFactories.length === 0) { - throw new Error(`Cannot create a suitable storage key for handle '${handleId}' with capabilities ${capabilities.toDebugString()}`); + throw new Error(`Cannot create a suitable storage key for handle '${ + handleId}' with capabilities ${capabilities.toDebugString()}`); } return this.selector.select(selectedFactories); } private async createStorageKeyWithFactory(factory: StorageKeyFactory, type: Type, handleId: string): Promise { - const schemaHash = await type.getEntitySchema().hash(); - const containerKey = factory.create(new ContainerStorageKeyOptions( - this.options.arcId, schemaHash, type.getEntitySchema().name)); + const schema = type.getEntitySchema(); + const schemaHash = await schema.hash(); + const options = new ContainerStorageKeyOptions(this.options.arcId, schemaHash, schema.name); + const containerKey = factory.create(options); const containerChildKey = containerKey.childKeyForHandle(handleId); if (!Flags.defaultReferenceMode) { return containerChildKey; } - if (type.isReference || - (type.getContainedType() && type.getContainedType().isReference)) { + const containedType = type.getContainedType(); + if (type.isReference || (containedType && containedType.isReference)) { return containerChildKey; } - const backingKey = factory.create(new BackingStorageKeyOptions( - this.options.arcId, schemaHash, type.getEntitySchema().name)); - + const backingKey = factory.create(new BackingStorageKeyOptions(this.options.arcId, schemaHash, schema.name)); // ReferenceModeStorageKeys in different drivers can cause problems with garbage collection. assert(backingKey.protocol === containerKey.protocol); - return new ReferenceModeStorageKey(backingKey, containerChildKey); } - static registerStorageKeyFactory(factory: StorageKeyFactory) { - assert(!CapabilitiesResolver.defaultStorageKeyFactories[factory.protocol], - `Storage key factory for '${factory.protocol}' already registered`); - CapabilitiesResolver.defaultStorageKeyFactories[factory.protocol] = factory; + registerStorageKeyFactory(factory: StorageKeyFactory) { + const defaultFactories = this.defaultStorageKeyFactories; + assert(!defaultFactories[factory.protocol], `Storage key factory for '${factory.protocol}' already registered`); + defaultFactories[factory.protocol] = factory; } - static reset() { - CapabilitiesResolver.defaultStorageKeyFactories = {}; + reset() { + this.defaultStorageKeyFactories = {}; } } + +//export const CapabilitiesResolver = new _CapabilitiesResolver(); + diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index e597b3d55d5..480577e1af5 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -28,7 +28,6 @@ import {TypeChecker} from './type-checker.js'; import {ClaimIsTag} from './arcs-types/claim.js'; import {StorageKey} from './storage/storage-key.js'; import {Exists} from './storage/drivers/driver.js'; -import {StorageKeyParser} from './storage/storage-key-parser.js'; import {VolatileMemoryProvider, VolatileStorageKey} from './storage/drivers/volatile.js'; import {RamDiskStorageKey} from './storage/drivers/ramdisk.js'; import {ReferenceModeStorageKey} from './storage/reference-mode-storage-key.js'; @@ -39,6 +38,8 @@ import {canonicalManifest} from './canonical-manifest.js'; import {Policy} from './policy/policy.js'; import {resolveFieldPathType} from './field-path.js'; import {StoreInfo, StoreClaims} from './storage/store-info.js'; +import {StorageKeyParser} from './storage/storage-key-parser.js'; + export enum ErrorSeverity { Error = 'error', diff --git a/src/runtime/particle-execution-context.ts b/src/runtime/particle-execution-context.ts index 0c32961c82d..781f1fde558 100644 --- a/src/runtime/particle-execution-context.ts +++ b/src/runtime/particle-execution-context.ts @@ -18,6 +18,7 @@ import {ParticleSpec} from './arcs-types/particle-spec.js'; import {Particle, Capabilities} from './particle.js'; import {StorageProxy} from './storage/storage-proxy.js'; import {CRDTTypeRecord} from '../crdt/lib-crdt.js'; +//import {StorageCommunicationEndpoint, StorageCommunicationEndpointProvider} from './storage/store-interface.js'; import {ProxyCallback, ProxyMessage, StorageCommunicationEndpoint} from './storage/store-interface.js'; import {PropagatedException} from './arc-exceptions.js'; import {Type, MuxType} from '../types/lib-types.js'; @@ -30,12 +31,16 @@ import {Ttl} from './capabilities.js'; import {Handle} from './storage/handle.js'; import {StorageProxyMuxer} from './storage/storage-proxy-muxer.js'; import {EntityHandleFactory} from './storage/entity-handle-factory.js'; -import {CRDTMuxEntity, TypeToCRDTTypeRecord, CRDTTypeRecordToType} from './storage/storage.js'; +//import {CRDTMuxEntity, CRDTTypeRecordToType} from './storage/storage.js'; +//import {createStorageEndpoint} from './storage/storage-endpoint.js'; +import {CRDTMuxEntity/*, TypeToCRDTTypeRecord, CRDTTypeRecordToType*/} from './storage/storage.js'; import {StorageEndpointImpl} from './storage/storage-endpoint.js'; import {StorageFrontend} from './storage/storage-frontend.js'; import {StoreInfo} from './storage/store-info.js'; -import {VolatileStorageKey} from './storage/drivers/volatile.js'; -import {StorageKeyParser} from './storage/storage-key-parser.js'; +//import {VolatileStorageKey} from './storage/drivers/volatile.js'; +//import {StorageKeyParser} from './storage/storage-key-parser.js'; + +//StorageKeyParser.addDefaultParser(VolatileStorageKey.protocol, VolatileStorageKey.fromString); export type PecFactory = (pecId: Id, idGenerator: IdGenerator) => MessagePort; @@ -69,7 +74,7 @@ export class ParticleExecutionContext implements StorageFrontend { private readonly pecId: Id; private readonly loader: Loader; private readonly pendingLoads = []>[]; - private readonly keyedProxies: Dictionary | Promise>> = {}; + //private readonly keyedProxies: Dictionary | Promise>> = {}; private readonly keyedProxyMuxers: Dictionary | Promise>> = {}; private readonly wasmContainers: Dictionary = {}; @@ -469,4 +474,4 @@ export class ParticleExecutionContext implements StorageFrontend { } } -StorageKeyParser.addDefaultParser(VolatileStorageKey.protocol, VolatileStorageKey.fromString); +//StorageKeyParser.addDefaultParser(VolatileStorageKey.protocol, VolatileStorageKey.fromString); diff --git a/src/runtime/recipe/tests/recipe-test.ts b/src/runtime/recipe/tests/recipe-test.ts index cabdf04e027..746cfa8b902 100644 --- a/src/runtime/recipe/tests/recipe-test.ts +++ b/src/runtime/recipe/tests/recipe-test.ts @@ -25,10 +25,6 @@ describe('recipe', () => { runtime = new Runtime(); }); - afterEach(() => { - Runtime.resetDrivers(); - }); - it('normalize errors', async () => { const manifest = await runtime.parse(` schema S1 diff --git a/src/runtime/runtime.ts b/src/runtime/runtime.ts index 87a532a8789..41a46774ea3 100644 --- a/src/runtime/runtime.ts +++ b/src/runtime/runtime.ts @@ -11,8 +11,7 @@ import {assert} from '../platform/assert-web.js'; import {Description} from './description.js'; import {Manifest} from './manifest.js'; -import {Arc} from './arc.js'; -import {CapabilitiesResolver} from './capabilities-resolver.js'; +import {ArcOptions, Arc} from './arc.js'; import {RuntimeCacheService} from './runtime-cache.js'; import {IdGenerator, ArcId, Id} from './id.js'; import {PecFactory} from './particle-execution-context.js'; @@ -28,12 +27,15 @@ import {workerPool} from './worker-pool.js'; import {Modality} from './arcs-types/modality.js'; import {StorageKey} from './storage/storage-key.js'; import {StorageKeyFactory} from './storage-key-factory.js'; -import {StorageKeyParser} from './storage/storage-key-parser.js'; import {DriverFactory} from './storage/drivers/driver-factory.js'; -import {RamDiskStorageDriverProvider} from './storage/drivers/ramdisk.js'; -import {SimpleVolatileMemoryProvider, VolatileMemoryProvider, VolatileStorageKey, VolatileStorageKeyFactory} from './storage/drivers/volatile.js'; +import {StorageKeyParser} from './storage/storage-key-parser.js'; +import {_CapabilitiesResolver} from './capabilities-resolver.js'; import {StorageService} from './storage/storage-service.js'; +//import {StorageEndpointManager} from './storage/storage-manager.js'; import {DirectStorageEndpointManager} from './storage/direct-storage-endpoint-manager.js'; +import {RamDiskStorageDriverProvider} from './storage/drivers/ramdisk.js'; +import {SimpleVolatileMemoryProvider, VolatileMemoryProvider, VolatileStorageKey, VolatileStorageKeyFactory, VolatileStorageDriverProvider} from './storage/drivers/volatile.js'; +//import {Env} from './env.js'; const {warn} = logsFactory('Runtime', 'orange'); @@ -45,7 +47,8 @@ export type RuntimeOptions = Readonly<{ composerClass?: typeof SlotComposer; context?: Manifest; rootPath?: string, - urlMap?: {} + urlMap?: {}, + staticMap?: {} }>; export type RuntimeArcOptions = Readonly<{ @@ -60,39 +63,22 @@ export type RuntimeArcOptions = Readonly<{ modality?: Modality; }>; - -// TODO(sjmiles): weird layering here due to dancing around global state (working on it) -let staticMemoryProvider; -const initDrivers = () => { - VolatileStorageKey.register(); - staticMemoryProvider = new SimpleVolatileMemoryProvider(); - RamDiskStorageDriverProvider.register(staticMemoryProvider); -}; - -initDrivers(); +type StorageKeyPrefixer = (arcId: ArcId) => StorageKey; const nob = Object.create(null); @SystemTrace export class Runtime { - public context: Manifest; - public readonly pecFactory: PecFactory; - public readonly loader: Loader | null; - private cacheService: RuntimeCacheService; - private composerClass: typeof SlotComposer | null; - private memoryProvider: VolatileMemoryProvider; - readonly storageService: StorageService; - readonly arcById = new Map(); + // TODO(sjmiles): patching over layer problems due to static objects static resetDrivers(noDefault?: true) { - DriverFactory.providers = new Set(); - StorageKeyParser.reset(); - CapabilitiesResolver.reset(); - if (!noDefault) { - initDrivers(); - } + console.log('!FrOnK'); } + // TODO(sjmiles): static methods represent boilerplate. + // There's no essential reason they are part of Runtime. + // Consider. + static mapFromRootPath(root: string) { // TODO(sjmiles): this is a commonly-used map, but it's not generic enough to live here. // Shells that use this default should be provide it to `init` themselves. @@ -111,20 +97,90 @@ export class Runtime { }; } + /** + * Given an arc, returns it's description as a string. + */ + static async getArcDescription(arc: Arc) : Promise { + // Verify that it's one of my arcs, and make this non-static, once I have + // Runtime objects in the calling code. + return (await Description.create(arc)).getArcDescription(); + } + + static async resolveRecipe(arc: Arc, recipe: Recipe): Promise { + if (this.normalize(recipe)) { + if (recipe.isResolved()) { + return recipe; + } + const resolver = new RecipeResolver(arc); + const plan = await resolver.resolve(recipe); + if (plan && plan.isResolved()) { + return plan; + } + warn('failed to resolve:\n', (plan || recipe).toString({showUnresolved: true})); + } + return null; + } + + static normalize(recipe: Recipe): boolean { + if (Runtime.isNormalized(recipe)) { + return true; + } + const errors = new Map(); + if (recipe.normalize({errors})) { + return true; + } + warn('failed to normalize:\n', errors, recipe.toString()); + return false; + } + + static isNormalized(recipe: Recipe): boolean { + return Object.isFrozen(recipe); + } + + // non-static members + + public context: Manifest; + public readonly pecFactory: PecFactory; + public readonly loader: Loader | null; + private cacheService: RuntimeCacheService; + private composerClass: typeof SlotComposer | null; + public memoryProvider: VolatileMemoryProvider; + public readonly storageService: StorageService; + public readonly arcById = new Map(); + public driverFactory: DriverFactory; + public storageKeyParser: StorageKeyParser; + public capabilitiesResolver: _CapabilitiesResolver; + constructor(opts: RuntimeOptions = {}) { + const customMap = opts.urlMap || nob; const rootMap = opts.rootPath && Runtime.mapFromRootPath(opts.rootPath) || nob; - const urlMap = opts.urlMap || nob; - const map = {...rootMap, ...urlMap}; - this.loader = opts.loader || new Loader(map); + this.loader = opts.loader || new Loader({...rootMap, ...customMap}, opts.staticMap); this.pecFactory = opts.pecFactory || pecIndustry(this.loader); this.composerClass = opts.composerClass || SlotComposer; this.cacheService = new RuntimeCacheService(); - this.memoryProvider = opts.memoryProvider || staticMemoryProvider; + this.memoryProvider = opts.memoryProvider || new SimpleVolatileMemoryProvider(); + //this.storageManager = opts.storageManager || new DirectStorageEndpointManager(); + //this.memoryProvider = opts.memoryProvider || staticMemoryProvider; this.storageService = opts.storageService || new DirectStorageEndpointManager(); this.context = opts.context || new Manifest({id: 'manifest:default'}); + this.initDrivers(); // user information. One persona per runtime for now. } + initDrivers() { + // storage drivers + this.driverFactory = new DriverFactory(); + this.storageKeyParser = new StorageKeyParser(); + this.capabilitiesResolver = new _CapabilitiesResolver(); + VolatileStorageKey.register(this); + // TODO(sjmiles): affects DriverFactory + RamDiskStorageDriverProvider.register(this); + } + + destroy() { + workerPool.clear(); + } + getCacheService() { return this.cacheService; } @@ -133,8 +189,24 @@ export class Runtime { return this.memoryProvider; } - destroy() { - workerPool.clear(); + buildArcParams(name?: string, storageKeyPrefix?: StorageKeyPrefixer): ArcOptions { + const id = IdGenerator.newSession().newArcId(name); + const {loader, context} = this; + const factories = [new VolatileStorageKeyFactory()]; + return { + id, + loader, + context, + pecFactories: [this.pecFactory], + slotComposer: this.composerClass ? new this.composerClass() : null, + storageService: this.storageService, + capabilitiesResolver: new _CapabilitiesResolver({arcId: id, factories}), + driverFactory: this.driverFactory, + storageKey: storageKeyPrefix ? storageKeyPrefix(id) : new VolatileStorageKey(id, '') + }; + //const volatileStorageDriverProvider = new VolatileStorageDriverProvider(this); + //DriverFactory.register(this.volatileStorageDriverProvider); + //return {id, loader, pecFactories, slotComposer, storageManager, capabilitiesResolver, context}; } // TODO(shans): Clean up once old storage is removed. @@ -146,9 +218,9 @@ export class Runtime { const slotComposer = this.composerClass ? new this.composerClass() : null; const storageKey = storageKeyPrefix ? storageKeyPrefix(id) : new VolatileStorageKey(id, ''); const factories = (options && options.storargeKeyFactories) || [new VolatileStorageKeyFactory()]; - const capabilitiesResolver = new CapabilitiesResolver({arcId: id, factories}); - const {loader, context, storageService} = this; - return new Arc({id, storageKey, capabilitiesResolver, loader, slotComposer, context, storageService, ...options}); + const capabilitiesResolver = new _CapabilitiesResolver({arcId: id, factories}); + const {loader, context, storageService, driverFactory} = this; + return new Arc({id, storageKey, capabilitiesResolver, loader, slotComposer, context, storageService, driverFactory, ...options}); } /** @@ -157,10 +229,15 @@ export class Runtime { * (2) a deserialized arc (TODO: needs implementation) * (3) a newly created arc */ - runArc(name: string, storageKeyPrefix: (arcId: ArcId) => StorageKey, options?: RuntimeArcOptions): Arc { + runArc(name: string, storageKeyPrefix: StorageKeyPrefixer, options?: RuntimeArcOptions): Arc { if (!this.arcById.has(name)) { // TODO: Support deserializing serialized arcs. - this.arcById.set(name, this.newArc(name, storageKeyPrefix, options)); + const params = { + ...this.buildArcParams(name, storageKeyPrefix), + ...options + }; + const arc = new Arc(params); + this.arcById.set(name, arc); } return this.arcById.get(name); } @@ -175,20 +252,11 @@ export class Runtime { return [...this.arcById.values()].find(arc => !!arc.activeRecipe.findParticle(particleId)); } - /** - * Given an arc, returns it's description as a string. - */ - static async getArcDescription(arc: Arc) : Promise { - // Verify that it's one of my arcs, and make this non-static, once I have - // Runtime objects in the calling code. - return (await Description.create(arc)).getArcDescription(); - } - async parse(content: string, options?): Promise { const {loader, memoryProvider} = this; // TODO(sjmiles): this method of generating a manifest id is ad-hoc, // maybe should be using one of the id generators, or even better - // we could eliminate it if the Manifest object takes care of this. + // we could evacipate it if the Manifest object takes responsibility. const id = `in-memory-${Math.floor((Math.random()+1)*1e6)}.manifest`; // TODO(sjmiles): this is a virtual manifest, the fileName is invented const opts = {id, fileName: `./${id}`, loader, memoryProvider, ...options}; @@ -200,38 +268,4 @@ export class Runtime { const opts = {id: path, memoryProvider, ...options}; return Manifest.load(path, opts.loader || this.loader, opts); } - - // TODO(sjmiles): static methods represent boilerplate. - // There's no essential reason they are part of Runtime. - - static async resolveRecipe(arc: Arc, recipe: Recipe): Promise { - if (this.normalize(recipe)) { - if (recipe.isResolved()) { - return recipe; - } - const resolver = new RecipeResolver(arc); - const plan = await resolver.resolve(recipe); - if (plan && plan.isResolved()) { - return plan; - } - warn('failed to resolve:\n', (plan || recipe).toString({showUnresolved: true})); - } - return null; - } - - static normalize(recipe: Recipe): boolean { - if (Runtime.isNormalized(recipe)) { - return true; - } - const errors = new Map(); - if (recipe.normalize({errors})) { - return true; - } - warn('failed to normalize:\n', errors, recipe.toString()); - return false; - } - - static isNormalized(recipe: Recipe): boolean { - return Object.isFrozen(recipe); - } } diff --git a/src/runtime/storage/database-storage-key.ts b/src/runtime/storage/database-storage-key.ts index d05144dc391..2d160254191 100644 --- a/src/runtime/storage/database-storage-key.ts +++ b/src/runtime/storage/database-storage-key.ts @@ -11,7 +11,6 @@ import {assert} from '../../platform/assert-web.js'; import {StorageKey} from './storage-key.js'; import {Capabilities, Persistence, Queryable, Ttl, Shareable, DeletePropagation} from '../capabilities.js'; -import {CapabilitiesResolver} from '../capabilities-resolver.js'; import {StorageKeyFactory, StorageKeyOptions} from '../storage-key-factory.js'; export abstract class DatabaseStorageKey extends StorageKey { @@ -42,9 +41,9 @@ export abstract class DatabaseStorageKey extends StorageKey { return match; } - static register() { - CapabilitiesResolver.registerStorageKeyFactory(new PersistentDatabaseStorageKeyFactory()); - CapabilitiesResolver.registerStorageKeyFactory(new MemoryDatabaseStorageKeyFactory()); + static register({capabilitiesResolver}) { + capabilitiesResolver.registerStorageKeyFactory(new PersistentDatabaseStorageKeyFactory()); + capabilitiesResolver.registerStorageKeyFactory(new MemoryDatabaseStorageKeyFactory()); } } diff --git a/src/runtime/storage/direct-storage-endpoint-manager.ts b/src/runtime/storage/direct-storage-endpoint-manager.ts index 0b6fed6600d..5af70283e79 100644 --- a/src/runtime/storage/direct-storage-endpoint-manager.ts +++ b/src/runtime/storage/direct-storage-endpoint-manager.ts @@ -33,12 +33,15 @@ export class DirectStorageEndpointManager implements StorageService { if (ctor == null) { throw new Error(`No constructor registered for mode ${storeInfo.mode}`); } - this.activeStoresByKey.set(storeInfo.storageKey, await ctor.construct>({ + const construct = ctor.construct.bind(ctor); + //const instance = await ctor.construct>({ + const instance = await construct({ storageKey: storeInfo.storageKey, exists: storeInfo.exists, type: storeInfo.type as unknown as CRDTTypeRecordToType>, storeInfo: storeInfo as unknown as StoreInfo>>, - })); + }); + this.activeStoresByKey.set(storeInfo.storageKey, instance); storeInfo.exists = Exists.ShouldExist; } return this.activeStoresByKey.get(storeInfo.storageKey) as ActiveStore>; diff --git a/src/runtime/storage/direct-store-muxer.ts b/src/runtime/storage/direct-store-muxer.ts index 0a0a79c6f95..97553d60802 100644 --- a/src/runtime/storage/direct-store-muxer.ts +++ b/src/runtime/storage/direct-store-muxer.ts @@ -14,7 +14,7 @@ import {ActiveStore} from './active-store.js'; import {StorageKey} from './storage-key.js'; import {DirectStore} from './direct-store.js'; import {Dictionary, BiMap, noAwait} from '../../utils/lib-utils.js'; -import {StoreConstructorOptions, StorageMode, ProxyMessageType} from './store-interface.js'; +import {StoreConstructorOptions, ProxyMessageType} from './store-interface.js'; import {assert} from '../../platform/assert-web.js'; import {PropagatedException, reportSystemException} from '../arc-exceptions.js'; diff --git a/src/runtime/storage/drivers/driver-factory.ts b/src/runtime/storage/drivers/driver-factory.ts index 99480173173..49856d798e9 100644 --- a/src/runtime/storage/drivers/driver-factory.ts +++ b/src/runtime/storage/drivers/driver-factory.ts @@ -18,31 +18,43 @@ export interface StorageDriverProvider { driver(storageKey: StorageKey, exists: Exists): Promise>; } +let staticDriverFactory; + export class DriverFactory { - static providers: Set = new Set(); - static async driverInstance(storageKey: StorageKey, exists: Exists) { - for (const provider of this.providers) { - if (provider.willSupport(storageKey)) { - return provider.driver(storageKey, exists); - } - } - return null; + //name; + providers: Set = new Set(); + constructor() { + staticDriverFactory = this; + //this.name = Math.floor(Math.random()*90) + 10; + //console.warn('DriverFactory constructed: ', this.name); } - - static register(storageDriverProvider: StorageDriverProvider) { + register(storageDriverProvider: StorageDriverProvider) { + //console.warn(`DriverFactory(${this.name}).register`); //, storageDriverProvider); this.providers.add(storageDriverProvider); } - - static unregister(storageDriverProvider: StorageDriverProvider) { + unregister(storageDriverProvider: StorageDriverProvider) { this.providers.delete(storageDriverProvider); } - - static willSupport(storageKey: StorageKey) { + willSupport(storageKey: StorageKey) { + return !!(this.supportingProvider(storageKey)); + } + async driverInstance(storageKey: StorageKey, exists: Exists) { + const provider = this.supportingProvider(storageKey); + return provider ? provider.driver(storageKey, exists) : null; + } + supportingProvider(storageKey): StorageDriverProvider { for (const provider of this.providers) { if (provider.willSupport(storageKey)) { - return true; + return provider; } } - return false; + return null; + } + // statics + static register({driverFactory}, storageDriverProvider: StorageDriverProvider) { + driverFactory.register(storageDriverProvider); + } + static async driverInstance(storageKey: StorageKey, exists: Exists) { + return staticDriverFactory.driverInstance(storageKey, exists); } } diff --git a/src/runtime/storage/drivers/firebase.ts b/src/runtime/storage/drivers/firebase.ts index 41acba8b022..9128863695d 100644 --- a/src/runtime/storage/drivers/firebase.ts +++ b/src/runtime/storage/drivers/firebase.ts @@ -8,15 +8,12 @@ * http://polymer.github.io/PATENTS.txt */ -import {StorageDriverProvider, DriverFactory} from './driver-factory.js'; +import {StorageDriverProvider} from './driver-factory.js'; import {Driver, ReceiveMethod, Exists} from './driver.js'; import {StorageKey} from '../storage-key.js'; -import {ArcId} from '../../id.js'; import {RuntimeCacheService} from '../../runtime-cache.js'; import {assert} from '../../../platform/assert-web.js'; import {firebase} from '../../../../concrete-storage/firebase.js'; -import {StorageKeyParser} from '../storage-key-parser.js'; -import {CapabilitiesResolver} from '../../capabilities-resolver.js'; import {Capabilities, Persistence, Shareable} from '../../capabilities.js'; import {StorageKeyOptions, StorageKeyFactory} from '../../storage-key-factory.js'; @@ -73,7 +70,7 @@ export class FirebaseAppCache { getApp(key: FirebaseStorageKey) { const keyAsString = key.toString(); if (!this.appCache.has(keyAsString)) { - this.appCache.set(keyAsString, firebase.initializeApp(key)); + this.appCache.set(keyAsString, firebase.initializeApp(key, `[salt${Math.random()}]`)); } return this.appCache.get(keyAsString); } @@ -209,7 +206,6 @@ export class FirebaseDriver extends Driver { } } - export class FirebaseStorageDriverProvider implements StorageDriverProvider { protected readonly cacheService: RuntimeCacheService; @@ -227,15 +223,16 @@ export class FirebaseStorageDriverProvider implements StorageDriverProvider { } const driver = new FirebaseDriver(storageKey, exists); - await driver.init(new FirebaseAppCache(this.cacheService)); + const cache = new FirebaseAppCache(this.cacheService); + await driver.init(cache); return driver; } - static register(cacheService: RuntimeCacheService, options: FirebaseStorageKeyOptions) { - DriverFactory.register(new FirebaseStorageDriverProvider(cacheService)); - StorageKeyParser.addParser(FirebaseStorageKey.protocol, FirebaseStorageKey.fromString); + static register({driverFactory, storageKeyParser, capabilitiesResolver}, cacheService: RuntimeCacheService, options: FirebaseStorageKeyOptions) { + driverFactory.register(new FirebaseStorageDriverProvider(cacheService)); + storageKeyParser.addParser(FirebaseStorageKey.protocol, FirebaseStorageKey.fromString); const {projectId, domain, apiKey} = options; - CapabilitiesResolver.registerStorageKeyFactory(new FirebaseStorageKeyFactory(options)); + capabilitiesResolver.registerStorageKeyFactory(new FirebaseStorageKeyFactory(options)); } } diff --git a/src/runtime/storage/drivers/ramdisk.ts b/src/runtime/storage/drivers/ramdisk.ts index 4d425e55b0e..3776c30c201 100644 --- a/src/runtime/storage/drivers/ramdisk.ts +++ b/src/runtime/storage/drivers/ramdisk.ts @@ -11,11 +11,8 @@ import {StorageKey} from '../storage-key.js'; import {StorageDriverProvider, DriverFactory} from './driver-factory.js'; import {VolatileDriver, VolatileMemoryProvider} from './volatile.js'; -import {StorageKeyParser} from '../storage-key-parser.js'; import {Exists} from './driver.js'; -import {ArcId} from '../../id.js'; -import {Capabilities, Persistence, Encryption, Ttl, Queryable, Shareable} from '../../capabilities.js'; -import {CapabilitiesResolver} from '../../capabilities-resolver.js'; +import {Capabilities, Persistence, Shareable} from '../../capabilities.js'; import {StorageKeyFactory, StorageKeyOptions} from '../../storage-key-factory.js'; export class RamDiskStorageKey extends StorageKey { @@ -84,9 +81,9 @@ export class RamDiskStorageDriverProvider implements StorageDriverProvider { return new VolatileDriver(storageKey as RamDiskStorageKey, exists, memory); } - static register(memoryProvider: VolatileMemoryProvider) { - DriverFactory.register(new RamDiskStorageDriverProvider(memoryProvider)); - StorageKeyParser.addParser(RamDiskStorageKey.protocol, RamDiskStorageKey.fromString); - CapabilitiesResolver.registerStorageKeyFactory(new RamDiskStorageKeyFactory()); + static register({driverFactory, storageKeyParser, capabilitiesResolver, memoryProvider}) { + driverFactory.register(new RamDiskStorageDriverProvider(memoryProvider)); + storageKeyParser.addParser(RamDiskStorageKey.protocol, RamDiskStorageKey.fromString); + capabilitiesResolver.registerStorageKeyFactory(new RamDiskStorageKeyFactory()); } } diff --git a/src/runtime/storage/drivers/volatile.ts b/src/runtime/storage/drivers/volatile.ts index 6b718e85d81..31a1b30bad0 100644 --- a/src/runtime/storage/drivers/volatile.ts +++ b/src/runtime/storage/drivers/volatile.ts @@ -8,7 +8,7 @@ * http://polymer.github.io/PATENTS.txt */ -import {StorageDriverProvider, DriverFactory} from './driver-factory.js'; +import {StorageDriverProvider} from './driver-factory.js'; import {Driver, ReceiveMethod, Exists} from './driver.js'; import {StorageKey} from '../storage-key.js'; import {Arc} from '../../arc.js'; @@ -16,9 +16,7 @@ import {ArcId} from '../../id.js'; import {RamDiskStorageKey} from './ramdisk.js'; import {Dictionary} from '../../../utils/lib-utils.js'; import {assert} from '../../../platform/assert-web.js'; -import {StorageKeyParser} from '../storage-key-parser.js'; -import {Capabilities, Persistence, Encryption, Ttl, Queryable, Shareable} from '../../capabilities.js'; -import {CapabilitiesResolver} from '../../capabilities-resolver.js'; +import {Capabilities, Persistence, Shareable} from '../../capabilities.js'; import {StorageKeyFactory, StorageKeyOptions} from '../../storage-key-factory.js'; type VolatileEntry = {data: Data, version: number, drivers: VolatileDriver[]}; @@ -59,8 +57,12 @@ export class VolatileStorageKey extends StorageKey { return new VolatileStorageKey(ArcId.fromString(arcId), unique, path); } - static register() { - CapabilitiesResolver.registerStorageKeyFactory(new VolatileStorageKeyFactory()); + // static register() { + // CapabilitiesResolver.registerStorageKeyFactory(new VolatileStorageKeyFactory()); + // } + + static register({capabilitiesResolver}) { + capabilitiesResolver.registerStorageKeyFactory(new VolatileStorageKeyFactory()); } } @@ -267,9 +269,9 @@ export class VolatileStorageDriverProvider implements StorageDriverProvider { } // QUESTION: This method is never being called, is it needed? - static register(arc: Arc) { - DriverFactory.register(new VolatileStorageDriverProvider(arc)); + static register({driverFactory}, arc: Arc) { + driverFactory.register(new VolatileStorageDriverProvider(arc)); } } -StorageKeyParser.addDefaultParser(VolatileStorageKey.protocol, VolatileStorageKey.fromString); +//StorageKeyParser.addDefaultParser(VolatileStorageKey.protocol, VolatileStorageKey.fromString); diff --git a/src/runtime/storage/storage-key-parser.ts b/src/runtime/storage/storage-key-parser.ts index cd5aefed027..20ab40291c0 100644 --- a/src/runtime/storage/storage-key-parser.ts +++ b/src/runtime/storage/storage-key-parser.ts @@ -9,59 +9,74 @@ */ import {StorageKey, StorageKeyLiteral} from './storage-key.js'; import {ReferenceModeStorageKey} from './reference-mode-storage-key.js'; +import {VolatileStorageKey} from './drivers/volatile.js'; type ParserTopLevel = (key: string) => StorageKey; type Parser = (key: string, parse: ParserTopLevel) => StorageKey; +let staticParser; + /** * Parses storage key string representations back into real StorageKey * instances. * - * Singleton class with static methods. If you modify the default set of storage + * If you modify the default set of storage * keys in a test, remember to call StorageKeyParser.reset() in the tear-down * method. */ export class StorageKeyParser { - private static defaultParsers: [string, Parser][] = [ + private parsers; + + constructor() { + this.parsers = this.getDefaultParsers(); + staticParser = this; + } + + private defaultParsers: [string, Parser][] = [ [ReferenceModeStorageKey.protocol, ReferenceModeStorageKey.fromString], + [VolatileStorageKey.protocol, VolatileStorageKey.fromString] ]; - private static getDefaultParsers(): Map { + private getDefaultParsers(): Map { return new Map(this.defaultParsers); } - private static parsers = StorageKeyParser.getDefaultParsers(); - - static parse(key: string): StorageKey { + parse(key: string): StorageKey { const match = key.match(/^((?:\w|-)+):\/\/(.*)$/); if (!match) { throw new Error('Failed to parse storage key: ' + key); } const protocol = match[1]; - const parser = StorageKeyParser.parsers.get(protocol); + const parser = this.parsers.get(protocol); if (!parser) { throw new Error(`Unknown storage key protocol ${protocol} in key ${key}.`); } - return parser(key, StorageKeyParser.parse); + return parser(key, this.parse.bind(this)); } - static reset() { + reset() { this.parsers = this.getDefaultParsers(); } - static addParser(protocol: string, parser: Parser) { + addParser(protocol: string, parser: Parser) { if (this.parsers.has(protocol)) { throw new Error(`Parser for storage key protocol ${protocol} already exists.`); } this.parsers.set(protocol, parser); } - static addDefaultParser(protocol: string, parser: Parser) { + addDefaultParser(protocol: string, parser: Parser) { this.defaultParsers.push([protocol, parser]); if (!this.parsers.has(protocol)) { this.parsers.set(protocol, parser); } } + + static parse(key): StorageKey { + return staticParser.parse(key); + } } +staticParser = new StorageKeyParser(); + StorageKey.fromLiteral = (literal: StorageKeyLiteral) => StorageKeyParser.parse(literal.key); diff --git a/src/runtime/storage/testing/mock-firebase.ts b/src/runtime/storage/testing/mock-firebase.ts index bb9a31b672e..2554cc07e7a 100644 --- a/src/runtime/storage/testing/mock-firebase.ts +++ b/src/runtime/storage/testing/mock-firebase.ts @@ -16,7 +16,6 @@ import {Exists} from '../drivers/driver.js'; import {assert} from '../../../platform/chai-web.js'; import {RuntimeCacheService} from '../../runtime-cache.js'; import {StorageKeyParser} from '../storage-key-parser.js'; -import {StorageKeyOptions} from '../../storage-key-factory.js'; /** * These classes are intended to mimic firebase behaviour, including asynchrony. @@ -333,11 +332,12 @@ class MockFirebaseAppCache extends FirebaseAppCache { } export class MockFirebaseStorageDriverProvider extends FirebaseStorageDriverProvider { + static appCache; + async driver(storageKey: StorageKey, exists: Exists) { if (!this.willSupport(storageKey)) { throw new Error(`This provider does not support storageKey ${storageKey.toString()}`); } - return MockFirebaseStorageDriverProvider.newDriverForTesting(this.cacheService, storageKey, exists); } @@ -348,10 +348,13 @@ export class MockFirebaseStorageDriverProvider extends FirebaseStorageDriverProv return driver; } - static register(cacheService: RuntimeCacheService) { - DriverFactory.register(new MockFirebaseStorageDriverProvider(cacheService)); - StorageKeyParser.addParser(FirebaseStorageKey.protocol, FirebaseStorageKey.fromString); - const {projectId, domain, apiKey} = mockFirebaseStorageKeyOptions; + static register({driverFactory, storageKeyParser, capabilitiesResolver}, cacheService: RuntimeCacheService, options?: FirebaseStorageKeyOptions) { + //static register(cacheService: RuntimeCacheService) { + //DriverFactory.register(new MockFirebaseStorageDriverProvider(cacheService)); + //StorageKeyParser.addParser(FirebaseStorageKey.protocol, FirebaseStorageKey.fromString); + //const {projectId, domain, apiKey} = mockFirebaseStorageKeyOptions; + driverFactory.register(new MockFirebaseStorageDriverProvider(cacheService)); + storageKeyParser.addParser(MockFirebaseStorageKey.protocol, MockFirebaseStorageKey.fromString); } static getValueForTesting(cacheService: RuntimeCacheService, storageKey: MockFirebaseStorageKey) { diff --git a/src/runtime/storage/tests/active-store-test.ts b/src/runtime/storage/tests/active-store-test.ts index 163fb413474..1f7f1073ba1 100644 --- a/src/runtime/storage/tests/active-store-test.ts +++ b/src/runtime/storage/tests/active-store-test.ts @@ -23,22 +23,17 @@ import {ActiveStore} from '../active-store.js'; import {DirectStorageEndpointManager} from '../direct-storage-endpoint-manager.js'; import {Runtime} from '../../runtime.js'; -let testKey: StorageKey; - -async function createStore(): Promise> { - return new DirectStorageEndpointManager().getActiveStore(new StoreInfo({ - storageKey: testKey, type: new CountType(), exists: Exists.ShouldCreate, id: 'an-id'})); -} - describe('Store', async () => { - + let runtime; + let testKey: StorageKey; + async function createStore(): Promise> { + const info = new StoreInfo({storageKey: testKey, type: new CountType(), exists: Exists.ShouldCreate, id: 'an-id'}); + const endpoints = new DirectStorageEndpointManager(); + return endpoints.getActiveStore(info); + } beforeEach(() => { testKey = new MockStorageKey(); - Runtime.resetDrivers(); - }); - - after(() => { - Runtime.resetDrivers(); + runtime = new Runtime(); }); it(`will throw an exception if an appropriate driver can't be found`, async () => { @@ -51,7 +46,7 @@ describe('Store', async () => { }); it('will construct Direct stores when required', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -59,7 +54,7 @@ describe('Store', async () => { }); it('will propagate model updates from proxies to drivers', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -76,7 +71,7 @@ describe('Store', async () => { }); it('will apply and propagate operation updates from proxies to drivers', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -95,7 +90,7 @@ describe('Store', async () => { }); it('will respond to a model request from a proxy with a model', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -130,7 +125,7 @@ describe('Store', async () => { }); it('will only send a model response to the requesting proxy', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -151,7 +146,7 @@ describe('Store', async () => { }); it('will propagate updates from drivers to proxies', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -177,7 +172,7 @@ describe('Store', async () => { }); it('can clone data from another store', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); // Write some data. @@ -192,7 +187,7 @@ describe('Store', async () => { }); it(`won't send an update to the driver after driver-originated messages`, async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -208,7 +203,7 @@ describe('Store', async () => { }); it('will resend failed driver updates after merging', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); @@ -239,7 +234,7 @@ describe('Store', async () => { }); it('resolves a combination of messages from the proxy and the driver', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createStore(); const driver = activeStore['driver'] as MockDriver; let lastModel = null; diff --git a/src/runtime/storage/tests/direct-store-muxer-test.ts b/src/runtime/storage/tests/direct-store-muxer-test.ts index 71d5dd307b6..4ab8b9cdee7 100644 --- a/src/runtime/storage/tests/direct-store-muxer-test.ts +++ b/src/runtime/storage/tests/direct-store-muxer-test.ts @@ -33,8 +33,8 @@ let storageService: StorageService; describe('Direct Store Muxer', async () => { beforeEach(() => { - Runtime.resetDrivers(); - DriverFactory.register(new MockStorageDriverProvider()); + const runtime = new Runtime(); + DriverFactory.register(runtime, new MockStorageDriverProvider()); storageService = new DirectStorageEndpointManager(); }); @@ -46,7 +46,7 @@ describe('Direct Store Muxer', async () => { const id = await dsm.on(async msg => { assert.equal(ProxyMessageType.ModelUpdate, msg.type); assert.equal(id, msg.id); - resolve(); + resolve(null); }); }); @@ -69,7 +69,7 @@ describe('Direct Store Muxer', async () => { await dsm.on(async msg => { if (msg.type === ProxyMessageType.ModelUpdate) { assert.deepStrictEqual(msg.model, entityCRDT.getData()); - resolve(); + resolve(null); } }); }); @@ -77,7 +77,7 @@ describe('Direct Store Muxer', async () => { await dsm.on(async msg => { if (msg.type === ProxyMessageType.ModelUpdate) { assert.deepStrictEqual(msg.model, entityCRDT.getData()); - resolve(); + resolve(null); } }); }); diff --git a/src/runtime/storage/tests/firebase-store-integration-test.ts b/src/runtime/storage/tests/firebase-store-integration-test.ts index 1daae0bbdbd..f231681ce05 100644 --- a/src/runtime/storage/tests/firebase-store-integration-test.ts +++ b/src/runtime/storage/tests/firebase-store-integration-test.ts @@ -11,7 +11,6 @@ import {assert} from '../../../platform/chai-web.js'; import {ProxyMessageType} from '../store-interface.js'; import {CRDTCountTypeRecord, CRDTCount, CountOpTypes} from '../../../crdt/lib-crdt.js'; -import {DriverFactory} from '../drivers/driver-factory.js'; import {Exists} from '../drivers/driver.js'; import {Runtime} from '../../runtime.js'; import {MockFirebaseStorageDriverProvider, MockFirebaseStorageKey} from '../testing/mock-firebase.js'; @@ -22,20 +21,17 @@ import {ActiveStore} from '../active-store.js'; import {DirectStorageEndpointManager} from '../direct-storage-endpoint-manager.js'; async function createStore(storageKey: StorageKey, exists: Exists): Promise> { - return (await new DirectStorageEndpointManager().getActiveStore(new StoreInfo({ - storageKey, type: new CountType(), exists, id: 'an-id'}))) as ActiveStore; + const info = new StoreInfo({storageKey, type: new CountType(), exists, id: 'an-id'}); + const endpoints = new DirectStorageEndpointManager(); + const store = await endpoints.getActiveStore(info); + return store as ActiveStore; } -describe('Firebase + Store Integration', async () => { +describe('Firebase + Store Integration', async function() { let runtime; beforeEach(() => { - Runtime.resetDrivers(); runtime = new Runtime(); - MockFirebaseStorageDriverProvider.register(runtime.getCacheService()); - }); - - after(() => { - Runtime.resetDrivers(); + MockFirebaseStorageDriverProvider.register(runtime, runtime.getCacheService()); }); it('will store a sequence of model and operation updates as models', async () => { diff --git a/src/runtime/storage/tests/ramdisk-direct-store-muxer-integration-test.ts b/src/runtime/storage/tests/ramdisk-direct-store-muxer-integration-test.ts index 60421493155..d9feed5ff50 100644 --- a/src/runtime/storage/tests/ramdisk-direct-store-muxer-integration-test.ts +++ b/src/runtime/storage/tests/ramdisk-direct-store-muxer-integration-test.ts @@ -10,7 +10,7 @@ import {assert} from '../../../platform/chai-web.js'; import {ProxyMessageType, ProxyMessage} from '../store-interface.js'; -import {RamDiskStorageKey} from '../drivers/ramdisk.js'; +import {RamDiskStorageKey, RamDiskStorageDriverProvider} from '../drivers/ramdisk.js'; import {Exists} from '../drivers/driver.js'; import {Runtime} from '../../runtime.js'; import {DirectStoreMuxer} from '../direct-store-muxer.js'; @@ -29,10 +29,6 @@ function assertHasModel(message: ProxyMessage, model: CRDTEntity< } describe('RamDisk + Direct Store Muxer Integration', async () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('will allow storage of a number of objects', async () => { const manifest = await Manifest.parse(` schema Simple @@ -40,6 +36,8 @@ describe('RamDisk + Direct Store Muxer Integration', async () => { `); const simpleSchema = manifest.schemas.Simple; + const runtime = new Runtime(); + //RamDiskStorageDriverProvider.register(runtime.getMemoryProvider()); const storageKey = new RamDiskStorageKey('unique'); const type = new MuxType(new EntityType(simpleSchema)); const storeInfo = new StoreInfo>({ diff --git a/src/runtime/storage/tests/ramdisk-store-integration-test.ts b/src/runtime/storage/tests/ramdisk-store-integration-test.ts index 60b8b2f43a6..cc3af5148b1 100644 --- a/src/runtime/storage/tests/ramdisk-store-integration-test.ts +++ b/src/runtime/storage/tests/ramdisk-store-integration-test.ts @@ -11,7 +11,7 @@ import {assert} from '../../../platform/chai-web.js'; import {ProxyMessageType} from '../store-interface.js'; import {CRDTCountTypeRecord, CRDTCount, CountOpTypes} from '../../../crdt/lib-crdt.js'; -import {RamDiskStorageKey} from '../drivers/ramdisk.js'; +import {RamDiskStorageKey, RamDiskStorageDriverProvider} from '../drivers/ramdisk.js'; import {Exists} from '../drivers/driver.js'; import {Runtime} from '../../runtime.js'; import {CountType} from '../../../types/lib-types.js'; @@ -27,12 +27,9 @@ async function createStore(storageKey: StorageKey, exists: Exists): Promise { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('will store a sequence of model and operation updates as models', async () => { const runtime = new Runtime(); + //RamDiskStorageDriverProvider.register(runtime.getMemoryProvider()); const storageKey = new RamDiskStorageKey('unique'); const activeStore = await createStore(storageKey, Exists.ShouldCreate); @@ -54,6 +51,7 @@ describe('RamDisk + Store Integration', async () => { it('will store operation updates from multiple sources', async () => { const runtime = new Runtime(); + //RamDiskStorageDriverProvider.register(runtime.getMemoryProvider()); const storageKey = new RamDiskStorageKey('unique'); const activeStore1 = await createStore(storageKey, Exists.ShouldCreate); const activeStore2 = await createStore(storageKey, Exists.ShouldExist); @@ -91,6 +89,7 @@ describe('RamDisk + Store Integration', async () => { it('will store operation updates from multiple sources with some timing delays', async () => { // store1.onProxyMessage, DELAY, DELAY, DELAY, store1.onProxyMessage, store2.onProxyMessage, DELAY, DELAY, DELAY, store2.onProxyMessage, DELAY, DELAY, DELAY, DELAY, DELAY const runtime = new Runtime(); + //RamDiskStorageDriverProvider.register(runtime.getMemoryProvider()); const storageKey = new RamDiskStorageKey('unique'); const activeStore1 = await createStore(storageKey, Exists.ShouldCreate); const activeStore2 = await createStore(storageKey, Exists.ShouldExist); diff --git a/src/runtime/storage/tests/reference-mode-store-integration-test.ts b/src/runtime/storage/tests/reference-mode-store-integration-test.ts index c4452332c85..b8b57072506 100644 --- a/src/runtime/storage/tests/reference-mode-store-integration-test.ts +++ b/src/runtime/storage/tests/reference-mode-store-integration-test.ts @@ -25,28 +25,23 @@ import {Referenceable} from '../../../crdt/lib-crdt.js'; describe('ReferenceModeStore Integration', async () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('will store and retrieve entities through referenceModeStores (separate stores)', async () => { const storageKey = new ReferenceModeStorageKey(new RamDiskStorageKey('backing'), new RamDiskStorageKey('container')); - const type = new EntityType(new Schema(['AnEntity'], {foo: 'Text'})).collectionOf(); // Use newHandle here rather than setting up a store inside the arc, as this ensures writeHandle and readHandle // are on top of different storage stacks. - const writeHandle = await newHandle(new StoreInfo({storageKey, type, id: 'write-handle'}), - new Runtime().newArc('testWritesArc')); - const readHandle = await newHandle(new StoreInfo({storageKey, type, id: 'read-handle'}), - new Runtime().newArc('testReadArc')); + const writeInfo = new StoreInfo({storageKey, type, id: 'write-handle'}); + const writeHandle = await newHandle(writeInfo, new Runtime().newArc('testWritesArc')); + + const readInfo = new StoreInfo({storageKey, type, id: 'read-handle'}); + const readHandle = await newHandle(readInfo, new Runtime().newArc('testReadArc')); readHandle.particle = new Particle(); const returnPromise = new Promise((resolve, reject) => { - let state = 0; - readHandle.particle['onHandleSync'] = async (handle, model) => { + console.warn('onHandleSync', model); if (state === 0) { assert.deepEqual(model, []); state = 1; @@ -56,9 +51,9 @@ describe('ReferenceModeStore Integration', async () => { resolve(); } }; - }); + console.warn('writeHandle.addFromData'); await writeHandle.addFromData({foo: 'This is text in foo'}); return returnPromise; }); diff --git a/src/runtime/storage/tests/reference-mode-store-test.ts b/src/runtime/storage/tests/reference-mode-store-test.ts index 5ebad5177cf..ca3f56f4d71 100644 --- a/src/runtime/storage/tests/reference-mode-store-test.ts +++ b/src/runtime/storage/tests/reference-mode-store-test.ts @@ -87,18 +87,16 @@ function myEntityToMyEntityModel(entity: MyEntity, actor: string): MyEntityModel describe('Reference Mode Store', async () => { + let runtime; + beforeEach(() => { + runtime = new Runtime(); testKey = new ReferenceModeStorageKey(new MockHierarchicalStorageKey(), new MockHierarchicalStorageKey()); storeInfo = new StoreInfo({ storageKey: testKey, type: collectionType, exists: Exists.ShouldCreate, id: 'base-store-id'}); - Runtime.resetDrivers(); storageService = new DirectStorageEndpointManager(); }); - after(() => { - Runtime.resetDrivers(); - }); - it(`will throw an exception if an appropriate driver can't be found`, async () => { const type = new SingletonType(new CountType()); try { @@ -111,7 +109,7 @@ describe('Reference Mode Store', async () => { }); it('will construct ReferenceMode stores when required', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const type = new SingletonType(new CountType()); const activeStore = await storageService.getActiveStore((new StoreInfo({ @@ -120,7 +118,7 @@ describe('Reference Mode Store', async () => { }); it('will propagate model updates from proxies to drivers', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -151,7 +149,7 @@ describe('Reference Mode Store', async () => { }); it('can clone data from another store', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -172,7 +170,7 @@ describe('Reference Mode Store', async () => { }); it('will apply and propagate operation updates from proxies to drivers', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -202,7 +200,7 @@ describe('Reference Mode Store', async () => { }); it('clear entity in the backing store when they are removed from a collection', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -241,7 +239,7 @@ describe('Reference Mode Store', async () => { }); it('will respond to a model request from a proxy with a model', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -280,7 +278,7 @@ describe('Reference Mode Store', async () => { }); it('will only send a model response to the requesting proxy', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -301,7 +299,7 @@ describe('Reference Mode Store', async () => { }); it('will propagate updates from drivers to proxies', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -339,7 +337,7 @@ describe('Reference Mode Store', async () => { // TODO: this test can be enabled when we output operations from collection model merges it.skip(`won't send an update to the driver after driver-originated messages`, async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -356,7 +354,7 @@ describe('Reference Mode Store', async () => { }); it('will resend failed driver updates after merging', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -399,7 +397,7 @@ describe('Reference Mode Store', async () => { }); it('resolves a combination of messages from the proxy and the driver', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); @@ -440,7 +438,7 @@ describe('Reference Mode Store', async () => { }); it('holds onto a container update until the relevant backing data arrives', async () => { - DriverFactory.register(new MockStorageDriverProvider()); + DriverFactory.register(runtime, new MockStorageDriverProvider()); const activeStore = await createReferenceModeStore(); diff --git a/src/runtime/storage/tests/storage-key-test.ts b/src/runtime/storage/tests/storage-key-test.ts index a2fdff9b8a4..bf7db3640fe 100644 --- a/src/runtime/storage/tests/storage-key-test.ts +++ b/src/runtime/storage/tests/storage-key-test.ts @@ -21,11 +21,7 @@ describe('StorageKey', () => { beforeEach(() => { const runtime = new Runtime(); - FirebaseStorageDriverProvider.register(runtime.getCacheService(), mockFirebaseStorageKeyOptions); - }); - - afterEach(() => { - Runtime.resetDrivers(); + FirebaseStorageDriverProvider.register(runtime, runtime.getCacheService(), mockFirebaseStorageKeyOptions); }); it('can round-trip VolatileStorageKey', () => { diff --git a/src/runtime/storage/tests/store-sequence-test.ts b/src/runtime/storage/tests/store-sequence-test.ts index cca6cf3f354..924fd9d43ef 100644 --- a/src/runtime/storage/tests/store-sequence-test.ts +++ b/src/runtime/storage/tests/store-sequence-test.ts @@ -62,9 +62,8 @@ describe('Store Sequence', async () => { it('services a model request and applies 2 models', async () => { const sequenceTest = new SequenceTest>(); sequenceTest.setTestConstructor(async () => { - Runtime.resetDrivers(); - DriverFactory.register(new MockStorageDriverProvider()); - + const runtime = new Runtime(); + DriverFactory.register(runtime, new MockStorageDriverProvider()); return createStore(testKey, Exists.ShouldCreate); }); @@ -127,9 +126,8 @@ describe('Store Sequence', async () => { const sequenceTest = new SequenceTest>(); sequenceTest.setTestConstructor(async () => { - Runtime.resetDrivers(); - DriverFactory.register(new MockStorageDriverProvider()); - + const runtime = new Runtime(); + DriverFactory.register(runtime, new MockStorageDriverProvider()); return createStore(testKey, Exists.ShouldCreate); }); @@ -178,8 +176,7 @@ describe('Store Sequence', async () => { sequenceTest.setTestConstructor(async () => { const runtime = new Runtime(); const arc = runtime.newArc('arc', null); - Runtime.resetDrivers(); - VolatileStorageDriverProvider.register(arc); + VolatileStorageDriverProvider.register(runtime, arc); const storageKey = new VolatileStorageKey(arc.id, 'unique'); const activeStore1 = await createStore(storageKey, Exists.ShouldCreate); const activeStore2 = await createStore(storageKey, Exists.ShouldExist); @@ -228,8 +225,7 @@ describe('Store Sequence', async () => { const sequenceTest = new SequenceTest(); sequenceTest.setTestConstructor(async () => { const runtime = new Runtime(); - Runtime.resetDrivers(); - MockFirebaseStorageDriverProvider.register(runtime.getCacheService()); + MockFirebaseStorageDriverProvider.register(runtime, runtime.getCacheService()); const storageKey = new FirebaseStorageKey('test', 'test.domain', 'testKey', 'foo'); const activeStore1 = await createStore(storageKey, Exists.ShouldCreate); const activeStore2 = await createStore(storageKey, Exists.ShouldExist); @@ -278,8 +274,7 @@ describe('Store Sequence', async () => { sequenceTest.setTestConstructor(async () => { const runtime = new Runtime(); const arc = runtime.newArc('arc', id => new VolatileStorageKey(id, '')); - Runtime.resetDrivers(); - VolatileStorageDriverProvider.register(arc); + VolatileStorageDriverProvider.register(runtime, arc); const storageKey = new VolatileStorageKey(arc.id, 'unique'); const activeStore1 = await createStore(storageKey, Exists.ShouldCreate); const activeStore2 = await createStore(storageKey, Exists.ShouldExist); diff --git a/src/runtime/tests/arc-test.ts b/src/runtime/tests/arc-test.ts index 5d42beee3e7..262f9be7762 100644 --- a/src/runtime/tests/arc-test.ts +++ b/src/runtime/tests/arc-test.ts @@ -64,12 +64,7 @@ async function setup(storageKeyPrefix: (arcId: ArcId) => StorageKey) { } describe('Arc new storage', () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - - it('preserves data when round-tripping through serialization', async () => { - Runtime.resetDrivers(); + it('FLOOB preserves data when round-tripping through serialization', async () => { // TODO(shans): deserialization currently uses a RamDisk store to deserialize into because we don't differentiate // between parsing a manifest for public consumption (e.g. with RamDisk resources in it) and parsing a serialized // arc (with an @activeRecipe). We'll fix this by adding a 'private' keyword to store serializations which will @@ -98,18 +93,18 @@ describe('Arc new storage', () => { defineParticle(({Particle}) => class Noop extends Particle {}); ` }); + const runtime = new Runtime({loader}); - const manifest = await runtime.parseFile('./manifest'); - const dataClass = Entity.createEntityClass(manifest.findSchemaByName('Data'), null); - const id = ArcId.fromString('test'); - const storageKey = new VolatileStorageKey(id, 'unique'); - const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({id, storageKey, loader, context: manifest, storageService}); + runtime.context = await runtime.parseFile('./manifest'); + + const opts = runtime.buildArcParams('test'); + const arc = new Arc(opts); + const dataClass = Entity.createEntityClass(runtime.context.findSchemaByName('Data'), null); const varStore = await arc.createStore(new SingletonType(dataClass.type), undefined, 'test:0'); - const colStore = await arc.createStore(dataClass.type.collectionOf(), undefined, 'test:1'); + const colStore = await arc.createStore(dataClass.type.collectionOf(), undefined, 'test:1'); - const refVarKey = new ReferenceModeStorageKey(new VolatileStorageKey(id, 'colVar'), new VolatileStorageKey(id, 'refVar')); + const refVarKey = new ReferenceModeStorageKey(new VolatileStorageKey(arc.id, 'colVar'), new VolatileStorageKey(arc.id, 'refVar')); const refVarStore = await arc.createStore(new SingletonType(dataClass.type), undefined, 'test:2', [], refVarKey); const varHandle = await handleForStoreInfo(varStore, arc); @@ -126,7 +121,7 @@ describe('Arc new storage', () => { await colHandle.add(d3); await refVarHandle.set(d4); - const recipe = manifest.recipes[0]; + const recipe = runtime.context.recipes[0]; recipe.handles[0].mapToStorage(varStore); recipe.handles[1].mapToStorage(colStore); recipe.handles[2].mapToStorage(refVarStore); @@ -135,13 +130,17 @@ describe('Arc new storage', () => { await arc.instantiate(recipe); const serialization = await arc.serialize(); + console.warn(serialization); arc.dispose(); await varHandle.clear(); await colHandle.clear(); await refVarHandle.clear(); - const arc2 = await Arc.deserialize({serialization, loader, fileName: '', context: manifest, storageService}); + const {context, storageService, driverFactory} = opts; + debugger; + const arc2 = await Arc.deserialize({fileName: '', serialization, loader, context, storageService, driverFactory}); + debugger; const varStore2 = arc2.findStoreById(varStore.id) as StoreInfo; const colStore2 = arc2.findStoreById(colStore.id) as StoreInfo; const refVarStore2 = arc2.findStoreById(refVarStore.id) as StoreInfo; @@ -198,10 +197,6 @@ describe('Arc new storage', () => { const doSetup = async () => setup(arcId => new VolatileStorageKey(arcId, '')); describe('Arc', () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('idle can safely be called multiple times ', async () => { const runtime = new Runtime(); const arc = runtime.newArc('test'); @@ -242,8 +237,8 @@ describe('Arc', () => { }); it('optional provided handles do not resolve without parent', async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + const manifest = await runtime.parse(` schema Thing value: Text @@ -262,12 +257,13 @@ describe('Arc', () => { TestParticle a: reads thingA b: writes thingB - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `, {fileName: process.cwd() + '/input.manifest'}); const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService, driverFactory}); const thingClass = Entity.createEntityClass(manifest.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -360,8 +356,8 @@ describe('Arc', () => { }); it('required provided handles do not resolve without parent', async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + const manifest = await runtime.parse(` schema Thing value: Text @@ -380,12 +376,13 @@ describe('Arc', () => { TestParticle a: reads thingA b: writes thingB - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `, {fileName: process.cwd() + '/input.manifest'}); const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService, driverFactory}); const thingClass = Entity.createEntityClass(manifest.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -414,8 +411,8 @@ describe('Arc', () => { it('optional provided handles cannot resolve without parent', async () => { await assertThrowsAsync(async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + const manifest = await runtime.parse(` schema Thing value: Text @@ -435,11 +432,12 @@ describe('Arc', () => { a: reads thingA b: writes thingB d: writes maybeThingD - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `, {fileName: process.cwd() + '/input.manifest'}); const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService, driverFactory}); const thingClass = Entity.createEntityClass(manifest.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -486,9 +484,9 @@ describe('Arc', () => { const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const loader = runtime.loader; const slotComposer = new SlotComposer(); - const arc = new Arc({loader, context, id, storageKey, storageService, slotComposer}); + const {loader, driverFactory} = runtime; + const arc = new Arc({loader, context, id, storageKey, storageService, slotComposer, driverFactory}); const thingClass = Entity.createEntityClass(context.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -508,8 +506,8 @@ describe('Arc', () => { }); it('optional provided handles are not required to resolve with dependencies', async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + const manifest = await runtime.parse(` schema Thing value: Text @@ -529,11 +527,12 @@ describe('Arc', () => { a: reads thingA b: writes thingB c: reads maybeThingC - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `, {fileName: process.cwd() + '/input.manifest'}); const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService, driverFactory}); const thingClass = Entity.createEntityClass(manifest.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -564,8 +563,8 @@ describe('Arc', () => { it('required provided handles must resolve with dependencies', async () => { await assertThrowsAsync(async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + const manifest = await runtime.parse(` schema Thing value: Text @@ -585,11 +584,12 @@ describe('Arc', () => { a: reads thingA b: writes thingB c: reads maybeThingC - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `, {fileName: process.cwd() + '/input.manifest'}); const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService, driverFactory}); const thingClass = Entity.createEntityClass(manifest.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -609,8 +609,8 @@ describe('Arc', () => { }); it('optional provided handles can resolve with parent 1', async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + const manifest = await runtime.parse(` schema Thing value: Text @@ -631,11 +631,12 @@ describe('Arc', () => { b: writes thingB c: reads maybeThingC d: writes maybeThingD - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `, {fileName: process.cwd() + '/input.manifest'}); const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService, driverFactory}); const thingClass = Entity.createEntityClass(manifest.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -663,8 +664,8 @@ describe('Arc', () => { }); it('required provided handles can resolve with parent 2', async () => { - const loader = new Loader(); - const manifest = await Manifest.parse(` + const runtime = new Runtime(); + const manifest = await runtime.parse(` schema Thing value: Text @@ -685,11 +686,12 @@ describe('Arc', () => { b: writes thingB c: reads maybeThingC d: writes maybeThingD - `, {loader, fileName: process.cwd() + '/input.manifest'}); + `, {fileName: process.cwd() + '/input.manifest'}); const id = ArcId.newForTest('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer: new SlotComposer(), loader, context: manifest, id, storageKey, storageService, driverFactory}); const thingClass = Entity.createEntityClass(manifest.findSchemaByName('Thing'), null); const aStore = await arc.createStore(new SingletonType(thingClass.type), 'aStore', 'test:1'); @@ -717,19 +719,20 @@ describe('Arc', () => { }); it('deserializing a serialized empty arc produces an empty arc', async () => { + const runtime = new Runtime(); const slotComposer = new SlotComposer(); - const loader = new Loader(); const id = Id.fromString('test'); const storageKey = new VolatileStorageKey(id, ''); const context = new Manifest({id}); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({slotComposer, loader, id, storageKey, context, storageService}); + const {loader, driverFactory} = runtime; + const arc = new Arc({slotComposer, loader, context, id, storageKey, storageService, driverFactory}); await arc.idle; const serialization = await arc.serialize(); arc.dispose(); - const newArc = await Arc.deserialize({serialization, loader, slotComposer, context, fileName: 'foo.manifest', storageService}); + const newArc = await Arc.deserialize({serialization, loader, slotComposer, context, fileName: 'foo.manifest', storageService, driverFactory}); await newArc.idle; assert.strictEqual(newArc.stores.length, 0); assert.strictEqual(newArc.activeRecipe.toString(), `@active\n${arc.activeRecipe.toString()}`); @@ -738,7 +741,7 @@ describe('Arc', () => { }); it('deserializing a simple serialized arc produces that arc', async () => { - const {arc, context, recipe, Foo, Bar, loader} = await doSetup(); + const {arc, context, recipe, Foo, Bar, loader} = await doSetup(); let fooStore = await arc.createStore(new SingletonType(Foo.type), undefined, 'test:1'); const fooHandle = await handleForStoreInfo(fooStore, arc); const fooStoreCallbacks = CallbackTracker.create(await arc.getActiveStore(fooStore), 1); @@ -758,8 +761,8 @@ describe('Arc', () => { const serialization = await arc.serialize(); arc.dispose(); - const storageService = arc.storageService; - const newArc = await Arc.deserialize({serialization, loader, fileName: '', slotComposer: new SlotComposer(), context, storageService}); + const {driverFactory, storageService} = arc; + const newArc = await Arc.deserialize({serialization, loader, fileName: '', slotComposer: new SlotComposer(), context, storageService, driverFactory}); await newArc.idle; fooStore = newArc.findStoreById(fooStore.id) as StoreInfo; barStore = newArc.findStoreById(barStore.id) as StoreInfo; @@ -787,11 +790,13 @@ describe('Arc', () => { '*': 'defineParticle(({Particle}) => class extends Particle {});', }); - const manifest = await Manifest.load('./manifest', loader); + const runtime = new Runtime({loader}); + const manifest = await runtime.parseFile('./manifest'); + const {driverFactory} = runtime; const id = Id.fromString('test'); const storageKey = new VolatileStorageKey(id, ''); const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({id, storageKey, loader, context: manifest, storageService}); + const arc = new Arc({id, storageKey, loader, context: manifest, storageService, driverFactory}); const recipe = manifest.recipes[0]; assert(recipe.normalize()); assert(recipe.isResolved()); @@ -821,22 +826,23 @@ describe('Arc', () => { const storageKey1 = new VolatileStorageKey(id1, ''); const storageKey2 = new VolatileStorageKey(id2, ''); - Runtime.resetDrivers(); // runtime creates a default RamDisk with SimpleVolatileMemoryProvider - assert.equal(DriverFactory.providers.size, 1); + const runtime = new Runtime(); + const {driverFactory} = runtime; + assert.equal(driverFactory.providers.size, 1); const storageService = new DirectStorageEndpointManager(); - const arc1 = new Arc({id: id1, storageKey: storageKey1, loader: new Loader(), context: new Manifest({id: id1}), storageService}); - assert.strictEqual(DriverFactory.providers.size, 2); + const arc1 = new Arc({id: id1, storageKey: storageKey1, loader: new Loader(), context: new Manifest({id: id1}), storageService, driverFactory}); + assert.strictEqual(driverFactory.providers.size, 2); - const arc2 = new Arc({id: id2, storageKey: storageKey2, loader: new Loader(), context: new Manifest({id: id2}), storageService}); - assert.strictEqual(DriverFactory.providers.size, 3); + const arc2 = new Arc({id: id2, storageKey: storageKey2, loader: new Loader(), context: new Manifest({id: id2}), storageService, driverFactory}); + assert.strictEqual(driverFactory.providers.size, 3); arc1.dispose(); - assert.strictEqual(DriverFactory.providers.size, 2); + assert.strictEqual(driverFactory.providers.size, 2); arc2.dispose(); - assert.equal(DriverFactory.providers.size, 1); + assert.equal(driverFactory.providers.size, 1); }); it('preserves create handle ids if specified', Flags.withDefaultReferenceMode(async () => { diff --git a/src/runtime/tests/capabilities-resolver-test.ts b/src/runtime/tests/capabilities-resolver-test.ts index 917e308bce0..baffcf275ac 100644 --- a/src/runtime/tests/capabilities-resolver-test.ts +++ b/src/runtime/tests/capabilities-resolver-test.ts @@ -10,22 +10,23 @@ import {assert} from '../../platform/chai-web.js'; import {Flags} from '../flags.js'; import {VolatileStorageKey} from '../storage/drivers/volatile.js'; -import {RamDiskStorageKey, RamDiskStorageDriverProvider} from '../storage/drivers/ramdisk.js'; +import {RamDiskStorageKey} from '../storage/drivers/ramdisk.js'; import {DatabaseStorageKey, MemoryDatabaseStorageKey, PersistentDatabaseStorageKey, MemoryDatabaseStorageKeyFactory} from '../storage/database-storage-key.js'; import {StorageKey} from '../storage/storage-key.js'; import {ReferenceModeStorageKey} from '../storage/reference-mode-storage-key.js'; import {EntityType, ReferenceType, Schema} from '../../types/lib-types.js'; -import {CapabilitiesResolver} from '../capabilities-resolver.js'; +import {_CapabilitiesResolver} from '../capabilities-resolver.js'; import {ArcId} from '../id.js'; import {Capabilities, Persistence, Ttl, Shareable, DeletePropagation} from '../capabilities.js'; import {assertThrowsAsync} from '../../testing/test-util.js'; import {Runtime} from '../runtime.js'; import {Manifest} from '../manifest.js'; -import {TestVolatileMemoryProvider} from '../testing/test-volatile-memory-provider.js'; describe('Capabilities Resolver New', () => { - afterEach(() => { - Runtime.resetDrivers(); + + let runtime; + beforeEach(() => { + runtime = new Runtime(); }); type StorageKeyType = typeof VolatileStorageKey|typeof RamDiskStorageKey|typeof DatabaseStorageKey; @@ -38,7 +39,7 @@ describe('Capabilities Resolver New', () => { `Expected ${refKey.storageKey.constructor.name} to be instance of ${expectedType.name}`); } const entityType = new EntityType(new Schema(['Thing'], {result: 'Text'})); - const referenceType = new ReferenceType(entityType); + //const referenceType = new ReferenceType(entityType); const handleId = 'h0'; const unspecified = Capabilities.fromAnnotations(); @@ -49,7 +50,7 @@ describe('Capabilities Resolver New', () => { const onDiskWithTtl = Capabilities.create([Persistence.onDisk(), Ttl.minutes(30)]); it('fails creating keys with no factories', Flags.withDefaultReferenceMode(async () => { - const resolver = new CapabilitiesResolver({arcId: ArcId.newForTest('test')}); + const resolver = new _CapabilitiesResolver({arcId: ArcId.newForTest('test')}); // Verify storage keys for none of the capabilities cannot be created. await assertThrowsAsync(async () => resolver.createStorageKey(unspecified, entityType, handleId)); await assertThrowsAsync(async () => resolver.createStorageKey(inMemory, entityType, handleId)); @@ -61,8 +62,7 @@ describe('Capabilities Resolver New', () => { it('creates volatile keys', Flags.withDefaultReferenceMode(async () => { // Register volatile storage key factory. // Verify only volatile (in-memory, no ttl) storage key can be created. - //VolatileStorageKey.register(); - const resolver = new CapabilitiesResolver({arcId: ArcId.newForTest('test')}); + const resolver = new _CapabilitiesResolver({arcId: ArcId.newForTest('test')}); const createKey = resolver.createStorageKey.bind(resolver); verifyReferenceModeStorageKey(await createKey(unspecified, entityType, handleId), VolatileStorageKey); verifyReferenceModeStorageKey(await createKey(inMemory, entityType, handleId), VolatileStorageKey); @@ -73,9 +73,9 @@ describe('Capabilities Resolver New', () => { })); it('creates keys with db only factories', Flags.withDefaultReferenceMode(async () => { - Runtime.resetDrivers(true); - DatabaseStorageKey.register(); - const resolver = new CapabilitiesResolver({arcId: ArcId.newForTest('test')}); + runtime.resetDrivers(); + DatabaseStorageKey.register(runtime); + const resolver = new _CapabilitiesResolver({arcId: ArcId.newForTest('test')}); const createKey = resolver.createStorageKey.bind(resolver); verifyReferenceModeStorageKey(await createKey(unspecified, entityType, handleId), MemoryDatabaseStorageKey); verifyReferenceModeStorageKey(await createKey(inMemory, entityType, handleId), MemoryDatabaseStorageKey); @@ -87,9 +87,8 @@ describe('Capabilities Resolver New', () => { it('creates keys with volatile and db factories', Flags.withDefaultReferenceMode(async () => { // Register database storage key factories. Verify all storage keys created as expected. - Runtime.resetDrivers(); - DatabaseStorageKey.register(); - const resolver = new CapabilitiesResolver({arcId: ArcId.newForTest('test')}); + DatabaseStorageKey.register(runtime); + const resolver = new _CapabilitiesResolver({arcId: ArcId.newForTest('test')}); const verify = async (a, b, c, d) => verifyReferenceModeStorageKey(await resolver.createStorageKey(a, b, c), d); await verify(unspecified, entityType, handleId, VolatileStorageKey); await verify(Capabilities.create([new Shareable(false)]), entityType, handleId, VolatileStorageKey); @@ -101,7 +100,7 @@ describe('Capabilities Resolver New', () => { })); it('creates keys with custom factory', Flags.withDefaultReferenceMode(async () => { - const resolver = new CapabilitiesResolver({arcId: ArcId.newForTest('test'), factories: [new MemoryDatabaseStorageKeyFactory()]}); + const resolver = new _CapabilitiesResolver({arcId: ArcId.newForTest('test'), factories: [new MemoryDatabaseStorageKeyFactory()]}); verifyReferenceModeStorageKey(await resolver.createStorageKey(unspecified, entityType, handleId), VolatileStorageKey); verifyReferenceModeStorageKey(await resolver.createStorageKey(inMemory, entityType, handleId), VolatileStorageKey); verifyReferenceModeStorageKey(await resolver.createStorageKey(inMemoryWithTtls, entityType, handleId), MemoryDatabaseStorageKey); @@ -110,7 +109,7 @@ describe('Capabilities Resolver New', () => { })); it('creates keys for recipe with volatile and db factories', Flags.withDefaultReferenceMode(async () => { - DatabaseStorageKey.register(); + DatabaseStorageKey.register(runtime); const manifestStr = ` recipe h0: create @@ -120,7 +119,7 @@ describe('Capabilities Resolver New', () => { h4: create @queryable @ttl('30m') `; const recipe = (await Manifest.parse(manifestStr)).recipes[0]; - const resolver = new CapabilitiesResolver({arcId: ArcId.newForTest('test')}); + const resolver = new _CapabilitiesResolver({arcId: ArcId.newForTest('test')}); verifyReferenceModeStorageKey(await resolver.createStorageKey( recipe.handles[0].capabilities, entityType, handleId), VolatileStorageKey); diff --git a/src/runtime/tests/description-test.ts b/src/runtime/tests/description-test.ts index 561d6afb1e7..929d20fb72b 100644 --- a/src/runtime/tests/description-test.ts +++ b/src/runtime/tests/description-test.ts @@ -594,7 +594,8 @@ recipe }); it('capitalizes when some particles do not have descriptions', async () => { - const manifest = (await Manifest.parse(` + const runtime = new Runtime(); + const manifest = (await runtime.parse(` interface DummyInterface particle NoDescription particle NoDescMuxer @@ -616,10 +617,11 @@ recipe myslot: consumes slot1 `)); const recipe = manifest.recipes[0]; + //const storageService = new DirectStorageEndpointManager(); + const {storageService, driverFactory} = runtime; // Cannot use createTestArc here, because capabilities-resolver cannot be set to null, // and interface returns a null schema, and cannot generate hash. - const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({id: ArcId.newForTest('test'), context: manifest, loader: new Loader(), storageService}); + const arc = new Arc({id: ArcId.newForTest('test'), context: manifest, loader: new Loader(), storageService, driverFactory}); arc['_activeRecipe'] = recipe; arc['_recipeDeltas'].push({particles: recipe.particles, handles: recipe.handles, slots: recipe.slots, patterns: recipe.patterns}); diff --git a/src/runtime/tests/manifest-test.ts b/src/runtime/tests/manifest-test.ts index bf0d6c262d0..99f58066c17 100644 --- a/src/runtime/tests/manifest-test.ts +++ b/src/runtime/tests/manifest-test.ts @@ -12,7 +12,7 @@ import {parse} from '../../gen/runtime/manifest-parser.js'; import {assert} from '../../platform/chai-web.js'; import {fs} from '../../platform/fs-web.js'; import {path} from '../../platform/path-web.js'; -import {Manifest, ManifestParseOptions, ErrorSeverity} from '../manifest.js'; +import {Manifest, ErrorSeverity} from '../manifest.js'; import {checkDefined, checkNotNull} from '../testing/preconditions.js'; import {Loader} from '../../platform/loader.js'; import {Dictionary} from '../../utils/lib-utils.js'; @@ -22,17 +22,15 @@ import {ClaimType} from '../arcs-types/enums.js'; import {CheckHasTag, CheckBooleanExpression, CheckCondition, CheckIsFromStore, CheckImplication} from '../arcs-types/check.js'; import {ProvideSlotConnectionSpec, ParticleDataflowType} from '../arcs-types/particle-spec.js'; import {Entity} from '../entity.js'; -import {RamDiskStorageDriverProvider, RamDiskStorageKey} from '../storage/drivers/ramdisk.js'; +import {RamDiskStorageKey} from '../storage/drivers/ramdisk.js'; import {digest} from '../../platform/digest-web.js'; -import {DriverFactory} from '../storage/drivers/driver-factory.js'; -import {TestVolatileMemoryProvider} from '../testing/test-volatile-memory-provider.js'; import {FirebaseStorageDriverProvider} from '../storage/drivers/firebase.js'; import {Runtime} from '../runtime.js'; import {mockFirebaseStorageKeyOptions} from '../storage/testing/mock-firebase.js'; import {Flags} from '../flags.js'; import {TupleType, CollectionType, EntityType, TypeVariable, Schema, BinaryExpression, FieldNamePrimitive, NumberPrimitive, PrimitiveField} from '../../types/lib-types.js'; -import {ActiveCollectionEntityStore, handleForStoreInfo, CollectionEntityType} from '../storage/storage.js'; +import {handleForStoreInfo, CollectionEntityType} from '../storage/storage.js'; import {Ttl} from '../capabilities.js'; import {StoreInfo} from '../storage/store-info.js'; import {deleteFieldRecursively} from '../../utils/lib-utils.js'; @@ -50,13 +48,11 @@ describe('manifest', async () => { let runtime; let storageService; beforeEach(() => { - Runtime.resetDrivers(); runtime = new Runtime(); storageService = new DirectStorageEndpointManager(); }); afterEach(() => { - Runtime.resetDrivers(); }); it('can parse a manifest containing a recipe', async () => { @@ -2799,9 +2795,7 @@ resource SomeName }); it('can parse a manifest with storage key handle definitions', async () => { - FirebaseStorageDriverProvider.register( - new Runtime().getCacheService(), - mockFirebaseStorageKeyOptions); + FirebaseStorageDriverProvider.register(runtime, runtime.getCacheService(), mockFirebaseStorageKeyOptions); const manifest = await runtime.parse(` schema Bar value: Text @@ -4465,13 +4459,6 @@ describe('annotations', async () => { '*': '{"root": {}, "locations": {}}' }); const runtime = new Runtime(); - beforeEach(() => { - Runtime.resetDrivers(); - }); - afterEach(() => { - Runtime.resetDrivers(); - }); - it('parses annotations', async () => { const annotationsStr = ` annotation noParam diff --git a/src/runtime/tests/particle-api-test.ts b/src/runtime/tests/particle-api-test.ts index 0b47fe11be4..6d0d58919ea 100644 --- a/src/runtime/tests/particle-api-test.ts +++ b/src/runtime/tests/particle-api-test.ts @@ -350,7 +350,7 @@ describe('particle-api', () => { // TODO(cypher1): Disabling this for now. The resolution seems to depend on order. // It is likely that this usage was depending on behavior that may not be intended. it.skip('can load a recipe referencing a manifest store', async () => { - RamDiskStorageDriverProvider.register(new TestVolatileMemoryProvider()); + //RamDiskStorageDriverProvider.register(new TestVolatileMemoryProvider()); const arc = await loadFilesIntoNewArc({ manifest: ` diff --git a/src/runtime/tests/particle-interface-loading-test.ts b/src/runtime/tests/particle-interface-loading-test.ts index 3d37c6861e3..660f2fdad05 100644 --- a/src/runtime/tests/particle-interface-loading-test.ts +++ b/src/runtime/tests/particle-interface-loading-test.ts @@ -68,11 +68,13 @@ describe('particle interface loading', () => { } } }; - });`}); - - const manifest = await Manifest.load('./src/runtime/tests/artifacts/test-particles.manifest', loader); - const storageService = new DirectStorageEndpointManager(); - const arc = new Arc({id: ArcId.newForTest('test'), loader, context: manifest, storageService}); + });` + }); + const runtime = new Runtime({loader}); + const manifest = await runtime.parseFile('./src/runtime/tests/artifacts/test-particles.manifest'); + //const storageService = new DirectStorageEndpointManager(); + const {driverFactory, storageService} = runtime; + const arc = new Arc({id: ArcId.newForTest('test'), loader, context: manifest, storageService, driverFactory}); const fooType = new EntityType(manifest.schemas.Foo); const barType = new EntityType(manifest.schemas.Bar); @@ -293,8 +295,9 @@ describe('particle interface loading', () => { const serialization = await arc.serialize(); arc.dispose(); - const storageService = new DirectStorageEndpointManager(); - const arc2 = await Arc.deserialize({serialization, loader, fileName: '', context: manifest, storageService}); + //const storageService = new DirectStorageEndpointManager(); + const {driverFactory, storageService} = runtime; + const arc2 = await Arc.deserialize({serialization, loader, fileName: '', context: manifest, storageService, driverFactory}); await arc2.idle; const fooHandle2 = await handleForStoreInfo(arc2.stores.find(StoreInfo.isSingletonEntityStore), arc2); diff --git a/src/runtime/tests/runtime-test.ts b/src/runtime/tests/runtime-test.ts index 603cdf32f50..70694ec00c6 100644 --- a/src/runtime/tests/runtime-test.ts +++ b/src/runtime/tests/runtime-test.ts @@ -45,49 +45,46 @@ function assertManifestsEqual(actual: Manifest, expected: Manifest) { } describe('Runtime', () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('gets an arc description for an arc', async () => { - const storageService = new DirectStorageEndpointManager(); + const runtime = new Runtime(); + const {storageService, driverFactory} = runtime; + //const storageService = new DirectStorageEndpointManager(); const arc = new Arc({ slotComposer: new SlotComposer(), id: ArcId.newForTest('test'), loader: new Loader(), context: new Manifest({id: ArcId.newForTest('test')}), - storageService + storageService, + driverFactory }); const description = await Description.create(arc); const expected = await description.getArcDescription(); const actual = await Runtime.getArcDescription(arc); assert.strictEqual(expected, actual); }); - it('parses a Manifest', async () => { - const content = ` - schema Greeting - value: Text + // it('parses a Manifest', async () => { + // const content = ` + // schema Greeting + // value: Text - particle Hello in 'hello.js' - text: writes Greeting {value} + // particle Hello in 'hello.js' + // text: writes Greeting {value} - recipe - handleA: create * - Hello - text: writes handleA`; - const fileName = './src/runtime/tests/artifacts/test.manifest'; - const expected = await Manifest.parse(content, {fileName}); - const actual = await new Runtime().parse(content, {fileName}); - assertManifestsEqual(actual, expected); - }); - it('loads a Manifest', async () => { - const registry = {}; - const loader = new Loader(); - const path = './src/runtime/tests/artifacts/test.manifest'; - const expected = await Manifest.load(path, loader, {registry}); - const actual = await new Runtime().parseFile(path, {loader, registry}); - assertManifestsEqual(actual, expected); - }); + // recipe + // handleA: create * + // Hello + // text: writes handleA`; + // const expected = await Manifest.parse(content); + // const actual = await Runtime.parseManifest(content); + // assertManifestsEqual(actual, expected); + // }); + // it('loads a Manifest', async () => { + // const registry = {}; + // const loader = new Loader(); + // const expected = await Manifest.load('./src/runtime/tests/artifacts/test.manifest', loader, registry); + // const actual = await Runtime.loadManifest('./src/runtime/tests/artifacts/test.manifest', loader, registry); + // assertManifestsEqual(actual, expected); + // }); it('runs arcs', async () => { const runtime = new Runtime(); assert.equal(runtime.arcById.size, 0); diff --git a/src/runtime/tests/test-environment-test.ts b/src/runtime/tests/test-environment-test.ts index 86ef8a3fb23..a7469ad867e 100644 --- a/src/runtime/tests/test-environment-test.ts +++ b/src/runtime/tests/test-environment-test.ts @@ -24,5 +24,4 @@ afterEach(function() { // Error function not yet included in mocha typescript declarations... this.test['error'](exception); } - Runtime.resetDrivers(); }); diff --git a/src/tests/arc-integration-test.ts b/src/tests/arc-integration-test.ts index 6c161b2160c..980710fa700 100644 --- a/src/tests/arc-integration-test.ts +++ b/src/tests/arc-integration-test.ts @@ -17,10 +17,6 @@ import {TestVolatileMemoryProvider} from '../runtime/testing/test-volatile-memor import {storageKeyPrefixForTest} from '../runtime/testing/handle-for-test.js'; describe('Arc integration', () => { - afterEach(() => { - Runtime.resetDrivers(); - }); - it('copies store tags', async () => { const loader = new Loader(null, { './p.js': `defineParticle(({Particle}) => class P extends Particle { diff --git a/src/tests/particles/common-test.ts b/src/tests/particles/common-test.ts index 12299d350b4..873a3680d8e 100644 --- a/src/tests/particles/common-test.ts +++ b/src/tests/particles/common-test.ts @@ -20,9 +20,6 @@ import {handleForActiveStore, CollectionEntityType} from '../../runtime/storage/ import {StoreInfo} from '../../runtime/storage/store-info.js'; describe('common particles test', () => { - afterEach(() => { - Runtime.resetDrivers(); - }); it('resolves after cloning', async () => { const memoryProvider = new TestVolatileMemoryProvider(); const manifest = await Manifest.parse(` diff --git a/src/tests/particles/dataflow-test.ts b/src/tests/particles/dataflow-test.ts index 676bd3a7dd2..b0d0fdb3193 100644 --- a/src/tests/particles/dataflow-test.ts +++ b/src/tests/particles/dataflow-test.ts @@ -27,5 +27,4 @@ describe('Dataflow example recipes', () => { } }); } - Runtime.resetDrivers(); }); diff --git a/src/tests/particles/particles-test.ts b/src/tests/particles/particles-test.ts index 3c443e673d4..9b352735ab7 100644 --- a/src/tests/particles/particles-test.ts +++ b/src/tests/particles/particles-test.ts @@ -19,14 +19,6 @@ describe('Particle definitions', () => { const runtime = new Runtime(); const filenames = glob.sync('particles/**/*.arcs'); - beforeEach(() => { - Runtime.resetDrivers(); - }); - - afterEach(() => { - Runtime.resetDrivers(); - }); - filenames .forEach(filename => { // skip experimental Native partices for now as they need a heavyweight build step diff --git a/src/tests/recipe-descriptions-test.ts b/src/tests/recipe-descriptions-test.ts index d152d616fd5..f7bae1eab56 100644 --- a/src/tests/recipe-descriptions-test.ts +++ b/src/tests/recipe-descriptions-test.ts @@ -10,16 +10,12 @@ import {assert} from '../platform/chai-web.js'; import {Loader} from '../platform/loader.js'; -import {Manifest} from '../runtime/manifest.js'; import {Runtime} from '../runtime/runtime.js'; import {StrategyTestHelper} from '../planning/testing/strategy-test-helper.js'; -import {TestVolatileMemoryProvider} from '../runtime/testing/test-volatile-memory-provider.js'; -import {RamDiskStorageDriverProvider} from '../runtime/storage/drivers/ramdisk.js'; import {VolatileStorageKey} from '../runtime/storage/drivers/volatile.js'; import {ArcId} from '../runtime/id.js'; import {storageKeyPrefixForTest} from '../runtime/testing/handle-for-test.js'; import {newRecipe} from '../runtime/recipe/lib-recipe.js'; -import {DriverFactory} from '../runtime/storage/drivers/driver-factory.js'; describe('recipe descriptions test', () => { // Avoid initialising non-POD variables globally, since they would be constructed even when @@ -35,11 +31,6 @@ describe('recipe descriptions test', () => { }); }); - afterEach(() => { - Runtime.resetDrivers(); - }); - - function createManifestString(options) { options = options || {}; diff --git a/src/tools/allocator-recipe-resolver.ts b/src/tools/allocator-recipe-resolver.ts index 5e1b3c242e3..3dc32a4de34 100644 --- a/src/tools/allocator-recipe-resolver.ts +++ b/src/tools/allocator-recipe-resolver.ts @@ -13,7 +13,7 @@ import {Runtime} from '../runtime/runtime.js'; import {Manifest} from '../runtime/manifest.js'; import {Type} from '../types/lib-types.js'; import {Recipe, RecipeComponent} from '../runtime/recipe/lib-recipe.js'; -import {CapabilitiesResolver} from '../runtime/capabilities-resolver.js'; +import {_CapabilitiesResolver} from '../runtime/capabilities-resolver.js'; import {IngressValidation} from '../runtime/policy/ingress-validation.js'; import {CreatableStorageKey} from '../runtime/storage/creatable-storage-key.js'; import {DatabaseStorageKey} from '../runtime/storage/database-storage-key.js'; @@ -43,7 +43,7 @@ export class AllocatorRecipeResolver { constructor(context: Manifest, private randomSalt: string, policiesManifest?: Manifest|null) { this.runtime = new Runtime({context}); - DatabaseStorageKey.register(); + DatabaseStorageKey.register(this.runtime); this.ingressValidation = policiesManifest ? new IngressValidation(policiesManifest.policies) : null; } @@ -78,7 +78,7 @@ export class AllocatorRecipeResolver { const handleById: {[index: string]: ({handles: Handle[], store?: StoreInfo})} = {}; // Find all `create` handles of long running recipes. for (const recipe of recipes.filter(r => isLongRunning(r))) { - const resolver = new CapabilitiesResolver({arcId: Id.fromString(findLongRunningArcId(recipe))}); + const resolver = new _CapabilitiesResolver({arcId: Id.fromString(findLongRunningArcId(recipe))}); for (const createHandle of recipe.handles.filter(h => h.fate === 'create' && h.id)) { if (handleById[createHandle.id]) { throw new AllocatorRecipeResolverError(` @@ -200,7 +200,7 @@ export class AllocatorRecipeResolver { if (isLongRunning(handle.recipe) && handle.id) { assert(!handle.storageKey); // store's storage key was set, but not the handle's const arcId = Id.fromString(findLongRunningArcId(handle.recipe)); - const resolver = new CapabilitiesResolver({arcId}); + const resolver = new _CapabilitiesResolver({arcId}); assert(handle.type.isResolved()); if (handle.type.getEntitySchema() === null) { throw new AllocatorRecipeResolverError(`Handle '${handle.id}' was not properly resolved.`); diff --git a/src/tools/tests/allocator-recipe-resolver-test.ts b/src/tools/tests/allocator-recipe-resolver-test.ts index 75f403159e5..dae151b84b6 100644 --- a/src/tools/tests/allocator-recipe-resolver-test.ts +++ b/src/tools/tests/allocator-recipe-resolver-test.ts @@ -28,7 +28,6 @@ import {FieldPathError} from '../../runtime/field-path.js'; const randomSalt = 'random_salt'; describe('allocator recipe resolver', () => { - afterEach(() => Runtime.resetDrivers()); it('detects long running arc', async () => { const manifest = (await Manifest.parse(` recipe Zero @@ -645,7 +644,6 @@ describe('allocator recipe resolver', () => { }); }); describe('allocator recipe resolver - ingress restricting', () => { - afterEach(() => Runtime.resetDrivers()); const particleSpec = ` particle Writer thing: writes Thing {a: Text, b: Text, c: Text, d: Text, e: Text} @@ -744,7 +742,6 @@ particle ReaderB const recipes = await resolver.resolve(); const writingRecipe = recipes.find(recipe => recipe.name === 'WritingRecipe'); assert.equal(writingRecipe.handles[0].type.resolvedType().toString(), expectedSchema); - Runtime.resetDrivers(); }; const verifyWritingRecipe = async (manifestStr: string, expectedSchema: string) => { diff --git a/src/tools/tests/codegen-unit-test-base.ts b/src/tools/tests/codegen-unit-test-base.ts index 7fe53675fc0..a4c738b4199 100644 --- a/src/tools/tests/codegen-unit-test-base.ts +++ b/src/tools/tests/codegen-unit-test-base.ts @@ -95,7 +95,6 @@ export abstract class ManifestCodegenUnitTest extends CodegenUnitTest { */ export async function runCompute(testCase: CodegenUnitTest, test: Test): Promise { Flags.reset(); - Runtime.resetDrivers(); const result = await testCase.compute(test.input, test.options, test); return Array.isArray(result) ? result : [result]; } diff --git a/src/tools/tests/recipe2plan-test.ts b/src/tools/tests/recipe2plan-test.ts index 75a8ab9846f..244ed886fe8 100644 --- a/src/tools/tests/recipe2plan-test.ts +++ b/src/tools/tests/recipe2plan-test.ts @@ -461,7 +461,6 @@ policy PolicyBarBr2Br3 { const assertSuccess = async (recipeStr) => verifyRecipeIngress(recipeStr, true); const assertFailure = async (recipeStr) => verifyRecipeIngress(recipeStr, false); const verifyRecipeIngress = async (recipeStr: string, expectedSuccess: boolean) => { - Runtime.resetDrivers(); const recipesManifest = await Manifest.parse(` ${manifestMetaAndParticleSpecs} ${recipeStr} diff --git a/src/wasm/tests/wasm-api-test.ts b/src/wasm/tests/wasm-api-test.ts index cb148b65ad0..e4966e1d6d3 100644 --- a/src/wasm/tests/wasm-api-test.ts +++ b/src/wasm/tests/wasm-api-test.ts @@ -34,7 +34,6 @@ class TestLoader extends Loader { constructor(readonly testDir: string) { super(); } - resolve(path: string) { // The manifest is in the same dir as this test file but the compiled wasm binaries // are in language-specific dirs, so we need to adjust the loading path accordingly. @@ -43,7 +42,6 @@ class TestLoader extends Loader { } return (path[0] === '$') ? `RESOLVED(${path})` : path; } - clone(): TestLoader { return this; } @@ -71,7 +69,6 @@ async function createBackingEntity(arc: Arc, referenceType: ReferenceType { describe(`wasm tests (${testLabel})`, function() { const isKotlin = testLabel === 'Kotlin'; @@ -112,7 +109,7 @@ Object.entries(testMap).forEach(([testLabel, testDir]) => { const slotObserver = new SlotTestObserver(); slotComposer.observeSlots(slotObserver); - return {arc, stores: info.stores, slotObserver}; + return {arc, stores: info.stores, slotObserver, runtime}; } it('onHandleSync / onHandleUpdate', async () => { @@ -534,7 +531,7 @@ Object.entries(testMap).forEach(([testLabel, testDir]) => { this.skip(); } - const {arc, stores} = await setup('OnFirstStartTest'); + const {arc, stores, runtime} = await setup('OnFirstStartTest'); const fooHandle = await handleForStoreInfo(stores.get('fooHandle') as StoreInfo, arc); assert.deepStrictEqual(await fooHandle.fetch() as {}, {txt: 'Created!'}); @@ -544,8 +541,9 @@ Object.entries(testMap).forEach(([testLabel, testDir]) => { const manifest = await manifestPromise; - const storageService = new DirectStorageEndpointManager(); - const arc2 = await Arc.deserialize({serialization, loader, fileName: '', context: manifest, storageService}); + //const storageService = new DirectStorageEndpointManager(); + const {driverFactory, storageService} = runtime; + const arc2 = await Arc.deserialize({serialization, loader, fileName: '', context: manifest, storageService, driverFactory}); await arc2.idle; const fooClass = Entity.createEntityClass(manifest.findSchemaByName('FooHandle'), null); @@ -555,58 +553,58 @@ Object.entries(testMap).forEach(([testLabel, testDir]) => { }); it('multiple handles onUpdate', async function() { - if (isCpp) { - this.skip(); - } - const {arc, stores} = await setup('CombineUpdatesTest'); - const handle1 = await handleForStoreInfo(stores.get('handle1') as StoreInfo, arc); - const handle2 = await handleForStoreInfo(stores.get('handle2') as StoreInfo, arc); - const handle3 = await handleForStoreInfo(stores.get('handle3') as StoreInfo, arc); - const handle4 = await handleForStoreInfo(stores.get('handle4') as StoreInfo, arc); - const handle5 = await handleForStoreInfo(stores.get('handle5') as StoreInfo, arc); - const handle6 = await handleForStoreInfo(stores.get('handle6') as StoreInfo, arc); - const handle7 = await handleForStoreInfo(stores.get('handle7') as StoreInfo, arc); - const handle8 = await handleForStoreInfo(stores.get('handle8') as StoreInfo, arc); - const handle9 = await handleForStoreInfo(stores.get('handle9') as StoreInfo, arc); - const handle10 = await handleForStoreInfo(stores.get('handle10') as StoreInfo, arc); - - await handle1.set(new handle1.entityClass({num: 1.0})); - await handle2.add(new handle2.entityClass({num: 1.0})); - await handle3.set(new handle3.entityClass({num3: 1.0})); - await handle4.set(new handle4.entityClass({num4: 1.0})); - await handle5.set(new handle5.entityClass({num5: 1.0})); - await handle6.set(new handle6.entityClass({num6: 1.0})); - await handle7.set(new handle7.entityClass({num7: 1.0})); - await handle8.set(new handle8.entityClass({num8: 1.0})); - await handle9.set(new handle9.entityClass({num9: 1.0})); - await handle10.set(new handle10.entityClass({num10: 1.0})); - - const errHandle = await handleForStoreInfo(stores.get('errors') as StoreInfo, arc); - - const sendEvent = async handler => { - await arc.idle; - arc.peh.sendEvent(arc.activeRecipe.particles[0], 'root', {handler}); - await arc.idle; - }; - - await sendEvent('checkEvents'); - - const errors = (await errHandle.toList()).map(e => e.msg); - - const expectedErrors = [ - `Single Handle OnUpdate called 1 times.`, - `Calling combineUpdates with 2 Handles called 2 times.`, - `Calling combineUpdates with 2 Handles called 2 times.`, - `Calling combineUpdates with 3 Handles called 3 times.`, - `Calling combineUpdates with 4 Handles called 4 times.`, - `Calling combineUpdates with 5 Handles called 5 times.`, - `Calling combineUpdates with 6 Handles called 6 times.`, - `Calling combineUpdates with 7 Handles called 7 times.`, - `Calling combineUpdates with 8 Handles called 8 times.`, - `Calling combineUpdates with 9 Handles called 9 times.`, - `Calling combineUpdates with 10 Handles called 10 times.`, - ]; - assert.deepStrictEqual(errors, expectedErrors); - }); + if (isCpp) { + this.skip(); + } + const {arc, stores} = await setup('CombineUpdatesTest'); + const handle1 = await handleForStoreInfo(stores.get('handle1') as StoreInfo, arc); + const handle2 = await handleForStoreInfo(stores.get('handle2') as StoreInfo, arc); + const handle3 = await handleForStoreInfo(stores.get('handle3') as StoreInfo, arc); + const handle4 = await handleForStoreInfo(stores.get('handle4') as StoreInfo, arc); + const handle5 = await handleForStoreInfo(stores.get('handle5') as StoreInfo, arc); + const handle6 = await handleForStoreInfo(stores.get('handle6') as StoreInfo, arc); + const handle7 = await handleForStoreInfo(stores.get('handle7') as StoreInfo, arc); + const handle8 = await handleForStoreInfo(stores.get('handle8') as StoreInfo, arc); + const handle9 = await handleForStoreInfo(stores.get('handle9') as StoreInfo, arc); + const handle10 = await handleForStoreInfo(stores.get('handle10') as StoreInfo, arc); + + await handle1.set(new handle1.entityClass({num: 1.0})); + await handle2.add(new handle2.entityClass({num: 1.0})); + await handle3.set(new handle3.entityClass({num3: 1.0})); + await handle4.set(new handle4.entityClass({num4: 1.0})); + await handle5.set(new handle5.entityClass({num5: 1.0})); + await handle6.set(new handle6.entityClass({num6: 1.0})); + await handle7.set(new handle7.entityClass({num7: 1.0})); + await handle8.set(new handle8.entityClass({num8: 1.0})); + await handle9.set(new handle9.entityClass({num9: 1.0})); + await handle10.set(new handle10.entityClass({num10: 1.0})); + + const errHandle = await handleForStoreInfo(stores.get('errors') as StoreInfo, arc); + + const sendEvent = async handler => { + await arc.idle; + arc.peh.sendEvent(arc.activeRecipe.particles[0], 'root', {handler}); + await arc.idle; + }; + + await sendEvent('checkEvents'); + + const errors = (await errHandle.toList()).map(e => e.msg); + + const expectedErrors = [ + `Single Handle OnUpdate called 1 times.`, + `Calling combineUpdates with 2 Handles called 2 times.`, + `Calling combineUpdates with 2 Handles called 2 times.`, + `Calling combineUpdates with 3 Handles called 3 times.`, + `Calling combineUpdates with 4 Handles called 4 times.`, + `Calling combineUpdates with 5 Handles called 5 times.`, + `Calling combineUpdates with 6 Handles called 6 times.`, + `Calling combineUpdates with 7 Handles called 7 times.`, + `Calling combineUpdates with 8 Handles called 8 times.`, + `Calling combineUpdates with 9 Handles called 9 times.`, + `Calling combineUpdates with 10 Handles called 10 times.`, + ]; + assert.deepStrictEqual(errors, expectedErrors); + }); }); }); diff --git a/tools/sigh.ts b/tools/sigh.ts index ce1c93b79a3..b3f867bc401 100644 --- a/tools/sigh.ts +++ b/tools/sigh.ts @@ -69,6 +69,7 @@ const buildShells = () => globalOptions.bazel ? true : buildPkg('shells'); const steps: {[index: string]: ((args?: string[]) => boolean|Promise)[]} = { peg: [peg, railroad], test: [peg, build, buildShells, runTestsOrHealthOnCron], + justTest: [runTestsOrHealthOnCron], testShells: [peg, build, buildShells, webpack, webpackStorage, devServerAsync, testWdioShells], testWdioShells: [testWdioShells], webpack: [peg, build, buildShells, webpack],