diff --git a/README.md b/README.md
index abb87de..c905666 100644
--- a/README.md
+++ b/README.md
@@ -1,45 +1,15 @@
-# Example Test Adapter for Visual Studio Code
+# Snort3 Test Explorer for Visual Studio Code
-This repository contains an example for implementing a `TestAdapter` extension that works with the
-[Test Explorer](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-test-explorer) extension.
-
-More documentation can be found in the [Test Adapter API repository](https://github.com/hbenl/vscode-test-adapter-api).
+Snort3 Test Explorer is a visual studio code extension that lets you run snort3 tests in the Sidebar of Visual Studio Code. This extention will activate when there is a snort3_test folder open in the workspace and automatically list all the tests available in the [Test Explorer](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-test-explorer) side bar.
## Setup
-* install the [Test Explorer](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-test-explorer) extension
-* fork and clone this repository and open it in VS Code
-* run `npm install`
-* run `npm run watch` or start the watch Task in VS Code
-* start the debugger
+* install the [Snort3 Test Explorer](https://marketplace.visualstudio.com/items?itemName=diptopandit.snort3-test-adapter) extension
+* open extension settings
+* set sf_prefix_snort3 to snort install path
+* set snort_srcpath to snort source code path
+* set dependencies to dependencies (libdaq, abcip, cpputest etc.) installation path
-You should now see a second VS Code window, the Extension Development Host.
-Open a folder in this window and click the "Test" icon in the Activity bar.
-Now you should see the fake example test suite in the side panel:
+You should now see a tree view of all the tests in the side panel:
![The fake example test suite](img/fake-tests.png)
-
-## Basic implementation
-
-* add any configuration properties that your Test Adapter needs to the `contributes.configuration.properties` section of `package.json`
-* replace the `loadFakeTests()` call in `src/adapter.ts` with your code for loading the test definitions for the real test framework
-* replace the `runFakeTests()` call in `src/adapter.ts` with your code for running the tests in a child process using the real test framework
-
-## Getting ready to publish
-
-* search for all occurrences of the word "example" in this project and replace them with the name of the testing framework that your Test Adapter supports
-* update `package.json` with your preferred values (at a minimum you should change `author`, `publisher`, `homepage`, `repository` and `bugs`)
-* create an icon for your Test Adapter (there's an SVG version of the Test Explorer icon at `img/test-explorer.svg`) and reference it in `package.json`
-* replace this README with your documentation
-
-Now you're ready to [publish](https://code.visualstudio.com/docs/extensions/publish-extension) the first version of your Test Adapter.
-
-## Completing the implementation
-
-* implement the `debug()` method
-* implement the `cancel()` method (it should kill the child process that was started by `run()` or `debug()`)
-* watch the configuration for any changes that may affect the loading of test definitions and reload the test definitions if necessary
-* watch the workspace for any changes to the test files and reload the test definitions if necessary
-* watch the configuration for any changes that may affect the results of running the tests and emit an `autorun` event if necessary
-* watch the workspace for any changes to the source files and emit an `autorun` event if necessary
-* ensure that only one test run is active at a time
diff --git a/img/fake-tests.png b/img/fake-tests.png
index 471aca7..7d48289 100644
Binary files a/img/fake-tests.png and b/img/fake-tests.png differ
diff --git a/img/test-explorer.svg b/img/test-explorer.svg
deleted file mode 100644
index 2c86a19..0000000
--- a/img/test-explorer.svg
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
diff --git a/package.json b/package.json
index de6afe8..7622acb 100644
--- a/package.json
+++ b/package.json
@@ -75,6 +75,11 @@
"type": "string",
"scope": "resource"
},
+ "snort3TestExplorer.snort_srcpath": {
+ "description": "absolute path to the snort source directory",
+ "type": "string",
+ "scope": "resource"
+ },
"snort3TestExplorer.dependencies": {
"description": "absolute path to the dependencies directory",
"type": "string",
diff --git a/release/snort3-test-adapter-0.0.1.vsix b/release/snort3-test-adapter-0.0.1.vsix
new file mode 100644
index 0000000..11e6cef
Binary files /dev/null and b/release/snort3-test-adapter-0.0.1.vsix differ
diff --git a/src/adapter.ts b/src/adapter.ts
index 53631d6..845cd73 100644
--- a/src/adapter.ts
+++ b/src/adapter.ts
@@ -5,6 +5,7 @@ import { Log } from 'vscode-test-adapter-util';
import { loadSnort3Tests, snort3Test, runTest } from './snort3Test';
import {myStatusBarItem} from './main';
import * as path from 'path';
+//import PromisePool from 'es6-promise-pool';
import {cpus} from 'os';
class jobQueue {
@@ -38,16 +39,19 @@ class jobQueue {
public flush(){
this.jobdata.splice(0);
}
+
+ public dispose(){
+ this.flush();
+ }
}
export class Snort3TestAdapter implements TestAdapter {
private disposables: { dispose(): void }[] = [];
public loadedTests: {suite:TestSuiteInfo, testDetails:Map}=<{suite:TestSuiteInfo, testDetails:Map}>{};
- private currentJobQ:jobQueue;
+ private currentJobQ:jobQueue = new jobQueue;
private running:boolean = false;
private loading:boolean = false;
private cancelling:boolean = false;
- //private active_jobs:snort3Test[]=[];
private readonly testsEmitter = new vscode.EventEmitter();
private readonly testStatesEmitter = new vscode.EventEmitter();
@@ -66,41 +70,57 @@ export class Snort3TestAdapter implements TestAdapter {
private readonly log: Log
) {
this.log.info('Initializing snort3_test adapter for '+ workspace.uri.path);
- const watcher1=vscode.workspace.createFileSystemWatcher('**/*.{py,xml,sh,lua}',true,false,true)
- .onDidChange((e)=>{ this.handleFileChange(e); });
- const watcher2=vscode.workspace.createFileSystemWatcher('**/*expected*',true,false,true)
- .onDidChange((e)=>{ this.handleFileChange(e); });
- const watcher3=vscode.workspace.onDidChangeConfiguration((change)=>{
- if(change.affectsConfiguration('snort3TestExplorer.sf_prefix_snort3')){
- this.isTestReady=this.validate_config();
- this.load();
- }
- if(change.affectsConfiguration('snort3TestExplorer.concurrency')){
- let newVal = (vscode.workspace.getConfiguration('snort3TestExplorer').get('concurrency'));
- if(newVal) this.concurrency=newVal;
- }
- });
this.disposables.push(this.testsEmitter);
this.disposables.push(this.testStatesEmitter);
this.disposables.push(this.autorunEmitter);
this.disposables.push(this.retireEmitter);
- this.disposables.push(watcher1);
- this.disposables.push(watcher2);
- this.disposables.push(watcher3);
- this.currentJobQ = new jobQueue;
- this.isTestReady = this.validate_config();
+ this.disposables.push(this.currentJobQ);
+ if(this.is_test_root())
+ {
+ const watcher1=vscode.workspace.createFileSystemWatcher('**/*.{py,xml,sh,lua}',true,false,true)
+ .onDidChange((e)=>{ this.handleFileChange(e); });
+ const watcher2=vscode.workspace.createFileSystemWatcher('**/*expected*',true,false,true)
+ .onDidChange((e)=>{ this.handleFileChange(e); });
+ const watcher3=vscode.workspace.onDidChangeConfiguration((change)=>{
+ if(change.affectsConfiguration('snort3TestExplorer.sf_prefix_snort3')){
+ this.isTestReady=this.validate_config();
+ this.load();
+ }
+ if(change.affectsConfiguration('snort3TestExplorer.concurrency')){
+ let newVal = (vscode.workspace.getConfiguration('snort3TestExplorer').get('concurrency'));
+ if(newVal) this.concurrency=newVal;
+ }
+ });
+
+ this.disposables.push(watcher1);
+ this.disposables.push(watcher2);
+ this.disposables.push(watcher3);
+ this.isTestReady = this.validate_config();
+ } else {
+ this.dispose();
+ }
}
+ private is_test_root():boolean{
+ try{
+ fs.accessSync(this.workspace.uri.path + '/bin/snorttest.py', fs.constants.R_OK);
+ return true;
+ } catch {
+ return false;
+ }
+ }
private validate_config():boolean{
- this.log.info('validating config');
- const config = vscode.workspace.getConfiguration('snort3TestExplorer');
+ let config = vscode.workspace.getConfiguration('snort3TestExplorer');
+ let snort_binary = config.get('sf_prefix_snort3')+'/bin/snort';
try{
- this.log.info(config.get('sf_prefix_snort3'));
fs.accessSync(this.workspace.uri.path + '/bin/snorttest.py', fs.constants.R_OK);
- fs.accessSync(config.get('sf_prefix_snort3')+'/bin/snort', fs.constants.R_OK);
+ fs.accessSync(snort_binary, fs.constants.R_OK);
} catch(e)
{
this.log.warn(this.workspace.uri.path+": "+e);
+ if(e.message.search(snort_binary))
+ vscode.window.showWarningMessage("Snort binary missing. \
+ Make sure sf_prefix_snort3 setting is correct and snort binary is present in that path.");
return false;
}
//don't care if this fails due to unavailable file handle
@@ -175,12 +195,10 @@ export class Snort3TestAdapter implements TestAdapter {
}
this.log.info(`Scheduling snort3 tests ${JSON.stringify(tests)}`);
this.testStatesEmitter.fire({ type: 'started', tests });
- myStatusBarItem.text=`$(beaker) $(sync~spin)Queuing jobs...`;
for (const suiteOrTestId of tests) {
const node = this.findNode(this.loadedTests.suite, suiteOrTestId);
if (node) this.currentJobQ.post(node);
}
- myStatusBarItem.text=`$(beaker) Snort3 Tests`;
if(this.running) return;
this.running = true;
var PromisePool = require('es6-promise-pool');
@@ -192,7 +210,7 @@ export class Snort3TestAdapter implements TestAdapter {
const test = self.loadedTests.testDetails.get(node.id);
return runTest(test,self.testStatesEmitter);
}
- else return null;
+ else return;
}
var test_pool = new PromisePool(testJobProducer, this.concurrency);
@@ -205,13 +223,14 @@ export class Snort3TestAdapter implements TestAdapter {
return;
}
-/* implement this method if your TestAdapter supports debugging tests
+/* implement this method to run snort with gdb debugging tests
async debug(tests: string[]): Promise {
// start a test run in a child process and attach the debugger to it...
}
*/
cancel(): void {
+ if(!this.isTestReady) return;
this.log.info('Cancelling all scheduled jobs...');
this.cancelling = true;
this.currentJobQ.flush();
diff --git a/src/main.ts b/src/main.ts
index e5ab0ed..9a6d438 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -7,8 +7,6 @@ export async function activate(context: vscode.ExtensionContext) {
const workspaceFolder = (vscode.workspace.workspaceFolders || [])[0];
- // create a simple logger that can be configured with the configuration variables
- // `exampleExplorer.logpanel` and `exampleExplorer.logfile`
const log = new Log('snort3TestExplorer', workspaceFolder, 'Snort3 Test Explorer');
context.subscriptions.push(log);
diff --git a/src/snort3Test.ts b/src/snort3Test.ts
index d180d88..ac5ba7c 100644
--- a/src/snort3Test.ts
+++ b/src/snort3Test.ts
@@ -25,11 +25,14 @@ export class snort3Test {
return new Promise((resolve)=>{
testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'running' });
this.active_child = child_process.spawn(this.executor,
- ['--daq-dir',this.test_env.SNORT_TEST_DAQ_DIR,'-x',this.test_env.SNORT_PREFIX,'.'],
+ ['--daq-dir',this.test_env.SNORT_TEST_DAQ_DIR,
+ '--plugin-path', this.test_env.SNORT_TEST_PLUGIN_PATH,
+ '--snort-test', this.test_env.SNORT3_TEST_ROOT,'-x',this.test_env.SNORT_PREFIX,'.'],
{cwd:this.xmlPath,env:this.test_env}).once('exit',(code,signal)=>{
if(!(signal || code)){
try{
let result=fs.readFileSync(this.xmlPath+'/results','utf8').toString().substring(0,8).split('\t')[0].toLowerCase();
+ if(result==='error') result = 'errored';
testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: result });
} catch{
testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'errored' });
@@ -37,10 +40,7 @@ export class snort3Test {
} else {
testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'errored' });
}
- /*if(signal || code && code > 2) testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'errored' });
- else if(code == 2) testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'skipped' });
- else if(code == 1) testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'failed' });
- else if(code == 0) testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'passed' });*/
+ this.active_child=undefined;
resolve();
});
if(!this.active_child){
@@ -48,6 +48,12 @@ export class snort3Test {
resolve();
}
});
+ /* -- for debugging --
+ return new Promise((resolve)=>{
+ testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'running' });
+ setTimeout(()=>{testStatesEmitter.fire({ type: 'test', test: this.xmlPath, state: 'passed' }); resolve();},500);
+ });
+ */
/*
return new Promise((resolve)=>{
testStatesEmitter.fire({ type: 'test', test: id, state: 'running' });
@@ -208,7 +214,7 @@ export async function loadSnort3Tests(rootdir:vscode.WorkspaceFolder)
const test_env = process.env;
let executor_dir = rootdir.uri.path;
let SF_PREFIX_SNORT3=(vscode.workspace.getConfiguration('snort3TestExplorer').get('sf_prefix_snort3'));
- let DEPENDENCY_DIR=vscode.workspace.getConfiguration('snort3TestExplorer').get('dependencies');
+ let DEPENDENCY_DIR=(vscode.workspace.getConfiguration('snort3TestExplorer').get('dependencies'));
let SNORT3_TEST_ROOT=executor_dir;
test_env.SNORT_LUA_PATH=SF_PREFIX_SNORT3+'/etc/snort/';
@@ -216,7 +222,7 @@ export async function loadSnort3Tests(rootdir:vscode.WorkspaceFolder)
test_env.SNORT_PREFIX=SF_PREFIX_SNORT3;
test_env.LD_LIBRARY_PATH=DEPENDENCY_DIR+'/libdaq/lib:'+SF_PREFIX_SNORT3+'/lib64:'+DEPENDENCY_DIR+'/safec/lib:'+DEPENDENCY_DIR+'/luajit/lib:'+DEPENDENCY_DIR+'/cpputest/lib64';
test_env.PKG_CONFIG_PATH=SF_PREFIX_SNORT3+'/lib64/pkgconfig:'+DEPENDENCY_DIR+'/libdaq/lib/pkgconfig:'+DEPENDENCY_DIR+'/cpputest/lib64/pkgconfig:'+DEPENDENCY_DIR+'/luajit/lib/pkgconfig:'+DEPENDENCY_DIR+'/safec/lib/pkgconfig';
- test_env.PATH=test_env.PATH+':'+SF_PREFIX_SNORT3+'/bin:'+SNORT3_TEST_ROOT+'/bin:'+DEPENDENCY_DIR+'/bin';
+ test_env.PATH=test_env.PATH+':'+SF_PREFIX_SNORT3+'/bin:'+SNORT3_TEST_ROOT+'/bin:'+DEPENDENCY_DIR+'/abcip/bin:'+DEPENDENCY_DIR+'/libdaq/bin:';
test_env.PYTHONPATH=SNORT3_TEST_ROOT+'/lib';
test_env.LUA_PATH=SF_PREFIX_SNORT3+'/include/snort/lua/\?.lua\;\;';
test_env.NFS_PCAP_DIR='/nfs/netboot/snort/snort-test/pcaps';
@@ -224,6 +230,7 @@ export async function loadSnort3Tests(rootdir:vscode.WorkspaceFolder)
test_env.SNORT_TEST_PLUGIN_PATH=SF_PREFIX_SNORT3+'/lib64';
test_env.SNORT_PLUGIN_PATH=SF_PREFIX_SNORT3+'/lib64';
test_env.SNORT3_TEST_ROOT=SNORT3_TEST_ROOT;
+ test_env.SNORT_SRCPATH=(vscode.workspace.getConfiguration('snort3TestExplorer').get('snort_srcpath'));
var snort3Tests = new Map();
const getLastItem = (thePath: string) => thePath.substring(thePath.lastIndexOf('/') + 1)