Skip to content

Commit

Permalink
Cover provider with unit tests (#32)
Browse files Browse the repository at this point in the history
* add mocha as test framework

Signed-off-by: Michael Granados <[email protected]>

* separate provider in module to provide better access to separated areas

Signed-off-by: Michael Granados <[email protected]>

* cover checkServiceAccount util

Signed-off-by: Michael Granados <[email protected]>

* cover checkBucket to verify if bucket exists on GCS

Signed-off-by: Michael Granados <[email protected]>

* cover mergeConfig function

Signed-off-by: Michael Granados <[email protected]>

* cover upload action

Signed-off-by: Michael Granados <[email protected]>

* add istanbul coverage

Signed-off-by: Michael Granados <[email protected]>

* change workflow

Signed-off-by: Michael Granados <[email protected]>

* remove not used line

Signed-off-by: Michael Granados <[email protected]>

* cover #delete action

Signed-off-by: Michael Granados <[email protected]>

* add tests for filenames using real cases for upload and upload with reference

Signed-off-by: Michael Granados <[email protected]>

* rescue separate general parse JSON error from specific attributes errors

Signed-off-by: Michael Granados <[email protected]>

* add EOL

Signed-off-by: Michael Granados <[email protected]>

* cover malformed JSON

Signed-off-by: Michael Granados <[email protected]>
  • Loading branch information
dgmike authored May 27, 2020
1 parent a8dd651 commit dbc5d14
Show file tree
Hide file tree
Showing 11 changed files with 1,050 additions and 202 deletions.
16 changes: 16 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[{package.json,*.yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"env": {
"node": true,
"es6": true
"es6": true,
"mocha": true
},
"plugins": ["prettier"],
"extends": [
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/npmpublish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ on:
types: [created]

jobs:
publish-npm:
npm-publish:
runs-on: ubuntu-latest
branches: master
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '10.x'
registry-url: https://registry.npmjs.org/
- run: npm ci
- run: npm install
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
14 changes: 14 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Test project
on: push

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '10.x'
registry-url: https://registry.npmjs.org/
- run: npm install
- run: npm run coverage
3 changes: 3 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recursive": true
}
4 changes: 4 additions & 0 deletions .nycrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"all": true,
"include": ["lib"]
}
199 changes: 2 additions & 197 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,202 +1,7 @@
'use strict';

const path = require('path');
const slugify = require('slugify');
const { Storage } = require('@google-cloud/storage');
const { init } = require('./provider');

/**
* Check validity of Service Account configuration
* @param config
* @returns {{private_key}|{client_email}|{project_id}|any}
*/
const checkServiceAccount = (config) => {
if (!config.serviceAccount) {
throw new Error('"Service Account JSON" is required!');
}
if (!config.bucketName) {
throw new Error('"Bucket name" is required!');
}
if (!config.baseUrl) {
/** Set to default **/
config.baseUrl = 'https://storage.googleapis.com/{bucket-name}';
}

let serviceAccount;

try {
serviceAccount =
typeof config.serviceAccount === 'string'
? JSON.parse(config.serviceAccount)
: config.serviceAccount;
} catch (e) {
throw new Error(
'Error parsing data "Service Account JSON", please be sure to copy/paste the full JSON file.'
);
}

/**
* Check exist
*/
if (!serviceAccount.project_id) {
throw new Error(
'Error parsing data "Service Account JSON". Missing "project_id" field in JSON file.'
);
}
if (!serviceAccount.client_email) {
throw new Error(
'Error parsing data "Service Account JSON". Missing "client_email" field in JSON file.'
);
}
if (!serviceAccount.private_key) {
throw new Error(
'Error parsing data "Service Account JSON". Missing "private_key" field in JSON file.'
);
}
return serviceAccount;
};

/**
* Check bucket exist, or create it
* @param GCS
* @param bucketName
* @returns {Promise<void>}
*/
const checkBucket = async (GCS, bucketName) => {
let bucket = GCS.bucket(bucketName);
await bucket.exists().then((data) => {
if (!data[0]) {
throw new Error(
'An error occurs when we try to retrieve the Bucket "' +
bucketName +
'". Check if bucket exist on Google Cloud Platform.'
);
}
});
};

/**
* Merge uploadProvider config with gcs key in custom Strapi config
* @param uploadProviderConfig
* @returns {{private_key}|{client_email}|{project_id}|any}
*/
const mergeConfigs = (providerConfig) => {
let customGcsConfig = strapi.config.gcs ? strapi.config.gcs : {};
let customEnvGcsConfig = strapi.config.currentEnvironment.gcs
? strapi.config.currentEnvironment.gcs
: {};
return { ...providerConfig, ...customGcsConfig, ...customEnvGcsConfig };
};

/**
*
* @type {{init(*=): {upload(*=): Promise<unknown>, delete(*): Promise<unknown>}}}
*/
module.exports = {
init(providerConfig) {
const config = mergeConfigs(providerConfig);
const serviceAccount = checkServiceAccount(config);
const GCS = new Storage({
projectId: serviceAccount.project_id,
credentials: {
client_email: serviceAccount.client_email,
private_key: serviceAccount.private_key,
},
});

return {
upload(file) {
return new Promise((resolve, reject) => {
const backupPath =
file.related && file.related.length > 0 && file.related[0].ref
? `${file.related[0].ref}`
: `${file.hash}`;
const filePath = file.path ? `${file.path}/` : `${backupPath}/`;
const fileName =
slugify(path.basename(file.name + '_' + file.hash, file.ext)) + file.ext.toLowerCase();

checkBucket(GCS, config.bucketName)
.then(() => {
/**
* Check if the file already exist and force to remove it on Bucket
*/
GCS.bucket(config.bucketName)
.file(`${filePath}${fileName}`)
.exists()
.then((exist) => {
if (exist[0]) {
strapi.log.info('File already exist, try to remove it.');
const fileName = `${file.url.replace(
config.baseUrl.replace('{bucket-name}', config.bucketName) + '/',
''
)}`;

GCS.bucket(config.bucketName)
.file(`${fileName}`)
.delete()
.then(() => {
strapi.log.debug(`File ${fileName} successfully deleted`);
})
.catch((error) => {
if (error.code === 404) {
return strapi.log.warn(
'Remote file was not found, you may have to delete manually.'
);
}
});
}
});
})
.then(() => {
/**
* Then save file
*/
GCS.bucket(config.bucketName)
.file(`${filePath}${fileName}`)
.save(file.buffer, {
contentType: file.mime,
public: true,
metadata: {
contentDisposition: `inline; filename="${file.name}"`,
},
})
.then(() => {
file.url = `${config.baseUrl.replace(
/{bucket-name}/,
config.bucketName
)}/${filePath}${fileName}`;
strapi.log.debug(`File successfully uploaded to ${file.url}`);
resolve();
})
.catch((error) => {
return reject(error);
});
});
});
},
delete(file) {
return new Promise((resolve, reject) => {
const fileName = `${file.url.replace(
config.baseUrl.replace('{bucket-name}', config.bucketName) + '/',
''
)}`;

GCS.bucket(config.bucketName)
.file(fileName)
.delete()
.then(() => {
strapi.log.debug(`File ${fileName} successfully deleted`);
})
.catch((error) => {
if (error.code === 404) {
return strapi.log.warn(
'Remote file was not found, you may have to delete manually.'
);
}
reject(error);
});
resolve();
});
},
};
},
init,
};
Loading

0 comments on commit dbc5d14

Please sign in to comment.