• This repository has been archived on 14/Oct/2020
  • Stars
    star
    398
  • Rank 108,325 (Top 3 %)
  • Language
    JavaScript
  • License
    GNU Affero Genera...
  • Created over 10 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Old CodeRunner project. See https://github.com/codewars/runner instead.

ARCHIVED

Please use https://github.com/codewars/runner to report any language related issues.

About

This project was previously used by Codewars and Qualified.io to execute small sets of code within various languages, using various testing frameworks. Each time code is run, it is executed within a Docker container in order to secure unsafe code execution.

All execution is done within Docker, with a Node CLI app contained within each container that manages the code execution for that specific language environment and returns the result via stdout.

Contributions

This project has been open-sourced so that the Codewars and Qualified communities can contribute support for new languages and frameworks. See the Language Support Status section for more information regarding which languages are currently supported and where their Codewars/Qualified support has been added.

Basic Usage

Within each Docker image, there is a copy of the Node executable and a run script. That script accepts multiple options for executing code. For example to run a simple javascript script which would output 2:

# this is how you run the Node CLI. For this to work you would have to bash into the correct Docker image
node run -l javascript -c "console.log(1+1)"

Because everything runs inside of Docker, you would normally not run Node directly from your host but instead via a Docker run command. To do this, you would either bash into the correct Docker image like so:

# direct Docker call:
docker run --rm -it --entrypoint bash codewars/node-runner

# alternatively you can use the provided Docker Compose configuration:
docker-compose run node-runner

Or you could choose to execute the code outside of Docker by creating a container that will remove itself after it executes:

# direct Docker call:
docker run --rm codewars/node-runner run -l javascript -c "console.log('I ran inside of Docker using NodeJS')"
docker run --rm codewars/ruby-runner run -l ruby -c "puts 'I ran inside of Docker using Ruby'"

# alternatively you can use the provided Docker Compose configuration:
docker-compose run javascript -c "console.log('I ran inside of Docker using NodeJS')"
docker-compose run ruby -c "puts 'I ran inside of Docker using Ruby'"

Integrated Test Suites

The most significant aspect of this project is that integrated test support is built in to many languages. This is how Codewars and Qualified work, instead of testing STDOUT of a program, the executed code is tested using traditional code testing methods, with unit-tests and language-specific testing frameworks.

Here is a very simple example of running tests using the simplified Codewars testing framework.

# manually running docker
docker run --rm codewars/node-runner run -l javascript -c "var a = 1;" -t cw -f "Test.assertEquals(a, 1)"

# using docker compose
docker-compose run javascript -c "var a = 1;" -t cw -f "Test.assertEquals(a, 1)"

Which would output <PASSED::>Test Passed: Value == 1 to STDOUT.

Language Support Status

Many languages are currently supported in various states of completeness. This list tries to keep track of each.

Legend: !!! = Failing Specs, ??? = Status is unknown, * = Any

Language Version Basic Run Project Mode Test Integration Codewars Qualified Docker Image Examples Notes
Assembly (GAS) !!! systems-runner Travis is failing, tests pass locally
Bash βœ“ βœ“ rspec rspec rspec ruby-runner
Brainf**k 20041219 βœ“ βœ“ cw-2 cw-2 esolangs-runner
C Clang 3.6/C11 βœ“ criterion criterion systems-runner
Clojure 1.8.0 βœ“ clojure.test clojure.test clojure.test jvm-runner clojure.test
CoffeeScript 1.10.0 βœ“ cw-2 cw-2 cw-2 node-runner cw-2
C++ 14 βœ“ igloo igloo igloo systems-runner
C# Mono 4.8 βœ“ βœ“ nunit nunit nunit dotnet-runner nunit
Chapel 1.15.0 βœ“ βœ“ cw-2 cw-2 chapel-runner cw-2
Crystal 0.21.1 βœ“ spec spec spec crystal-runner spec
Dart 1.23.0 βœ“ test test dart-runner test
Elixir 1.2.4 βœ“ exunit exunit elixir-runner
Erlang 20.0 βœ“ eunit erlang-runner
F# 4.1 βœ“ fuchu fuchu dotnet-runner Fuchu Tests should be placed in a module called "Tests", in a Fuchu testList
Go 1.8 βœ“ ginkgo ginkgo ginkgo go-runner ginkgo
Groovy 2.4.12 βœ“ junit4,spock gradle-runner
Haskell 7.10.3 βœ“ hspec!!! hspec hspec haskell-runner hspec An older version is running on CW & Qualified that is fully functional
Java 1.8.0_91 βœ“ junit junit junit java-runner junit
JavaScript 0.10.33 βœ“ βœ“ cw-2 cw-2 cw-2, node-runner cw-2
JavaScript 0.10.33/Babel βœ“ βœ“ cw-2 cw-2 cw-2, node-runner cw-2
JavaScript 6.11.0 βœ“ βœ“ cw-2, mocha cw-2 cw-2, mocha node-runner cw-2
JavaScript 6.11.0/Babel βœ“ βœ“ cw-2, mocha cw-2 cw-2, mocha node-runner cw-2
JavaScript 8.1.3 βœ“ βœ“ cw-2, mocha cw-2 cw-2, mocha node-runner cw-2
JavaScript 8.1.3/Babel βœ“ βœ“ cw-2, mocha cw-2 cw-2, mocha node-runner cw-2
Julia 0.4.6 βœ“ factcheck factcheck
Kotlin 1.1.4 βœ“ junit4,kotlintest gradle-runner
Lisp βœ“ Kumite Only func-runner
Lua 5.2 βœ“ busted busted lua-runner
Objective-C 2.0 βœ“ UnitKit UnitKit objc-runner
OCaml 4.02.3 βœ“ ounit ounit ocaml-runner Tests should be placed in a module called "Tests", in an array of OUnit labels named "suite"
Perl βœ“ Kumite Only *
PHP 7.0 βœ“ cw-2, phpunit phpunit phpunit, cw-2 alt-runner
PowerShell 6.0.0-beta.4 βœ“ Pester powershell-runner Pester
Python 2.7.6 βœ“ βœ“ cw-2, unittest cw-2 cw-2, unittest python-runner cw-2
Python 3.4.3 βœ“ βœ“ cw-2, unittest cw-2, unittest python-runner cw-2
Python 3.6 βœ“ βœ“ cw-2, unittest cw-2, unittest python-runner cw-2
R 3.4.1 βœ“ testthat r-runner
Racket βœ“ Kumite Only func-runner
Ruby 2.3.0 βœ“ βœ“ cw-2, rspec cw-2 cw-2, rspec ruby-runner cw-2
Rust 1.15.1 βœ“ rust rust
Scala 2.12.3 βœ“ junit4,scalatest gradle-runner
Scss/Sass ??? ???
SQL SQLite3 βœ“ βœ“ rspec
SQL Postgres 9.6 βœ“ βœ“ rspec
Swift 3.1.1 βœ“ xctest xctest
TypeScript 2.4 βœ“ mocha mocha node-runner TypeScript utilizes require instead of concatenating files

Setup

You should have Docker installed, if not do that first. Before you can run any of the code environments you will need to build the proper Docker image. To get started lets work with the node image.

Run make node to build the base and node images. This will take a few minutes. You can speed up the process by first downloading the existing images that you intend to work on, which will allow you to only need to build when you make a change.

For example, if you intend to work on the jvm image, you would do this:

# download existing images first to greatly speed up time
docker pull codewars/base-runner
docker pull codewars/jvm-runner

# now build the jvm image, so that any recent changes that have may not have been pushed yet get added into the image
make jvm

Once you image is downloaded/built, you can create a container to work within it. Doing this means you do not have to worry about having any of the project dependencies loaded directly on your machine.

Run the following command:

docker run \
    -it \
    --rm \
    --entrypoint bash \
    -v $(pwd)/lib:/runner/lib \
    -v $(pwd)/examples:/runner/examples \
    -v $(pwd)/frameworks:/runner/frameworks \
    -v $(pwd)/test:/runner/test \
    codewars/node-runner

This will create a new container and send you into the instance with your project's lib and test directories mounted as volumes. Mounting as a volume allows you to change files on your local machine and have those changes available to you from within the container.

Notice: We did not mount the entire directory because that would overwrite things such as your node_modules directory. If you need to update these you should make {image_you_want_to_update} the image to ensure you are always testing against the correct packages.

Docker Compose

We mentioned before that you also have the option of using Docker Compose to run the CLI tool. We have setup the docker-compose.yml file to provide very useful pre-configured services for making development easier. Instead of having to issue the long command mentioned above, you can simply run docker-compose run node-runner to bash into a fresh container with your local volumes already mounted.

All of the docker compose services are setup to mount volumes to make development easier, so that is the recommended way of interacting with the codebase. You should note though that the compose file is unable to build images due to how the directory structure is laid out, so you have to first make {runner_name} the image before you can run it. Otherwise it will pull down the latest copy from Docker Hub.

Running Tests

Once you are in the Docker image, you can run tests as a part of your development flow. For example:

# inside of container
mocha test/runners/typescript_spec.js

# or from outside the container
docker-compose run typescript_test

Test Suite Output Format

A custom and very basic format is used for sending data out of the CLI tool. All formatted data is returned via STDOUT. If you do nothing but write normal strings to STDOUT, then codewars.com will display each line as you would expect, unformatted.

A small subset of commands is supported that can be used to format output. They are:

  • <DESCRIBE::>
  • <IT::>
  • <PASSED::>
  • <FAILED::>
  • <ERROR::>
  • <COMPLETEDIN::>

Prefixing a new line with these commands will cause that line to be formatted. Since each new STDOUT line is considered a new piece of data, if you wish to format multiple lines as one item (such as a multi line "passed" message), then you must replace all \n line feed characters with the <:LF:> token.

For example, in Ruby, if you wanted to write a multi-line passed message:

def passed(msg)
  puts "<PASSED::>#{msg.gsub("\n", "<:LF:>")}"
end

Nested Describes

Some test frameworks support nested levels of describes. In order for our output to support multiple levels, you must also use the <COMPLETEDIN::> token, which acts as a terminator for the current item. This should be used to terminate both <DESCRIBE::> and <IT::> statements.

The following is a full example of what the output might look like, that supports nested describes:

<DESCRIBE::>Foo
<IT::>It should return a string
<PASSED::>Test Passed
<COMPLETEDIN::>23
<IT::>It should return "foo"
This is some direct output (i.e. console.log("..."))
<FAILED::>Expected "foo" but instead got ""
<COMPLETEDIN::>10
<DESCRIBE::>This is a nested describe
<IT::>Should not be null
<PASSED::>Test Passed
<COMPLETEDIN::>20
<COMPLETEDIN::>22
<COMPLETEDIN::>100

Notice how there are 3 <COMPLETEDIN::> statements at the end. The first one completes the last IT statement, the 2nd completes the nested DESCRIBE and the 3rd completes the top level "Foo" DESCRIBE.

COMPLETEDIN:: Details

The value of COMPLETEDIN should be time spent executing the related statement, in milliseconds. It is not required to support time. <COMPLETEDIN::> is valid on its own, and in that case it is only used to terminate the current statement.

Why the custom format?

Getting different test suites in different languages to all play together with the same format can be tricky. In many cases, customizing the test suite output is very limited (sometimes requiring hacking). Because of this, using formats such as XML and JSON are complicated because its not always possibly to correctly close out the data format when a program raises an exception.

The format chosen was originally done so that at any point in time the program could exit while still having readable data. Other formats, such as TAP (Test Anything Protocol) could also be an option. However another requirement that we had when designing the format was to have it be incredibly simple yet flexible, so that Codewars.com could support more than simply outputting test results. With the current format there is nothing stopping you from outputting HTML, JS canvas code, etc in order to create a rich and even interactive test result output.

How to add a new language

Note: These steps all assume you are adding a completely new language to the project. Many languages are currently in an incomplete state so not all steps may be needed in your case

  1. Install the language and its related packages on one of the Docker images. We have grouped many of the Docker images together so if that grouping makes sense then add it there, otherwise you will need to create a new docker image within the docker folder
  2. Add the newly created docker file to the Make and docker-compose files (if applicable)
  3. Add a new runner script within lib/runners. More details about this script later on.
  4. Add a new runner spec within test/runners. You will also need to add the runner spec to the Docker image so that it is tested as a part of the build process.
  5. Add a new examples yml file within the examples folder. These are the code examples that are used on Codewars.com when a user clicks the "Insert Example" button within the kata editor. There is also a helper available for running your examples as a part of the test suite.

Runner Script

The runner script is responsible for outputting a run method. This method utilizes the shovel helper which will handle all of the inter-process communication for you. The shovel config accepts strategies to determine how to handle running the code based on the options passed in. There are currently two types of strategies.

  • solutionOnly: Code is simply executed and its STDOUT returned. There is no test integration.
  • testIntegration: Code is executed within a configurable test suite and the test output is returned via STDOUT.

Each of these strategies is passed in a run method which is used to ultimately execute the final command.

More Repositories

1

codewars.com

Issue tracker for Codewars
2,040
star
2

python-test-framework

Codewars test framework for Python
Python
57
star
3

docs

The Codewars Docs 🚧 WIP
MDX
47
star
4

kata-test-framework-js

The framework used by Codewars for testing kata
JavaScript
32
star
5

runner

Issue tracker for Code Runner
29
star
6

codewars-api-docs

Codewars API v1 Docs
JavaScript
23
star
7

discord-bot

Codewars Discord Bot
TypeScript
22
star
8

lambda-calculus

Lambda Calculus compiler for Codewars
JavaScript
16
star
9

content-issues

Higher level issue tracker for the Codewars content.
14
star
10

noderunner

CoffeeScript
13
star
11

blog

The Codewars Blog
HTML
9
star
12

kata-test-framework-ruby

A version of the kata framework that is used within codewars.com
Ruby
9
star
13

kata-test-framework-haskell

codewars.com kata test framework for the Haskell language
Haskell
7
star
14

code-grouper

Used by www.codewars.com to group similar kata solutions together.
Ruby
6
star
15

codemirror-agda

Agda mode and input helper for CodeMirror used on Codewars
TypeScript
6
star
16

riscv

Container image for RISC-V
C
5
star
17

python-unittest

Python unittest runner with Codewars output
Python
5
star
18

testbox-codewars

Custom TestBox reporter and runner for Codewars
ColdFusion
5
star
19

ttester-codewars

"Testest" Forth Test Framework for Codewars
Forth
4
star
20

deprecated-codewars-docker

[Deprecated] Docker sandboxes for code katas in various languages.
JavaScript
4
star
21

codemirror-riscv

RISC-V mode for CodeMirror
JavaScript
4
star
22

tmp-snippets

A temporary repository to allow contributions to kata examples and kumite templates.
3
star
23

coq_codewars

A Coq plugin for Codewars
OCaml
3
star
24

kata-test-framework-java

offline kata framework, in java, used for codewars.com
Java
3
star
25

tags

Tag definitions
TypeScript
3
star
26

rust-devcontainer

devcontainer for solving Rust kata locally
Rust
3
star
27

testest

Vocabulary to test Factor code on Codewars
Factor
3
star
28

codemirror-unicode-helper

CodeMirror extension for entering Unicode characters with ASCII sequences. Defaults to LaTeX-like abbreviations.
TypeScript
3
star
29

marked-extensions

JavaScript
2
star
30

coq

Container image for Coq
Dockerfile
2
star
31

branding

Branding assets for Codewars
2
star
32

ginkgo

Custom reporter for Ginkgo
Go
2
star
33

batcan

Heroic authorizations system for ruby. Both simple and highly flexible.
Ruby
2
star
34

sql_spec_helper

Spec helper for SQL challenges
Ruby
1
star
35

ruby-test-framework

Codewars test framework for Ruby
Ruby
1
star
36

fortran-test-framework

Codewars test framework for Fortran
Fortran
1
star
37

busted-codewars

Codewars output handler for Busted
Lua
1
star
38

coderunner-elixir

1
star
39

fsharp

Container image for F#
F#
1
star
40

raku-tap2codewars

Transforms piped TAP to Codewars output
Raku
1
star
41

codewars-rackunit

RackUnit test runner for Codewars
Racket
1
star
42

codemirror-lambda-calculus

Lambda Calculus mode for CodeMirror
HTML
1
star
43

factor

Container image for Factor
Dockerfile
1
star
44

cobol-test

Codewars test framework for COBOL
COBOL
1
star
45

haskell

Container image for Haskell
Dockerfile
1
star
46

purescript

Container image for PureScript
PureScript
1
star
47

javascript-test-compat

Provides functions from the deprecated custom test framework
TypeScript
1
star
48

kata-clusters

Visualization of the Codewars kata library
JavaScript
1
star