diff --git a/.vscode/launch.json b/.vscode/launch.json index fd5b5d4a..707ea5fa 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,15 +13,6 @@ "outFiles": ["${workspaceRoot}/out/src/**/*.js"], "preLaunchTask": "compile typescript" }, - { - // A launch configuration that compiles the extension and runs mocha unit tests - "type": "node", - "request": "launch", - "name": "Launch Tests", - "program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", - "args": ["-u", "tdd", "--timeout", "999999", "--colors", "-r", "ts-node/register", "${workspaceRoot}/test/*.test.ts"], - "preLaunchTask": "compile typescript" - }, { "name": "Extension Tests", "type": "extensionHost", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 98c6bb8d..39a29253 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,7 @@ "command": "yarn run compile", // show the output window only if unrecognized errors occur. "presentation": { - "reveal": "silent" + "reveal": "never" }, // The tsc compiler is started in watching mode "isBackground": true, diff --git a/src/extension.ts b/src/extension.ts index 2afae680..40a7ec5e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -121,7 +121,7 @@ export async function activate(context: ExtensionContext): Promise { await fs.ensureDir(this.cachePath); + const cachedFiles = await fs.readdir(this.cachePath); + // clean up memento if cached files was deleted from fs + const cachedValues = cachedFiles.map((it) => path.join(this.cachePath, it)); + for (const key in this.cache) { + if (Object.prototype.hasOwnProperty.call(this.cache, key)) { + const cacheEntry = this.cache[key]; + if (!cachedValues.includes(cacheEntry.schemaPath)) { + delete this.cache[key]; + } + } + } + await this.memento.update(CACHE_KEY, this.cache); this.isInitialized = true; } @@ -44,6 +56,9 @@ export class JSONSchemaCache { } getETag(schemaUri: string): string | undefined { + if (!this.isInitialized) { + return undefined; + } return this.cache[schemaUri]?.eTag; } diff --git a/test/helper.ts b/test/helper.ts index ff4f741f..906ffbfa 100644 --- a/test/helper.ts +++ b/test/helper.ts @@ -123,3 +123,16 @@ export async function testDiagnostics(docUri: vscode.Uri, expectedDiagnostics: v assert.equal(actualDiagnostic.severity, expectedDiagnostic.severity); }); } + +export class TestMemento implements vscode.Memento { + get(key: string): T; + get(key: string, defaultValue: T): T; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + get(key: string, defaultValue?: T): T | undefined { + throw new Error('Method not implemented.'); + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + update(key: string, value: unknown): Thenable { + throw new Error('Method not implemented.'); + } +} diff --git a/test/json-schema-cache.test.ts b/test/json-schema-cache.test.ts new file mode 100644 index 00000000..218db526 --- /dev/null +++ b/test/json-schema-cache.test.ts @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Red Hat, Inc. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as sinon from 'sinon'; +import * as sinonChai from 'sinon-chai'; +import * as chai from 'chai'; +import * as vscode from 'vscode'; +import * as fs from 'fs-extra'; +import { JSONSchemaCache } from '../src/json-schema-cache'; +import { TestMemento } from './helper'; + +const expect = chai.expect; +chai.use(sinonChai); +describe('JSON Schema Cache Tests', () => { + const sandbox = sinon.createSandbox(); + let memento: sinon.SinonStubbedInstance; + let ensureDirStub: sinon.SinonStub; + let readdirStub: sinon.SinonStub; + let pathExistsStub: sinon.SinonStub; + let readFileStub: sinon.SinonStub; + + afterEach(() => { + sandbox.restore(); + }); + + beforeEach(() => { + memento = sandbox.stub(new TestMemento()); + ensureDirStub = sandbox.stub(fs, 'ensureDir'); + readdirStub = sandbox.stub(fs, 'readdir'); + pathExistsStub = sandbox.stub(fs, 'pathExists'); + readFileStub = sandbox.stub(fs, 'readFile'); + }); + + it('should clean up cache if there are no schema file', async () => { + memento.get.returns({ somePath: { schemaPath: '/foo/path/' } }); + memento.update.resolves(); + + ensureDirStub.resolves(); + readdirStub.resolves([]); + + pathExistsStub.resolves(false); + readFileStub.resolves(); + + const cache = new JSONSchemaCache('/some/path/', (memento as unknown) as vscode.Memento, {} as vscode.OutputChannel); + const result = await cache.getSchema('/some/uri'); + expect(result).is.undefined; + expect(memento.update).calledOnceWith('json-schema-key', {}); + }); + + it('should check cache', async () => { + const mementoData = { somePath: { schemaPath: '/some/path/foo.json' } }; + memento.get.returns(mementoData); + memento.update.resolves(); + + ensureDirStub.resolves(); + readdirStub.resolves(['foo.json']); + + pathExistsStub.resolves(false); + readFileStub.resolves(); + + const cache = new JSONSchemaCache('/some/path/', (memento as unknown) as vscode.Memento, {} as vscode.OutputChannel); + const result = await cache.getSchema('/some/uri'); + expect(result).is.undefined; + expect(memento.update).calledOnceWith('json-schema-key', mementoData); + }); +});