Running Tests
The library includes a set of unit tests, as well as scripts to collect performance measurements.
Running Unit Tests
The library includes unit tests (Mocha) and can be run with the following command:
~$ npm test
The test will check the core module:
PubsubCodeCodeEngineDispatcherScheduler
Each unit test can also be run individually using the command mocha <test file>:
~$ mocha require-test.js
ThingsJS library itself
Test file(s): test/require-test.js
- Require test:
require('things-js')- No error should be thrown
Code
Test file:test/Code-test.js
- No error should be thrown
- Output equivalency:
Code.run- Tests the output equivalency of instrumented
things-jscode versus raw code
- Tests the output equivalency of instrumented
Code Engine
Test file: test/CodeEngine-test.js
- Initialization:
new CodeEngine():- Code Engine instance starts up and emits a
'ready'signal
- Code Engine instance starts up and emits a
- ID assignment:
CodeEngine.id:- A unique ID is assigned to an initialized
Code Engineobject
- A unique ID is assigned to an initialized
- Pubsub assignment:
CodeEngine.pubsub- A
pubsubobject is assigned to an initializedCode Engine
- A
- Runs code:
CodeEngine.run_code- Runs a new code instance on the engine when the proper arguments are given
- Dies gracefully:
CodeEngine.killCode Engineexits and throws no errorsPubsub
Test file:test/Pubsub-test.js
- Initialization:
new Pubsub()- Pubsub instance starts up and emits a
readysignal
- Pubsub instance starts up and emits a
- ID assignment:
Pubsub.id- A unique ID is assigned to an initialized
Pubsubobject
- A unique ID is assigned to an initialized
- Subscription works:
Pubsub.subscribe- Handles single and multiple topic subscriptions
- Receives messages for a topic it is subscribed to
- Receives message in order
- Unsubscribe works:
Pubsub.unsubscribe- No longer receives messages for the topic it has unsubscribed from
- Publishes to subscribed node:
Pubsub.publish- Is able to publish data for a given topic to all node listening to the topic
- Dies gracefully on kill call:
Pubsub.killPubsubexits and throws no errors
Dispatcher
Test file: test/Dispatcher-test.js
- Initialization:
new Dispatcher()Dispatcherinstance starts up and emits areadysignal
- ID assignment:
Dispatcher.id- Dispatcher is assigned a unique ID
- Pubsub assignment:
Dispatcher.pubsub- Dispatcher is assigned a
pubsubobject
- Dispatcher is assigned a
- Correct
Code Engineview:Dispatcher.Engines- Dispatcher detects the correct number of
code engineinstances in the network
- Dispatcher detects the correct number of
- Correct
Code Enginestatuses:Dispatcher.Engines- Dispatcher detects the correct status of
idlecode engineinstances
- Dispatcher detects the correct status of
- Run code on a
Code Engine:Dispatcher.runCode, Dispatcher.engines, Dispatcher.programsCode Enginereturns a reply once code begins to execute- Dispatcher detects engines running code to have status
busy - Dispatcher detects new
programrunning - Dispatcher receives any
console outputby the new code instance
- Migration between
Code Engines:Dispatcher.moveCode,Dispatcher.enginesCode Enginereturns a reply once code migratesCode Enginethat migrates its code instance changes status toidleCode Enginethat executes migrated snapshot changes status tobusy- Migrated code executes from where it left off
- Process control:
Dispatcher.pauseCode, Dispatcher.resumeCode- A
Code Enginecan receive consecutivepauseandresumecommands - Replies are received for each
pauseorresumecommand sent
- A
Scheduler
Test file: test/Scheduler-test.js
- First fit scheduling algorithm:
Scheduler.algorithms['first_fit']- Passes the base case scenario of 0 tasks and 0 devices
- Throws an error when not enough memory exists for the given tasks and devices
- Returns a correct mapping when enough memory exists for the given tasks and devices
- Computing actions to go from one mapping to another:
Scheduler.computeActions- Computes the correct
runcommands to initialize new code instances - Computes the correct
killcommands to stop existing code instances - Computes the correct
migratecommand to move code instances
- Computes the correct
- Initialization:
new Scheduler():Schedulerinstance starts up and emits areadysignal
- ID assignment:
Scheduler.id:- Scheduler is assigned a unique ID
- Scheduler logs itself booting as its first event:
Scheduler.history- The past history is non-empty
- The first event log is the Scheduler booting
- Ignores rogue processes:
Scheduler._assess:- Does not return an error when assessing the current state of the network
- Ignores any processes without
code engineowners
- Correct network view:
Scheduler._assess:- Detects when a
Code Enginehas died - Does not fail when nodes leave the network
- Detects when a
- Handles an application request with no available devices:
Scheduler.behaviours['run_application']- Request times out
- Able to schedule an empty application (no components):
Scheduler.behaviours['run_application']- Sends back a reply over
pubsubindicating success
- Sends back a reply over
- Able to schedule an application with components on a running device:
Scheduler.behaviours['run_application']- Sends back a reply over
pubsubindicating successs
- Sends back a reply over
- Utilizes available
Code Enginesthat join network by migrating code instances:Scheduler._assess
Filesystem API
Test file: test/Filesystem-REST-test.js
- Writes a new file:
gfs.writeFile- Execution causes no error
- Read an existing file:
gfs.readFile- File name and contents match the file to be expected
- Read a non-existent file:
gfs.ReadFile- Error is thrown
- Write an existing file:
gfs.writeFile- Content is overwritten
- Append to a new file:
gfs.appendFile- New file is created with the append content
- Append to an existing file:
gfs.appendFile- The existing content is not overwritten but appended to for as long as
appendFile()is called
- The existing content is not overwritten but appended to for as long as
- Delete a non-existent file:
gfs.deleteFile- An error is thrown
- Delete an existing file:
gfs.deleteFile- The file no longer exists and cannot be read
Filesystem REST API
Test file: test/Filesystem-test.js
GET requests:- Get the
rootdirectory - Get a file from the
rootdirectory - Get a folder from the
rootdirectory - Get a file from a subdirectory
- Get the
POST requests::- Create a file in the
rootdirectory - Create a folder in the
rootdirectory - Create a file in a subdirectory
- Create a file in the
DELETE requests::- Delete a file from the
rootdirectory - Delete a non-empty folder
- Delete a file from the
Running Performance Measurement Scripts
There are scripts included that can be used to collect performance measurements. For example, we can measure the time taken to instrument input code or time taken to capture a snapshot.
~$ npm run test-script <script_name> <sample_count> <test_name>
<script_name> can be one of the following:
instrumentsnapshotrestoreexecute
<sample_count> must be a natural number greater than zero.
<test_name> is the test session name; any output generated by the test will be prefixed with this string.
Measuring Instrumentation
This script will measure the time taken to instrument a given program, and the code size change.
~$ npm run test-script instrument 100 test-01
Measuring Snapshot
This script will measure the time taken to capture a snapshot, and the snapshot size.
~$ npm run test-script snapshot 100 test-01
Measuring Restoration
This script will measure the time taken to restore a program from a given snapshot.
~$ npm run test-script restore 100 test-01
Measuring Execution
This script will collect runtime statistics such as memory and CPU usage.
~$ npm run test-script execute 3 test-01