Skip to content

Commit

Permalink
Merge pull request #23 from robertzk/acceptance_tests
Browse files Browse the repository at this point in the history
Acceptance tests
  • Loading branch information
kirillseva committed Jul 5, 2016
2 parents 036bcc2 + 6d12ec1 commit 8aba0f7
Show file tree
Hide file tree
Showing 27 changed files with 179 additions and 37 deletions.
4 changes: 4 additions & 0 deletions .Rbuildignore
@@ -1 +1,5 @@
.travis.yml
^node_modules
^test
^package.json$
^README.md
2 changes: 2 additions & 0 deletions .gitignore
@@ -1,3 +1,5 @@
*.tar.gz
..Rcheck
*.Rcheck
node_modules
npm-debug.log
27 changes: 11 additions & 16 deletions .travis.yml
@@ -1,16 +1,15 @@
language: c
language: r
sudo: false
warnings_are_errors: false
cache:
packages: true
directories:
- node_modules
before_install:
- curl -OL http://raw.github.com/craigcitro/r-travis/master/scripts/travis-tool.sh
- chmod 755 ./travis-tool.sh
- "./travis-tool.sh bootstrap"
install:
- "./travis-tool.sh install_deps"
- "./travis-tool.sh install_r microbenchmark knitr testthat httpuv json jsonlite"
- "./travis-tool.sh github_package jimhester/covr"
- "./travis-tool.sh github_package robertzk/testthatsomemore"
script: "./travis-tool.sh run_tests"
after_failure:
- "./travis-tool.sh dump_logs"
- npm install
script:
- Rscript -e 'ch <- devtools::check(); ts <- as.data.frame(devtools::test()); q(save="no", status = !as.logical(ch) || any(ts$failed | ts$error))'
- npm run test
after_success:
- "Rscript -e 'library(covr);coveralls()'"
notifications:
Expand All @@ -25,7 +24,3 @@ notifications:
template:
- "%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message}
| Details: %{build_url} | Changes: %{compare_url}"
env:
- global:
- WARNINGS_ARE_ERRORS=1
- _R_CHECK_FORCE_SUGGESTS_=0
9 changes: 6 additions & 3 deletions DESCRIPTION
Expand Up @@ -13,11 +13,14 @@ Depends:
R (>= 3.0.1)
Imports:
httpuv,
jsonlite
jsonlite,
methods
Suggests:
testthat,
covr,
testthatsomemore,
microbenchmark,
knitr
roxygen2
Remotes: robertzk/testthatsomemore@0.2.5
License: MIT + file LICENSE
LazyData: true
RoxygenNote: 5.0.1.9000
4 changes: 3 additions & 1 deletion NAMESPACE
@@ -1,6 +1,8 @@
# Generated by roxygen2 (4.1.1): do not edit by hand
# Generated by roxygen2: do not edit by hand

export(microserver_response)
export(run_server)
import(httpuv)
import(jsonlite)
importFrom(methods,as)
importFrom(stats,setNames)
1 change: 1 addition & 0 deletions NEWS.md
@@ -1,5 +1,6 @@
# Version 0.1.2

* Acceptance tests.
* JSON responses are now returned with `Content-Type: application/json`
instead of `Content-Type: text/json`.

Expand Down
2 changes: 2 additions & 0 deletions R/microserver-package.r
Expand Up @@ -5,4 +5,6 @@
#' @name microserver
#' @docType package
#' @import httpuv jsonlite
#' @importFrom methods as
#' @importFrom stats setNames
NULL
9 changes: 9 additions & 0 deletions R/utils.r
Expand Up @@ -83,3 +83,12 @@ common_type <- function(x) {
else if (length(unique(types)) == 1) { types[1] }
else { NA }
}

packagefile <- function(file, ..., read = FALSE) {
file <- system.file(file, ..., package = "microserver")
if (isTRUE(read)) {
paste(collapse = "\n", readLines(file))
} else {
file
}
}
18 changes: 17 additions & 1 deletion README.md
Expand Up @@ -5,14 +5,30 @@ Minimal R server mimicking Ruby's Sinatra gem.

# Installation

This package is not yet available from CRAN (as of October 5, 2015).
This package is not yet available from CRAN (as of July 5, 2016).
To install the latest development builds directly from GitHub, run this instead:

```r
if (!require("devtools")) install.packages("devtools")
devtools::install_github("robertzk/microserver")
```

# Testing

Running unit tests is simple: just run `devtools::test()` in your R console.

For acceptance tests, we rely on [mocha](https://mochajs.org/) and [chai](http://chaijs.com/). Both
of these tools come from the javascript world. In order to run acceptance tests
locally make sure you have `node` and `npm` installed. If both of these requirements
are satisfied then just run

```sh
npm install
npm run test
```

in the root of this repository.

# Usage

```r
Expand Down
5 changes: 5 additions & 0 deletions inst/routes.R
@@ -0,0 +1,5 @@
list(
"/ping" = function(...) "pong"
, "/parse_query" = function(p, q) { list(query = q) }
, function(...) list(exception = "catch all route")
)
6 changes: 6 additions & 0 deletions inst/simple_server.R
@@ -0,0 +1,6 @@
library(methods)
devtools::load_all()

routes <- source(microserver:::packagefile('inst/routes.R'))$value
cat('listening..\n')
microserver::run_server(routes, 33399)
2 changes: 1 addition & 1 deletion man/determine_route.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions man/extract_params_from_request.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions man/extract_query_from_request.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/http_server.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/is.microserver_response.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/microserver.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/microserver_response.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/run_server.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/simplify_homogeneous_lists.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions package.json
@@ -0,0 +1,24 @@
{
"name": "microserver",
"version": "0.1.2",
"description": "Acceptance tests for github.com/robertzk/microserver",
"main": "",
"scripts": {
"test": "./node_modules/.bin/mocha --delay"
},
"repository": {
"type": "git",
"url": "git+https://github.com/robertzk/microserver.git"
},
"author": "Kirill Sevastyanenko <kirillseva@gmail.com> (http://github.com/kirillseva)",
"license": "MIT",
"bugs": {
"url": "https://github.com/robertzk/microserver/issues"
},
"homepage": "https://github.com/robertzk/microserver#readme",
"dependencies": {
"chai": "^3.5.0",
"chai-http": "^3.0.0",
"mocha": "^2.5.3"
}
}
72 changes: 72 additions & 0 deletions test/smoke.js
@@ -0,0 +1,72 @@
'use strict';

var chai = require('chai')
, chaiHttp = require('chai-http')
, spawn = require('child_process').spawn
, PORT = 33399
, should = chai.should();

chai.use(chaiHttp);

var base_url = 'http://localhost:' + PORT;

var microserver = spawn('Rscript', [process.cwd() + '/inst/simple_server.R']);
microserver.on('data', function (data) {
console.log('stdout: ' + data);
});
microserver.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
microserver.on('close', function (code, signal) {
console.log('R process exited with code ' + code + ' by signal ' + signal);
});
microserver.on('error', function (err) {
console.log('Failed to start child process.');
});

setTimeout(
function() {
describe('microserver', function() {
after(function() {
microserver.kill()
});
it('should pong on a /ping', function(done) {
chai.request(base_url)
.get('/ping')
.end(function(err, res) {
should.not.exist(err);
res.should.have.status(200);
res.body.should.equal('pong');
done();
});
});
it('should use a catch all route on other requests', function(done) {
chai.request(base_url)
.get('/foo')
.end(function(err, res) {
should.not.exist(err);
res.should.have.status(200);
res.type.should.equal('application/json');
res.body.exception.should.equal('catch all route');
done();
});
});
it('can parse query parameters', function(done) {
var query = { name: 'foo', limit: 1 }
chai.request(base_url)
.get('/parse_query')
.query(query)
.end(function(err, res) {
should.not.exist(err);
res.should.have.status(200);
res.body.query.name.should.equal(query.name);
console.log(res.body);
res.body.query.limit.should.equal(query.limit.toString());
done();
});
});
});
run();
},
2000 // allow R server to start
);
Empty file modified tests/testthat.R 100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions tests/testthat/test-request.r 100644 → 100755
@@ -1,5 +1,5 @@
library(testthatsomemore)
context('extract_params_from_request')
context('extract params from request')

test_that('it returns NULL for an empty example', {
request <- list(rook.input = list(read_lines = function() ''))
Expand All @@ -18,7 +18,7 @@ test_that('it returns the correct parameter list for a simple correct example',
list(example = "JSON", number = 5, numeric = c(1,2), list = list(1, 'a')))
})

context('extract_query_from_request')
context('extract query from request')

test_that('it returns NULL for an empty query', {
expect_identical(extract_query_from_request(list(QUERY_STRING = NULL)), NULL)
Expand Down
Empty file modified tests/testthat/test-response.r 100644 → 100755
Empty file.
3 changes: 2 additions & 1 deletion tests/testthat/test-routes.r 100644 → 100755
@@ -1,5 +1,6 @@
library(testthatsomemore)
context("determine_route")
library(methods)
context("determine route")

test_that("it determines the root 404 route for a trivial example", {
expect_identical(determine_route(list(), "")()$status, 404)
Expand Down
Empty file modified tests/testthat/test-utils.R 100644 → 100755
Empty file.

0 comments on commit 8aba0f7

Please sign in to comment.