Browse Source

add jasmine test

pull/79/merge
Jeremy Wentworth 7 years ago
parent
commit
60976cf67b
5 changed files with 53 additions and 131 deletions
  1. +5
    -1
      .travis.yml
  2. +2
    -1
      package.json
  3. +35
    -0
      spec/basics.spec.js
  4. +11
    -0
      spec/support/jasmine.json
  5. +0
    -129
      test.js

+ 5
- 1
.travis.yml View File

@@ -1,3 +1,7 @@
language: node_js
node_js:
"6.2.0"
"6.2.0"

before_install:
- git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
- git fetch

+ 2
- 1
package.json View File

@@ -3,7 +3,7 @@
"version": "1.0.0",
"description": "*Manifest repository for VCV Rack plugins*",
"scripts": {
"test": "node test.js"
"test": "jasmine"
},
"repository": {
"type": "git",
@@ -14,6 +14,7 @@
},
"homepage": "https://github.com/VCVRack/community#readme",
"devDependencies": {
"jasmine": "^2.8.0",
"node-virustotal": "^2.4.2",
"request": "^2.83.0"
}


+ 35
- 0
spec/basics.spec.js View File

@@ -0,0 +1,35 @@
//Jasmine Test - https://jasmine.github.io/2.8/introduction.html
const fs = require("fs");

describe("json", function() {
it("simply valid parsable json", function(done) {
fs.readdir('plugins', function(err, files) {
if (err){
fail("unable to read plugins dir");
}

for (let index in files) {
const filePath = `plugins/${files[index]}`;
if(!filePath.toLowerCase().endsWith('.json')){
fail("manifests should have .json extension");
}
fs.readFile(filePath, 'utf8', (err, fileContent) => {
if (err){
fail("unable to read manifest file");
}
let manifestObj;
try {
manifestObj = JSON.parse(fileContent+"FAIL");
done();
} catch(err){
fail(`Invalid JSON: ${filePath}\n${err}`);
}
});
}
});
});

});

+ 11
- 0
spec/support/jasmine.json View File

@@ -0,0 +1,11 @@
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.js"
],
"helpers": [
"helpers/**/*.js"
],
"stopSpecOnExpectationFailure": false,
"random": false
}

+ 0
- 129
test.js View File

@@ -1,129 +0,0 @@
/*
check valid JSON
check valid SHA256
upload to VirusTotal and assert less than 3 or so engines return suspicious for each ZIP

ZIP must not contain a __MACOSX directory at root level.
ZIP must not be a tarbomb. Yes, I know the first is a subset of this one, but it's better to have more feedback.
We might even want to assert that the single folder at root level is named as the slug of the plugin. I'm for this.

schema validation

slug required
if we could have a "soft" warning for slugs matching /[a-zA-Z0-9_\-]/+, that'd be great, although I'd rather their slugs break this than change.
version required
version must begin with "0.5." (this will be changed with each version bump.)

*/



const fs = require("fs");
const request = require("request");
const { exec } = require('child_process');
const vt = require("node-virustotal");//https://github.com/natewatson999/node-virustotal
const con = vt.MakePublicConnection();
const archArr = ['win', 'lin', 'mac'];
const verbose = false;

//VT_API_KEY is set in travisci (or set when run locally)
con.setKey(process.env.VT_API_KEY);
if(verbose){console.log('key', con.getKey());}

//15 seconds between calls is required by virus total (4 per minute)
//https://www.virustotal.com/en/documentation/public-api/v2/
con.setDelay(15000);
if(verbose){console.log('delay', con.getDelay());}

//We always just check all JSON because it's easy.
//However, we only want to check zip files of manifests that have changed.



//TODO FIX - travis doesn't have master
// https://github.com/travis-ci/travis-ci/issues/6069
// todo check diff to see if "download" or "sha256" changed
exec('git diff -w --stat --name-only origin/master -- plugins/', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
const changedManifestFiles = stdout.trim().split('\n');
testAllManifests(changedManifestFiles);
});

function testAllManifests(changedManifestFiles){
if(verbose){console.log("changedManifestFiles", changedManifestFiles);}
fs.readdir('plugins', function(err, files) {
if (err){ throw err; }

for (let index in files) {
const filePath = `plugins/${files[index]}`;
if(!filePath.toLowerCase().endsWith('.json')){
throw new Error("manifests should have .json extension");
}
fs.readFile(filePath, 'utf8', (err, data) => {
if (err){ throw err; }
if(verbose){console.log("testing: ", filePath);}
const shouldTestZip = changedManifestFiles.includes(filePath);
testOneManifest(filePath, data, shouldTestZip);
});
}
});
}

function testOneManifest(filePath, fileContent, shouldTestZip = false) {
let manifestObj;
try {
manifestObj = JSON.parse(fileContent);
} catch(err){
console.error(`Invalid JSON: ${filePath}`);
throw err;
}

if (manifestObj.downloads) {
let zipUrlsChecked = [];
let lastSha256;
archArr.map(arch => {
const archObj = manifestObj.downloads[arch];
if (archObj && archObj.download) {
if(zipUrlsChecked.includes(archObj.download)){
if(lastSha256 !== archObj.sha256){
throw new Error('SHA256 should be the same if the download URL is the same.');
}
} else {
zipUrlsChecked.push(archObj.download);
lastSha256 = archObj.sha256;

if(shouldTestZip){
testOneArch(archObj);
} else {
if(verbose){console.log("not testing zip because the manifest hasn't changed: ", filePath);}
}
}
}
});
}
}

function testOneArch(archObj) {
const urlParts = archObj.download.split('/');
const zipName = urlParts[urlParts.length - 1].split('\?')[0];
if(verbose){console.log(`Downloading ${archObj.download}`);}
request(archObj.download).pipe(fs.createWriteStream(zipName)).on('finish', ()=>{
con.FileEvaluation(zipName, "application/zip", fs.readFileSync(zipName), function(data) {
console.log(data);
if(archObj.sha256 !== data.sha256){
throw new Error(`Invalid sha256 value. manifest:${archObj.sha256} virustotal:${data.sha256}`);
}
if(data.positives > 2){
throw new Error(`Too many positives from virustotal.`);
}
}, function(err) {
if (err){ throw err; }
});
});
}

Loading…
Cancel
Save