Giter Club home page Giter Club logo

bokor's Introduction

Bokor

npm version

Bokor project is no longer maintained and set to read-only. Feel free to fork as needed!

Bokor is a simple, Record and Playback Mock Server written in Node.js, utilized for Service Virtualization.

Bokor is very similar to the many VCR-like tools out there today, but prides itself on its ease of use and speed to setup. It can be utilized for any mocking needs, but was primarily developed for mocking back end service calls in automated UI testing.

Bokor was developed and is in use at Nike since early 2016. There, it is used to improve the speed, reliability and test coverage of the integration and user interface test suites for native mobile applications.


Installation

Install Node JS

$ npm install bokor

Usage

Create server.js file

var serversProperties = require('./servers.properties');
var filtersProperties = require('./filters.properties');

var bokor = require('bokor');

bokor.start({
servers : serversProperties,
filters : filtersProperties
});

Server Configuration

Create servers.properties file

The servers.properties file is utilized to configure what servers will be proxied. The url_filter field utilizes regular expressions to determine which requests to proxy and the url field instructs Bokor which base url to proxy the request to.

var servers = {
   server1: {
        url_filter: '*/users*',
        url: 'api.github.com',
    },
    server2: {
        url_filter: '/unique-url-filter-here/*',
        url: 'url-your-application-uses',
    }
};

module.exports = servers;

Filter Configuration

Create filters.properties file

Both the URL and the request body, if present, are used to generate the filename for fixtures. The latter is used to differentiate between two POST or PUT requests pointing to the same URL but differing only in the request body.

Sometimes, a request contains data in the URL that is necessary for the successful execution of that request, but changes from repeated invocations of that resource. One typical example is a timestamp; another is a uniquely generated request ID. However, sometimes two requests that have all other parts of the request aside from these parameters constant should be considered the same for recording and playback purposes.

Suppose that your tests make the following request:

http://example.com/client-config?user_id=444444321

and while the user_id query parameter is required for the request to complete, you want to playback the same data that was recorded, regardless of what user_id was used during recording and during playback. Use a URL filter like filter2 below.

The url_filter field is used to determine which requests should have regx applied to it. The matcher is a regex. The filter is only applied to determine which fixture will be used; the actual request made to the remote resource during recording is unchanged.

var filters = {
    filter1: {
        description: 'DO NOT REMOVE-ignores the access token on ALL requests',
        url_filter: /[\w]+/,
        regx: /access_token=[\w]+/,
        replace: '',
    },
   filter2: {
        description: 'EXAMPLE-ignores user_id on all requests to client-config',
        url_filter: /client-config/,
        regx: /&user_id=[0-9]+/,
        replace: '',
    },
    filter3: {
        description: 'EXAMPLE-ignores os version on all requests to client-config',
        url_filter: /client-config/,
        regx: /os_version=[\/\d*\.\d*]+/,
        replace: '',
    },
    filter4: {
        descripton: 'EXAMPLE-replaces all version call with 1.0.0 call',
        url_filter: /client-config/,
        regx: /com.example.ios\/\d*\.\d*.\d*/,
        replace: 'com.example.ios/1.0.0',
    },
};

module.exports = filters;

Run server

$ node server.js
bokor server rolled lucky 7777

Command Line

Bokor can be run through the command line using the bokor command.

npm i -g bokor

$ bokor --help                                                                    ⬡ 8.9.1 [±feature/cli ●●]
Usage:
  node bokor [OPTION]

  Options:
    -p, --port      port of the bokor server [7777]
    -f, --filters   file exporting filters.properties
    -s, --servers   file exporting servers.properties
    -d, --datetimes file exporting datetimes.properties
    -h, --help      display this help

Advanced Configuration

Relative Date Time Objects

Often we find the need to have date time results relative from the current date time. For example; "5 minutes from now" or "Exactly 3 days from now". With Bokor you can manipulate your recorded date time values in any possible way you can imagine.

Create datetimes.properties file

First create a key name that is meaningful like: NOW_DATETIME_UTC. Next utilizing the Moment.JS library create your javascript function that will manipulate the date time to your needs like: moment().utc().format(), making sure to escape any single quotes.

var datetimes = {
    datetime1: {
        key: 'NOW_DATETIME_UTC',
        value: 'moment().utc().format()',
    },
   datetime2: {
        key: 'NOW_DATETIME_UTC_PLUS_10_MINUTES',
        value: 'moment().utc().add(10, \'m\').format()',
    }
};
module.exports = datetimes;
Add the date time configuration to the server.js file.
var serversProperties = require('./servers.properties');
var filtersProperties = require('./filters.properties');
var datetimesProperties = require('./datetimes.properties');

var bokor = require('bokor');

bokor.start({
servers : serversProperties,
filters : filtersProperties,
datetimes : datetimesProperties
});

Once you have completed the configuration modify your recorded data fixtures, by replacing date time values with a the key values you created. Bokor will dynamically create date time values the next time you request that data fixture.

Static Resources

By default Bokor serves any static resource in the static_files folder. You can modify this folder name by adjusting the server config.

bokor.start({
servers : serversProperties,
filters : filtersProperties,
staticFileLocation: customFolder
});

Admin Server

By default Bokor runs an admin server on port 58080. If you do not need this feature you can turn off the admin server by adjusting the server config.

bokor.start({
servers : serversProperties,
filters : filtersProperties,
admin: false
});

Port

By default Bokor runs on port 7777. You can modify this port by adjusting the server config.

bokor.start({
servers : serversProperties,
filters : filtersProperties,
port: 1234
});

Secure

By default Bokor checks a services SSL cert and will fail if the cert is self-signed / invalid CA. You can modify this behavior by adjusting the server config.

bokor.start({
servers : serversProperties,
filters : filtersProperties,
secure: false,
});

Data Fixtures

Data Bins

Bins give Bokor the ability to respond differently to the exact same request. A series of downstream requests can be isolated, and their fixtures stored in a separate directory.

All recorded data will be stored in a top level folder called bins. By default all recorded fixtures will be stored in the bins\default folder.

Change Default Bin

Admin Server Method

Bokor runs an internal admin server on port 58080 that allows you to change the bin Bokor is reading and writing to.

To change from the bins\default bin make a post to the internal server bokor is running. Run the below command to have Bokor configured to bins\sampleBinName.

$ curl -H "Content-Type: application/json" -X \
POST -d '{"testName": "sampleBinName"}' \
http://localhost:58080/testOptions

This changes the global state of the Bokor server and all requests will go through this bin.

Header Method

Using the header method allows the Bokor server to respond to simultaneous requests from different bins.

To do this you must modify the header of every request proxied through the Bokor server. Add a header with the name of: x-bokor-test-name and the value of binName to each network request. Bokor will read the request headers and use the specified bin to determine the response.

Fixture Filenames

Fixture data generated during the recording phase are stored in files. In order to uniquely associate each HTTP request with a filename used to store the fixture data, several characteristics of the request are examined:

  • The HTTP method, e.g. GET or POST.
  • The request URL.
  • The request body.
  • The names of all the request headers.
  • The names of all the cookies sent in the request.

This data is then aggregated and sent through an MD5 hash to produce the filename.

Static Resources

Bokor provides the ability to host static content. Just store files in your static resources directory and request them from the root of the Bokor server. http://localhost:7777/bokor.jpg

bokorServer/
+-- bins
+-- static_files
    +-- bokor.jpg
    +-- test.json
+-- server.js
+-- filters.properties
+-- servers.properties

Logs

Bokor uses Bunyan for logging. Bunyan is a simple and fast JSON logging library. Bunyan has many features. One of them allows pretty-printing of the log. We show this feature in the below Demo From Source

(cache=miss)

❤️ If the request does not find a prerecorded response it will log cache miss.

(cache=hit)

💚 If the request finds a prerecorded response it will log cache hit.

Demo from Source

Follow the below steps to run the Bokor Demo.

$ git clone https://github.com/Nike-Inc/bokor.git
$ cd bokor
$ npm install
$ cd examples/source_example/
$ node server.js | ../../node_modules/.bin/bunyan

Record a response

$ curl http://localhost:7777/users/jimmyeisenhauer

Playback the response (notice the improved response time)

$ curl http://localhost:7777/users/jimmyeisenhauer

Tests

$ npm run coverage

FAQ

Where did the name Bokor come from?

It is a long story, but one of my favorite quotes is:

“any sufficiently advanced technology is indistinguishable from magic.”

-arthur c. clarke

So of course I penned a similar quote around test automation.

“software tests that unexplainably pass or fail are indistinguishable from voodoo.”

-james r. eisenhauer

And a Bokor is a voodoo sorcerer for hire who are said to serve the loa 'with both hands', practicing for both good and evil.

License

Bokor is released under the Apache 2.0 license. See LICENSE for details.

Creators

Special thanks to Ben Williams for leading the efforts to have Bokor open sourced. Also thanks to the Sepia team for their code and inspiration.

bokor's People

Contributors

austinmcorso avatar dependabot[bot] avatar desertblade avatar jimmyeisenhauer avatar kination avatar thgaskell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bokor's Issues

Show how to do a cohesive demo using a http://todobackend.com/ test harness

Refer the fantastic http://todobackend.com/ comparison portal.
The web.py example is pretty self contained.

Your demo should be a (fill in the blanks) version of this:

git clone [email protected]:moredip/todo-backend-py.git 
cd todo-backend-py/
pip install web.py 

(Setup Bokor to record here)

python todo-backend.py 

Launch tests in browser, via http://todobackend.com/specs/index.html?https://localhost:8080

Stop the todo-backend.py server
stop Bokor
(inspect captured traffic)

Then .. instructions as to how to play back and pass the same test-harness suite.

Be aware though that the author set up web.py incorrectly, and you might need to find the python process in ps aux to kill it if control-c isn't responding.

Do you have thoughts on adding a CLI?

Great tool.

I was thinking if there is thought or a roadmap to add a cli for Bokor.
The simple use case that is would solve would be not needing a seperate bokor/index.js file, when using bokor whenever using a "default" scructure.

In an app you need to start the dev server (typically) and then start the bokor server which most of the time takes in default files.
i.e. "start:bokok": "npm run start:dev && node bokor

At some point it would be nice if we could add a cli option that would allow us to simply run
"start:bokok": "npm run start:dev && bokor
The cli would use default file path and names unless args to overwrite some of those values was passed in.

TypeError: proxyReq.getHeader is not a function

When running a curl command through bokor I am receiving the following error:

 if(server && !proxyReq.getHeader('expect')) {
                             ^
TypeError: proxyReq.getHeader is not a function

Digging into it the dependency http-proxy was updated in May (https://github.com/http-party/node-http-proxy/pull/1447/files) which is causing the issue.

Downgrading the package resolves issue: npm install [email protected]

This solution is not ideal due to DOS vulnerability: https://www.npmjs.com/advisories/1486

The error is coming out of the Sepia packages /bokor/lib/sepia/src/cache.js:253:13)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.