Skip to content

Commit

Permalink
refactor: Seclude ensureExists util
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrzesik committed Jan 12, 2021
1 parent 26140db commit c3f59e4
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 88 deletions.
22 changes: 9 additions & 13 deletions lib/plugins/aws/customResources/generateZip.js
@@ -1,28 +1,24 @@
'use strict';

const path = require('path');
const BbPromise = require('bluebird');
const fse = require('fs-extra');
const getTmpDirPath = require('../../../utils/fs/getTmpDirPath');
const createZipFile = require('../../../utils/fs/createZipFile');
const getEnsureArtifact = require('../../../utils/getEnsureArtifact');
const ensureArtifact = require('../../../utils/ensureArtifact');

const srcDirPath = path.join(__dirname, 'resources');

const artifactName = 'custom-resources.zip';

const ensureCustomResourcesArtifact = getEnsureArtifact(artifactName, (cachePath) =>
BbPromise.try(() => {
module.exports = async () => {
const resultPath = await ensureArtifact(artifactName, async (cachePath) => {
const tmpDirPath = getTmpDirPath();
const tmpInstalledLambdaPath = path.resolve(tmpDirPath, 'resource-lambda');
const tmpZipFilePath = path.resolve(tmpDirPath, 'resource-lambda.zip');
const cachedZipFilePath = path.resolve(cachePath, artifactName);
return fse
.copy(srcDirPath, tmpInstalledLambdaPath)
.then(() => createZipFile(tmpInstalledLambdaPath, tmpZipFilePath))
.then(() => fse.move(tmpZipFilePath, cachedZipFilePath));
})
);

module.exports = () =>
ensureCustomResourcesArtifact().then((cachePath) => path.resolve(cachePath, artifactName));
await fse.copy(srcDirPath, tmpInstalledLambdaPath);
await createZipFile(tmpInstalledLambdaPath, tmpZipFilePath);
await fse.move(tmpZipFilePath, cachedZipFilePath);
});
return path.resolve(resultPath, artifactName);
};
17 changes: 9 additions & 8 deletions lib/plugins/aws/invokeLocal/index.js
Expand Up @@ -18,20 +18,21 @@ const { v4: uuidv4 } = require('uuid');
const dirExists = require('../../../utils/fs/dirExists');
const fileExists = require('../../../utils/fs/fileExists');
const isStandalone = require('../../../utils/isStandaloneExecutable');
const getEnsureArtifact = require('../../../utils/getEnsureArtifact');
const ensureArtifact = require('../../../utils/ensureArtifact');
const resolveCfImportValue = require('../utils/resolveCfImportValue');
const resolveCfRefValue = require('../utils/resolveCfRefValue');

const cachePath = path.join(cachedir('serverless'), 'invokeLocal');

const ensureRuntimeWrappers = isStandalone
? getEnsureArtifact('runtimeWrappers/validationFile', async (artifactsPath) => {
await fse.copy(
path.resolve(__dirname, 'runtimeWrappers'),
path.resolve(artifactsPath, 'runtimeWrappers')
);
return fse.ensureFile(path.resolve(artifactsPath, 'runtimeWrappers/validationFile'));
})
? () =>
ensureArtifact('runtimeWrappers/validationFile', async (artifactsPath) => {
await fse.copy(
path.resolve(__dirname, 'runtimeWrappers'),
path.resolve(artifactsPath, 'runtimeWrappers')
);
return fse.ensureFile(path.resolve(artifactsPath, 'runtimeWrappers/validationFile'));
})
: () => Promise.resolve(__dirname);

class AwsInvokeLocal {
Expand Down
17 changes: 17 additions & 0 deletions lib/utils/ensureArtifact.js
@@ -0,0 +1,17 @@
'use strict';

const memoizee = require('memoizee');
const { version } = require('../../package');
const ensureExists = require('./ensureExists');
const path = require('path');
const os = require('os');

const cachePath = path.resolve(os.homedir(), '.serverless/artifacts', version);

module.exports = memoizee(
async (filename, generate) => {
await ensureExists(path.resolve(cachePath, filename), generate);
return cachePath;
},
{ length: 1, promise: true }
);
20 changes: 20 additions & 0 deletions lib/utils/ensureExists.js
@@ -0,0 +1,20 @@
'use strict';

const fse = require('fs-extra');
const fs = require('fs');
const path = require('path');

module.exports = async (filename, generate) => {
const cacheDir = path.dirname(filename);
try {
const stats = await fs.promises.lstat(filename);
if (stats.isFile()) {
return;
}
} catch (err) {
if (err.code !== 'ENOENT') throw err;
}

await fse.ensureDir(cacheDir);
await generate(cacheDir);
};
39 changes: 0 additions & 39 deletions lib/utils/getEnsureArtifact.js

This file was deleted.

4 changes: 2 additions & 2 deletions test/mochaPatch.js
Expand Up @@ -2,7 +2,7 @@

const path = require('path');
const disableServerlessStatsRequests = require('@serverless/test/disable-serverless-stats-requests');
const { _ensureArtifact } = require('../lib/utils/getEnsureArtifact');
const ensureArtifact = require('../lib/utils/ensureArtifact');
const resolveLocalServerless = require('../lib/cli/resolve-local-serverless-path');

disableServerlessStatsRequests(path.resolve(__dirname, '..'));
Expand All @@ -25,6 +25,6 @@ runnerEmitter.on('runner', (runner) => {
// Ensure to reset memoization on artifacts generation after each test file run.
// Reason is that homedir is automatically cleaned for each test,
// therefore eventually built custom resource file is also removed
_ensureArtifact.clear();
ensureArtifact.clear();
});
});
34 changes: 34 additions & 0 deletions test/unit/lib/utils/ensureExists.test.js
@@ -0,0 +1,34 @@
'use strict';

const chai = require('chai');
const sinon = require('sinon');

const ensureExists = require('../../../../lib/utils/ensureExists');
const { getTmpDirPath } = require('../../../utils/fs');

const path = require('path');
const fs = require('fs');
const crypto = require('crypto');

const expect = chai.expect;
chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));

describe('test/unit/lib/utils/ensureExists.test.js', () => {
const testCacheDir = getTmpDirPath();

it('Should call generate if file missing', async () => {
const testFileName = `test-${crypto.randomBytes(2).toString('hex')}`;
const generateStub = sinon.stub().resolves();
await ensureExists(path.resolve(testCacheDir, testFileName), generateStub);
expect(generateStub.calledOnce).to.be.true;
});

it('Should not call generate if file exists', async () => {
const testFileName = `test-${crypto.randomBytes(2).toString('hex')}`;
await fs.promises.writeFile(path.resolve(testCacheDir, testFileName), '');
const generateStub = sinon.stub().resolves();
await ensureExists(path.resolve(testCacheDir, testFileName), generateStub);
expect(generateStub.calledOnce).to.be.false;
});
});
51 changes: 25 additions & 26 deletions test/unit/lib/utils/getEnsureArtifact.test.js
Expand Up @@ -2,45 +2,44 @@

const { expect } = require('chai');

const getEnsureArtifact = require('../../../../lib/utils/getEnsureArtifact');
const ensureArtifact = require('../../../../lib/utils/ensureArtifact');

const path = require('path');
const fs = require('fs');
const fse = require('fs-extra');
const crypto = require('crypto');

describe('#getEnsureArtifact', () => {
describe('#ensureArtifact', () => {
const testArtifactName = `test-${crypto.randomBytes(2).toString('hex')}`;

let testArtifactPath;
let ensureArtifact;
let invokedCount = 0;

before(() => {
ensureArtifact = getEnsureArtifact(testArtifactName, (cachePath) => {
testArtifactPath = path.resolve(cachePath, testArtifactName);
++invokedCount;
return fse.writeFile(testArtifactPath, '');
});
});

it('Should not generate on ensure function initialization', () =>
fse.pathExists(testArtifactPath).then((exists) => expect(exists).to.be.false));
const generateFunc = async (cachePath) => {
testArtifactPath = path.resolve(cachePath, testArtifactName);
++invokedCount;
await fs.promises.writeFile(testArtifactPath, '');
};

it('Should generate artifact if missing', () =>
ensureArtifact().then(() =>
fse.pathExists(testArtifactPath).then((exists) => expect(exists).to.be.true)
));
it('Should generate artifact if missing', async () => {
await ensureArtifact(testArtifactName, generateFunc);
const exists = await fse.pathExists(testArtifactPath);
expect(exists).to.be.true;
});

it('Should generate only on first access', () =>
ensureArtifact().then(() => expect(invokedCount).to.equal(1)));
it('Should generate only on first access', async () => {
await ensureArtifact(testArtifactName, generateFunc);
expect(invokedCount).to.equal(1);
});

it('Should not generate, if generated in past', () => {
getEnsureArtifact._ensureArtifact.delete(testArtifactName);
return ensureArtifact().then(() => expect(invokedCount).to.equal(1));
it('Should not generate, if generated in past', async () => {
ensureArtifact.delete(testArtifactName);
await ensureArtifact(testArtifactName, generateFunc);
expect(invokedCount).to.equal(1);
});

it('Should return cache path', () =>
ensureArtifact().then((cachePath) =>
expect(cachePath).to.include(`.serverless${path.sep}artifacts`)
));
it('Should return cache path', async () => {
const cachePath = await ensureArtifact(testArtifactName, generateFunc);
expect(cachePath).to.include(`.serverless${path.sep}artifacts`);
});
});

0 comments on commit c3f59e4

Please sign in to comment.