omnitest 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.gitmodules +0 -0
- data/.groc.json +7 -0
- data/.rspec +6 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +47 -0
- data/.travis.yml +12 -0
- data/.yardopts +3 -0
- data/Gemfile +26 -0
- data/README.md +341 -0
- data/Rakefile +33 -0
- data/appveyor.yml +9 -0
- data/bin/omnidoc +5 -0
- data/bin/omnitask +5 -0
- data/bin/omnitest +5 -0
- data/bower.json +21 -0
- data/doc-src/index.md.tt +341 -0
- data/doc-src/project_sets.md.tt +31 -0
- data/doc-src/usage/crosstask.md.tt +86 -0
- data/doc-src/usage/omnitest.md.tt +87 -0
- data/features/bootstrapping.feature +25 -0
- data/features/cloning.feature +32 -0
- data/features/fixtures/configs/omnitest_sample.yaml +11 -0
- data/features/fixtures/configs/skeptic_empty.yaml +12 -0
- data/features/fixtures/configs/skeptic_hello_world.yaml +10 -0
- data/features/show.feature +38 -0
- data/features/states.feature +40 -0
- data/features/step_definitions/sdk_steps.rb +22 -0
- data/features/support/env.rb +9 -0
- data/lib/omnitest.rb +211 -0
- data/lib/omnitest/cli.rb +297 -0
- data/lib/omnitest/command.rb +103 -0
- data/lib/omnitest/command/generate.rb +29 -0
- data/lib/omnitest/command/generators/code2doc.rb +79 -0
- data/lib/omnitest/command/generators/dashboard.rb +148 -0
- data/lib/omnitest/command/generators/documentation.rb +119 -0
- data/lib/omnitest/command/list.rb +62 -0
- data/lib/omnitest/command/project_action.rb +26 -0
- data/lib/omnitest/command/scenario_action.rb +20 -0
- data/lib/omnitest/command/show.rb +148 -0
- data/lib/omnitest/command/task.rb +27 -0
- data/lib/omnitest/command/test.rb +41 -0
- data/lib/omnitest/configuration.rb +53 -0
- data/lib/omnitest/documentation_generator.rb +68 -0
- data/lib/omnitest/project.rb +100 -0
- data/lib/omnitest/project_logger.rb +273 -0
- data/lib/omnitest/project_set.rb +47 -0
- data/lib/omnitest/reporters.rb +27 -0
- data/lib/omnitest/reporters/hash_reporter.rb +32 -0
- data/lib/omnitest/reporters/json_reporter.rb +12 -0
- data/lib/omnitest/reporters/markdown_reporter.rb +26 -0
- data/lib/omnitest/reporters/yaml_reporter.rb +12 -0
- data/lib/omnitest/run_action.rb +44 -0
- data/lib/omnitest/version.rb +3 -0
- data/lib/omnitest/workflow.rb +5 -0
- data/mkdocs.yml +8 -0
- data/omnitest.gemspec +39 -0
- data/omnitest.yaml +5 -0
- data/resources/assets/angular/angular.min.js +217 -0
- data/resources/assets/angular/angular.min.js.map +8 -0
- data/resources/assets/angular/json-formatter.min.css +6 -0
- data/resources/assets/angular/json-formatter.min.js +7 -0
- data/resources/assets/angular/ng-table.map +1 -0
- data/resources/assets/angular/ng-table.min.css +3 -0
- data/resources/assets/angular/ng-table.min.js +3 -0
- data/resources/assets/angular/ui-bootstrap-tpls.min.js +10 -0
- data/resources/assets/bootstrap/bootstrap.min.css +9 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.eot +0 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.svg +229 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/resources/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/resources/assets/pygments/autumn.css +58 -0
- data/resources/assets/pygments/borland.css +46 -0
- data/resources/assets/pygments/bw.css +34 -0
- data/resources/assets/pygments/colorful.css +61 -0
- data/resources/assets/pygments/default.css +62 -0
- data/resources/assets/pygments/emacs.css +61 -0
- data/resources/assets/pygments/friendly.css +61 -0
- data/resources/assets/pygments/fruity.css +69 -0
- data/resources/assets/pygments/github.css +61 -0
- data/resources/assets/pygments/manni.css +61 -0
- data/resources/assets/pygments/monokai.css +64 -0
- data/resources/assets/pygments/murphy.css +61 -0
- data/resources/assets/pygments/native.css +69 -0
- data/resources/assets/pygments/pastie.css +60 -0
- data/resources/assets/pygments/perldoc.css +58 -0
- data/resources/assets/pygments/tango.css +69 -0
- data/resources/assets/pygments/trac.css +59 -0
- data/resources/assets/pygments/vim.css +69 -0
- data/resources/assets/pygments/vs.css +33 -0
- data/resources/assets/pygments/zenburn.css +1 -0
- data/resources/assets/style.css +56 -0
- data/resources/code_sample.tt +2 -0
- data/resources/generators/dashboard/files/dashboard.html.tt +51 -0
- data/resources/generators/dashboard/files/dashboard.js +26 -0
- data/resources/generators/dashboard/templates/_test_report.html.haml +91 -0
- data/resources/generators/todo/templates/todo.md.tt +6 -0
- data/resources/generators/todo/todo_template.rb +1 -0
- data/samples/.gitignore +2 -0
- data/samples/_markdown.md +5 -0
- data/samples/bootstrap.sh +2 -0
- data/samples/clone.sh +2 -0
- data/samples/code2doc.sh +5 -0
- data/samples/default_bootstrap.rb +7 -0
- data/samples/detect.sh +2 -0
- data/samples/exec.sh +2 -0
- data/samples/omnitest.yaml +24 -0
- data/samples/omnitest_simple.yaml +8 -0
- data/samples/scripts/bootstrap +3 -0
- data/samples/show.sh +4 -0
- data/samples/skeptic.yaml +13 -0
- data/samples/skeptic_simple.yaml +9 -0
- data/samples/test.sh +2 -0
- data/samples/tests/omnitest/validators.rb +23 -0
- data/samples/verify.sh +3 -0
- data/scripts/bootstrap.ps1 +7 -0
- data/scripts/run_script.sh +4 -0
- data/skeptic.yaml +26 -0
- data/spec/fabricators/project_fabricator.rb +19 -0
- data/spec/fabricators/scenario_fabricator.rb +6 -0
- data/spec/fabricators/test_manifest_fabricator.rb +41 -0
- data/spec/fabricators/validator_fabricator.rb +12 -0
- data/spec/fixtures/factorial.py +18 -0
- data/spec/fixtures/omnitest.yaml +11 -0
- data/spec/fixtures/skeptic.yaml +16 -0
- data/spec/fixtures/src-doc/_scenario.md.erb +1 -0
- data/spec/fixtures/src-doc/quine.md.erb +20 -0
- data/spec/omnitest/cli_spec.rb +38 -0
- data/spec/omnitest/configuration_spec.rb +25 -0
- data/spec/omnitest/documentation_generator_spec.rb +59 -0
- data/spec/omnitest/file_finder_spec.rb +21 -0
- data/spec/omnitest/project_spec.rb +65 -0
- data/spec/omnitest_spec.rb +13 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/thor_spy.rb +66 -0
- data/tests/omnitest/bootstrap_validations.rb +7 -0
- data/tests/omnitest/show_validations.rb +22 -0
- data/yard_macros.rb +25 -0
- metadata +470 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
## Crosstasking (via Psychic)
|
2
|
+
|
3
|
+
Omnitest needs to be able to run tasks in any of the projects before it can run tests. Omnitest uses [psychic](https://github.com/omnitest/psychic), to run tasks. Psychic creates a uniform interface for running similar tasks in different projects, delegating to project specific task runners (like Rake, Make, npm run, or gradle) when necessary.
|
4
|
+
|
5
|
+
The first task you probably want to run is `bootstrap` in order to make sure the projects project is ready to test. Generally the `bootstrap` task will invoke a dependency manager like Bundler, npm, or pip.
|
6
|
+
|
7
|
+
```sh
|
8
|
+
$ bundle exec omnitest bootstrap
|
9
|
+
<%= scenario_output_snippet 'omnitest', 'bootstrap', include_command: false, format: :raw %>
|
10
|
+
```
|
11
|
+
|
12
|
+
### Custom tasks
|
13
|
+
|
14
|
+
There are a few default tasks like `bootstrap` that are built into omnitest (and psychic). The default tasks exist to match common test workflows (like the Travis-CI stages or Maven lifecycle), but you can also have omnitest invoke custom tasks.
|
15
|
+
|
16
|
+
So you could tell omnitest to invoke custom tasks like `documentation`, `metrics`, `lint` or `gitstats`:
|
17
|
+
|
18
|
+
```sh
|
19
|
+
$ bundle exec omnitest task lint
|
20
|
+
-----> Starting Omnitest (v0.2.0)
|
21
|
+
-----> Running task lint for ruby
|
22
|
+
Executing bundle exec rubocop -D
|
23
|
+
warning: parser/current is loading parser/ruby21, which recognizes
|
24
|
+
warning: 2.1.5-compliant syntax, but you are running 2.1.4.
|
25
|
+
Inspecting 2 files
|
26
|
+
..
|
27
|
+
|
28
|
+
2 files inspected, no offenses detected
|
29
|
+
-----> Running task lint for java
|
30
|
+
Executing gradle checkstyleMain
|
31
|
+
:compileJava UP-TO-DATE
|
32
|
+
:processResources UP-TO-DATE
|
33
|
+
:classes UP-TO-DATE
|
34
|
+
:checkstyleMain[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/HelloWorld.java:0: Missing package-info.java file.
|
35
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/HelloWorld.java:1: Line is longer than 100 characters (found 101).
|
36
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/HelloWorld.java:3: Missing a Javadoc comment.
|
37
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:1: Missing a Javadoc comment.
|
38
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:2:1: warning: '{' should be on the previous line.
|
39
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:4:3: warning: '{' should be on the previous line.
|
40
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:24: warning: 'for' construct must use '{}'s.
|
41
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:24:8: 'for' is not followed by whitespace.
|
42
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:24:30: warning: ')' is preceded with whitespace.
|
43
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:26: warning: 'for' construct must use '{}'s.
|
44
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:26:8: 'for' is not followed by whitespace.
|
45
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:27:28: warning: '(' is followed by whitespace.
|
46
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:27:54: warning: ')' is preceded with whitespace.
|
47
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:28: warning: 'for' construct must use '{}'s.
|
48
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:28:8: 'for' is not followed by whitespace.
|
49
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:29:28: warning: '(' is followed by whitespace.
|
50
|
+
[ant:checkstyle] /Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/src/main/java/Quine.java:29:33: warning: ')' is preceded with whitespace.
|
51
|
+
FAILED
|
52
|
+
|
53
|
+
FAILURE: Build failed with an exception.
|
54
|
+
|
55
|
+
* What went wrong:
|
56
|
+
Execution failed for task ':checkstyleMain'.
|
57
|
+
> Checkstyle rule violations were found. See the report at: file:///Users/Thoughtworker/repos/rackspace/polytrix/samples/sdks/java/build/reports/checkstyle/main.xml
|
58
|
+
|
59
|
+
* Try:
|
60
|
+
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
|
61
|
+
|
62
|
+
BUILD FAILED
|
63
|
+
|
64
|
+
Total time: 4.904 secs
|
65
|
+
-----> Running task lint for python
|
66
|
+
Executing ./scripts/lint.sh
|
67
|
+
New python executable in omnitest_python/bin/python
|
68
|
+
Installing setuptools, pip...done.
|
69
|
+
katas/hello_world.py:2:22: W292 no newline at end of file
|
70
|
+
katas/quine.py:2:8: E228 missing whitespace around modulo operator
|
71
|
+
-----> Omnitest is finished. (0m8.49s)
|
72
|
+
```
|
73
|
+
|
74
|
+
This is equivalent to running `psychic task lint` in each directory. See [psychic](https://github.com/omnitest/psychic) for more details about how psychic decides what command to invoke for any given task.
|
75
|
+
|
76
|
+
### Workflows
|
77
|
+
|
78
|
+
Coming soon....
|
79
|
+
|
80
|
+
A workflow is a group of tasks that you want to run together on each project.
|
81
|
+
|
82
|
+
The "commit test" workflow is the most common. This is basically a workflow that runs all the tests and checks that should be run before commiting a change. The [Travis-CI lifecycle](http://docs.travis-ci.com/user/build-lifecycle/) and [Maven Lifecycle](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html) (excluding the "deploy" stage in both cases) are examples.
|
83
|
+
|
84
|
+
Another workflow I've seen is the "morning" workflow. This workflow makes sure each of the projects are ready to start development. This is often similar to a "commit test" workflow, but it will also make sure you have a clean development environment, have fetched the latest upstream changes (from both version control and dependency management systems).
|
85
|
+
|
86
|
+
Another possibility would be a "end of sprint" or "pre-release" workflow. This could be very different than the two examples above. It may focus on collecting metrics or building and publishing release notes.
|
@@ -0,0 +1,87 @@
|
|
1
|
+
## Omnitesting (via Skeptic)
|
2
|
+
|
3
|
+
The `omnitest test` command will the same tests in each project, using spies to capture data and validate the behavior. This is for running tests that are shared across all projects to test for shared behavior. You can use `omnitask` to run each projects own test.
|
4
|
+
|
5
|
+
Currently this is used for testing a code sample for each scenario. Omnitest will run the sample and capture the process's exit code, stdout and stderr. You can register additional "spies" with skeptic in order to capture additional information or perform additional validation. For example, there are spies that use the [Pacto](https://github.com/thoughtworks/pacto) project to capture HTTP requests and compare them with the RESTful services that were expected to be called for the scenario.
|
6
|
+
|
7
|
+
### Defining test scenarios
|
8
|
+
|
9
|
+
Omnitest uses [Skeptic](https://github.com/omnitest/skeptic) to run tests, so the test scenarios are listed in a file called `skeptic.yaml`. The `suites` section of skeptic.yaml defines the tests you want to run. The suites contain scenarios ("samples"). Here is a simple file that defines a few scenarios:
|
10
|
+
|
11
|
+
<%= file_snippet 'samples/skeptic_simple.yaml' %>
|
12
|
+
|
13
|
+
You can also define properties for running samples with the "global_env" and "env" on suites. Here's a more complete example that shows defines some properties:
|
14
|
+
|
15
|
+
<%= file_snippet 'samples/skeptic.yaml' %>
|
16
|
+
|
17
|
+
### Available Commands
|
18
|
+
|
19
|
+
You can always see the available commands by running:
|
20
|
+
<%= exec_snippet 'bundle exec omnitest help' %>
|
21
|
+
|
22
|
+
You can see that most omnitest commands take two optional arguments: `[PROJECT|REGEXP|all] [SCENARIO|REGEXP|all]`. The first selects which projects a command applies to and the second selects which scenarios. See the documentation on [Project Sets](project_sets) for more information about selecting projects with the first parameter. The second argument, for selecting scenarios, has similar behavior:
|
23
|
+
- If omitted the command will apply to all scenarios.
|
24
|
+
- If a value is provided:
|
25
|
+
- If the value is "all" then the command applies to all scenarios. This only exists to make it possible to pass a third parameter, if necessary.
|
26
|
+
- If the value exactly matches the name of a scenario then only that scenario will be selected.
|
27
|
+
- If it does not match a scenario then it will be used as a regular expression to match other scenarios.
|
28
|
+
|
29
|
+
### Listing Tests
|
30
|
+
|
31
|
+
Omnitest keeps track of the test results so you don't need to test all projects or scenarios in a single run. You can use the command `omnitest list` to get quick summary of the latest results on the command line.
|
32
|
+
|
33
|
+
<%= exec_snippet 'bundle exec omnitest list', cwd: 'samples' %>
|
34
|
+
|
35
|
+
|
36
|
+
The list command can also illustrate the behavior of the two parameters for narrowing the scope of any omnitest command. For example you could list the results for the ruby project:
|
37
|
+
|
38
|
+
<%= exec_snippet 'bundle exec omnitest list ruby', cwd: 'samples' %>
|
39
|
+
|
40
|
+
Or you could list only the quine results for ruby and java:
|
41
|
+
|
42
|
+
<%= exec_snippet 'bundle exec omnitest list "(ruby|java)" quine', cwd: 'samples' %>
|
43
|
+
|
44
|
+
### Running Tests
|
45
|
+
|
46
|
+
The command `omnitest test` is for testing scenarios. If you run the command `omnitest test` in each project it will test every scenario in all projects. You can narrow the scope of what you want to test by selecting projects with the first parameter and tests with the second parameter.
|
47
|
+
|
48
|
+
For example, you could just run test quine scenario for the python project:
|
49
|
+
|
50
|
+
<%= exec_snippet 'bundle exec omnitest test python quine', cwd: 'samples' %>
|
51
|
+
|
52
|
+
Or, you could run all of the ruby tests:
|
53
|
+
|
54
|
+
<%= exec_snippet 'bundle exec omnitest test ruby', cwd: 'samples' %>
|
55
|
+
|
56
|
+
### Running individual phases
|
57
|
+
|
58
|
+
The test command actually runs a series of phases. You can run these phases individually, which may be useful if you're still developing the samples or tests and just want to check that they work up to a certain point. If you run any of these phases they will run all of the previous phases but will stop at your target phase.
|
59
|
+
|
60
|
+
There are two phases that apply at the project level:
|
61
|
+
- clone: Make sure the project is available, if it is missing attempt to get it from version control.
|
62
|
+
- bootstrap: Run the bootstrap task for the project to install dependenices.
|
63
|
+
|
64
|
+
And three phases for each scenario:
|
65
|
+
- detect: Find the code samples associated with the scenario.
|
66
|
+
- exec: Run the code sample and capture the result.
|
67
|
+
- verify: Validate the results captured by exec with any validators setup for that scenario.
|
68
|
+
|
69
|
+
So if you only want to make sure that all of the samples execute, without validating the results to make sure they performed as expected, you could run `omnitest exec`.
|
70
|
+
|
71
|
+
### Viewing Detailed Results
|
72
|
+
|
73
|
+
#### On the Console
|
74
|
+
|
75
|
+
The command `omnitest show` will display detailed results for the scenarios as text in your console.
|
76
|
+
|
77
|
+
<%= exec_snippet 'bundle exec omnitest show ruby hello', cwd: 'samples' %>
|
78
|
+
|
79
|
+
You can get even more information (including the actual code sample that was executed, with syntax highlighting if your console supports color) with the `--verbose` tag:
|
80
|
+
|
81
|
+
<%= exec_snippet 'bundle exec omnitest show ruby hello --verbose', cwd: 'samples' %>
|
82
|
+
|
83
|
+
#### Generating HTML reports
|
84
|
+
|
85
|
+
You can also generate a variety of reports with the `omnidoc` command. The most useful is `omnidoc dashboard`, which will generate a dashboard showing a grid of test results that looks similar to the `omnidoc list` command, where each item is linked to additional details about the result that is similar to the `omnidoc show` command for that scenario.
|
86
|
+
|
87
|
+
See the [omnidoc](omnidoc) documentation for more details.
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Feature: Boostrapping
|
2
|
+
|
3
|
+
Omnitest uses the [script/bootstrap](http://wynnnetherland.com/linked/2013012801/bootstrapping-consistency) pattern to prepare projects for testing. You can hook into any package manager, compiler, build tool, or any other toolchain to prepare to build and run samples.
|
4
|
+
|
5
|
+
Scenario: Bootstrapping all projects
|
6
|
+
Given the ruby project
|
7
|
+
And the java project
|
8
|
+
And the python project
|
9
|
+
And the sample omnitest config
|
10
|
+
And the hello_world skeptic config
|
11
|
+
When I run `bundle exec omnitest bootstrap`
|
12
|
+
Then the output should contain "-----> Bootstrapping java"
|
13
|
+
Then the output should contain "-----> Bootstrapping python"
|
14
|
+
Then the output should contain "-----> Bootstrapping ruby"
|
15
|
+
|
16
|
+
Scenario: Bootstrapping selected projects
|
17
|
+
Given the ruby project
|
18
|
+
And the java project
|
19
|
+
And the python project
|
20
|
+
And the sample omnitest config
|
21
|
+
And the hello_world skeptic config
|
22
|
+
When I run `bundle exec omnitest bootstrap "(java|ruby)"`
|
23
|
+
Then the output should contain "-----> Bootstrapping java"
|
24
|
+
Then the output should not contain "-----> Bootstrapping python"
|
25
|
+
Then the output should contain "-----> Bootstrapping ruby"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
@wip
|
2
|
+
Feature: Cloning
|
3
|
+
|
4
|
+
Omnitest can clone projects from git.
|
5
|
+
|
6
|
+
Scenario: Cloning all projects
|
7
|
+
Given the sample omnitest config
|
8
|
+
When I run `bundle exec omnitest clone`
|
9
|
+
Then the output should contain "-----> Cloning java"
|
10
|
+
Then the output should contain "-----> Cloning python"
|
11
|
+
Then the output should contain "-----> Cloning ruby"
|
12
|
+
|
13
|
+
Scenario: Cloning selected projects
|
14
|
+
Given the ruby project
|
15
|
+
And the java project
|
16
|
+
And the python project
|
17
|
+
And the sample omnitest config
|
18
|
+
When I run `bundle exec omnitest clone "(java|ruby)"`
|
19
|
+
Then the output should contain "-----> Cloning java"
|
20
|
+
Then the output should not contain "-----> Cloning python"
|
21
|
+
Then the output should contain "-----> Cloning ruby"
|
22
|
+
|
23
|
+
Scenario: Cloning by scenario
|
24
|
+
Given the ruby project
|
25
|
+
And the java project
|
26
|
+
And the python project
|
27
|
+
And the sample omnitest config
|
28
|
+
And the hello_world skeptic config
|
29
|
+
When I run `bundle exec omnitest clone hello`
|
30
|
+
Then the output should contain "-----> Cloning java"
|
31
|
+
Then the output should contain "-----> Cloning python"
|
32
|
+
Then the output should contain "-----> Cloning ruby"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Feature: Show
|
2
|
+
|
3
|
+
Scenario: Initial state
|
4
|
+
Given the ruby project
|
5
|
+
And the java project
|
6
|
+
And the python project
|
7
|
+
And the sample omnitest config
|
8
|
+
And the hello_world skeptic config
|
9
|
+
When I run `bundle exec omnitest show ruby 'hello world'`
|
10
|
+
Then the output should contain:
|
11
|
+
"""
|
12
|
+
katas-hello_world-ruby: <Not Found>
|
13
|
+
Test suite: Katas
|
14
|
+
Test scenario: hello world
|
15
|
+
Project: ruby
|
16
|
+
Source: sdks/ruby/katas/hello_world.rb
|
17
|
+
"""
|
18
|
+
|
19
|
+
@no-clobber
|
20
|
+
Scenario: State after testing
|
21
|
+
Given I run `bundle exec omnitest test ruby`
|
22
|
+
When I run `bundle exec omnitest show ruby 'hello world'`
|
23
|
+
Then the output should contain:
|
24
|
+
"""
|
25
|
+
katas-hello_world-ruby: Fully Verified (1 of 1)
|
26
|
+
Test suite: Katas
|
27
|
+
Test scenario: hello world
|
28
|
+
Project: ruby
|
29
|
+
Source: sdks/ruby/katas/hello_world.rb
|
30
|
+
Execution result:
|
31
|
+
Exit Status: 0
|
32
|
+
Stdout:
|
33
|
+
Hello, world!
|
34
|
+
Stderr:
|
35
|
+
Validations:
|
36
|
+
default validator: ✓ Passed
|
37
|
+
Data from spies:
|
38
|
+
"""
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Feature: States
|
2
|
+
|
3
|
+
Scenario: Initial state
|
4
|
+
Given the ruby project
|
5
|
+
And the java project
|
6
|
+
And the python project
|
7
|
+
And the sample omnitest config
|
8
|
+
And the hello_world skeptic config
|
9
|
+
When I run `bundle exec omnitest list`
|
10
|
+
Then the output should contain:
|
11
|
+
"""
|
12
|
+
Suite Scenario Project Status
|
13
|
+
Katas hello world ruby <Not Found>
|
14
|
+
Katas hello world java <Not Found>
|
15
|
+
Katas hello world python <Not Found>
|
16
|
+
"""
|
17
|
+
|
18
|
+
@no-clobber
|
19
|
+
Scenario: State after execution
|
20
|
+
Given I run `bundle exec omnitest exec python`
|
21
|
+
When I run `bundle exec omnitest list`
|
22
|
+
Then the output should contain:
|
23
|
+
"""
|
24
|
+
Suite Scenario Project Status
|
25
|
+
Katas hello world ruby <Not Found>
|
26
|
+
Katas hello world java <Not Found>
|
27
|
+
Katas hello world python Executed
|
28
|
+
"""
|
29
|
+
|
30
|
+
@no-clobber
|
31
|
+
Scenario: State after verification
|
32
|
+
Given I run `bundle exec omnitest verify ruby`
|
33
|
+
When I run `bundle exec omnitest list`
|
34
|
+
Then the output should contain:
|
35
|
+
"""
|
36
|
+
Suite Scenario Project Status
|
37
|
+
Katas hello world ruby Fully Verified (1 of 1)
|
38
|
+
Katas hello world java <Not Found>
|
39
|
+
Katas hello world python Executed
|
40
|
+
"""
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
Given(/^the (\w+) project$/) do |sdk|
|
4
|
+
FileUtils.mkdir_p "#{current_dir}/sdks"
|
5
|
+
FileUtils.cp_r "samples/sdks/#{sdk}", "#{current_dir}/sdks"
|
6
|
+
end
|
7
|
+
|
8
|
+
Given(/^the (\w+) omnitest config$/) do |config|
|
9
|
+
FileUtils.cp_r "features/fixtures/configs/omnitest_#{config}.yaml", "#{current_dir}/omnitest.yaml"
|
10
|
+
end
|
11
|
+
|
12
|
+
Given(/^the (\w+) skeptic config$/) do |config|
|
13
|
+
FileUtils.cp_r "features/fixtures/configs/skeptic_#{config}.yaml", "#{current_dir}/skeptic.yaml"
|
14
|
+
end
|
15
|
+
|
16
|
+
Then(/^the file "(.*?)" should contain yaml matching:$/) do |file, content|
|
17
|
+
in_current_dir do
|
18
|
+
actual_content = YAML.load(File.read(file))
|
19
|
+
expected_content = YAML.load(content)
|
20
|
+
expect(actual_content).to eq(expected_content)
|
21
|
+
end
|
22
|
+
end
|
data/lib/omnitest.rb
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'omnitest/version'
|
2
|
+
require 'omnitest/core'
|
3
|
+
require 'omnitest/psychic'
|
4
|
+
require 'omnitest/skeptic'
|
5
|
+
require 'omnitest/run_action'
|
6
|
+
require 'omnitest/project'
|
7
|
+
require 'omnitest/workflow'
|
8
|
+
require 'omnitest/project_set'
|
9
|
+
require 'omnitest/project_logger'
|
10
|
+
require 'omnitest/configuration'
|
11
|
+
require 'omnitest/documentation_generator'
|
12
|
+
|
13
|
+
module Omnitest
|
14
|
+
include Omnitest::Core::Logger
|
15
|
+
include Omnitest::Core::Logging
|
16
|
+
|
17
|
+
# File extensions that Omnitest can automatically detect/execute
|
18
|
+
SUPPORTED_EXTENSIONS = %w(py rb js)
|
19
|
+
|
20
|
+
module Delegators
|
21
|
+
# @api private
|
22
|
+
# @!macro delegate_to_skeptic
|
23
|
+
# @method $1()
|
24
|
+
def delegate_to_skeptic_class(meth)
|
25
|
+
define_method(meth) { |*args, &block| Skeptic.public_send(meth, *args, &block) }
|
26
|
+
end
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
# @!macro delegate_to_psychic
|
30
|
+
# @method $1()
|
31
|
+
def delegate_to_psychic_class(meth)
|
32
|
+
define_method(meth) { |*args, &block| Psychic.public_send(meth, *args, &block) }
|
33
|
+
end
|
34
|
+
|
35
|
+
# @api private
|
36
|
+
# @!macro delegate_to_psychic
|
37
|
+
# @method $1()
|
38
|
+
def delegate_to_psychic_instance(meth)
|
39
|
+
define_method(meth) { |*args, &block| psychic.public_send(meth, *args, &block) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api private
|
43
|
+
# @!macro delegate_to_projects
|
44
|
+
# @method $1()
|
45
|
+
def delegate_to_projects(meth)
|
46
|
+
define_method(meth) do |*args, &block|
|
47
|
+
project_regex = args.shift
|
48
|
+
run_action(filter_projects(project_regex), meth, configuration.concurrency, *args, &block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# @api private
|
53
|
+
# @!macro delegate_to_scenarios
|
54
|
+
# @method $1()
|
55
|
+
def delegate_to_scenarios(meth)
|
56
|
+
define_method(meth) do |*args, &block|
|
57
|
+
project_regex = args.shift
|
58
|
+
scenario_regex = args.shift
|
59
|
+
scenarios(project_regex, scenario_regex).map { |s| s.public_send(meth, *args, &block) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class << self
|
65
|
+
include Core::Configurable
|
66
|
+
include RunAction
|
67
|
+
extend Delegators
|
68
|
+
|
69
|
+
DEFAULT_PROJECT_SET_FILE = 'omnitest.yaml'
|
70
|
+
DEFAULT_TEST_MANIFEST_FILE = 'skeptic.yaml'
|
71
|
+
|
72
|
+
# @return [Logger] the common Omnitest logger
|
73
|
+
attr_accessor :logger
|
74
|
+
|
75
|
+
attr_accessor :psychic
|
76
|
+
|
77
|
+
attr_accessor :wants_to_quit
|
78
|
+
|
79
|
+
def new_logger(project) # (test, project, index)
|
80
|
+
name = project.name # instance_name(test, project)
|
81
|
+
index = Omnitest.projects.index(project) || 0
|
82
|
+
ProjectLogger.new(
|
83
|
+
stdout: STDOUT,
|
84
|
+
color: Core::Color::COLORS[index % Core::Color::COLORS.size].to_sym,
|
85
|
+
logdev: File.join(Omnitest.configuration.log_root, "#{name}.log"),
|
86
|
+
level: Omnitest::Core::Util.to_logger_level(Omnitest.configuration.log_level),
|
87
|
+
progname: name
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def basedir
|
92
|
+
@basedir ||= psychic.basedir
|
93
|
+
end
|
94
|
+
|
95
|
+
# @private
|
96
|
+
def trap_interrupt
|
97
|
+
trap('INT') do
|
98
|
+
exit!(1) if Omnitest.wants_to_quit
|
99
|
+
Omnitest.wants_to_quit = true
|
100
|
+
STDERR.puts "\nInterrupt detected... Interrupt again to force quit."
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def update_config!(options)
|
105
|
+
trap_interrupt
|
106
|
+
@logger = Omnitest.default_file_logger
|
107
|
+
project_set_file = options.file || DEFAULT_PROJECT_SET_FILE
|
108
|
+
@basedir = File.dirname project_set_file
|
109
|
+
skeptic_file = options.skeptic || DEFAULT_TEST_MANIFEST_FILE
|
110
|
+
|
111
|
+
Omnitest.configure do | config |
|
112
|
+
config.concurrency = options.concurrency
|
113
|
+
config.log_level = options.log_level || :info
|
114
|
+
config.project_set = project_set_file
|
115
|
+
config.skeptic.manifest_file = skeptic_file
|
116
|
+
config.travis = options.travis if options.respond_to? :travis
|
117
|
+
end
|
118
|
+
@test_dir = options.test_dir || File.expand_path('tests/omnitest/', @basedir)
|
119
|
+
end
|
120
|
+
|
121
|
+
delegate_to_skeptic_class :validate
|
122
|
+
|
123
|
+
delegate_to_projects :task
|
124
|
+
|
125
|
+
delegate_to_projects :workflow
|
126
|
+
|
127
|
+
delegate_to_projects :clone
|
128
|
+
|
129
|
+
delegate_to_projects :bootstrap
|
130
|
+
|
131
|
+
delegate_to_scenarios :test
|
132
|
+
|
133
|
+
delegate_to_scenarios :clear
|
134
|
+
|
135
|
+
delegate_to_scenarios :code2doc
|
136
|
+
|
137
|
+
Skeptic::Scenario::FSM::TRANSITIONS.each do | transition |
|
138
|
+
delegate_to_scenarios transition
|
139
|
+
end
|
140
|
+
|
141
|
+
def setup
|
142
|
+
# This autoload should probably be in Skeptic's initializer...
|
143
|
+
autoload_omnitest_files(@test_dir) unless @test_dir.nil? || !File.directory?(@test_dir)
|
144
|
+
end
|
145
|
+
|
146
|
+
def scenarios(project_regexp = 'all', scenario_regexp = 'all', options = {})
|
147
|
+
filtered_projects = filter_projects(project_regexp, options)
|
148
|
+
filtered_scenarios = filtered_projects.map(&:skeptic).flat_map do | skeptic |
|
149
|
+
skeptic.scenarios scenario_regexp, options
|
150
|
+
end
|
151
|
+
|
152
|
+
fail UserError, "No scenarios for regex `#{scenario_regexp}', try running `omnitest list'" if filtered_scenarios.empty?
|
153
|
+
filtered_scenarios
|
154
|
+
end
|
155
|
+
|
156
|
+
def filter_projects(regexp = 'all', _options = {})
|
157
|
+
return Omnitest.projects if regexp.nil? || regexp == 'all'
|
158
|
+
|
159
|
+
filtered_projects = Omnitest.projects.find { |s| s.name == regexp }
|
160
|
+
return [filtered_projects] if filtered_projects
|
161
|
+
|
162
|
+
filtered_projects ||= Omnitest.projects.select { |s| s.name =~ /#{regexp}/i }
|
163
|
+
fail UserError, "No projects matching regex `#{regexp}', known projects: #{Omnitest.projects.map(&:name)}" if filtered_projects.empty?
|
164
|
+
|
165
|
+
filtered_projects
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns a default file logger which emits on standard output and to a
|
169
|
+
# log file.
|
170
|
+
#
|
171
|
+
# @return [Logger] a logger
|
172
|
+
def default_file_logger
|
173
|
+
logfile = File.expand_path(File.join('.omnitest', 'logs', 'omnitest.log'))
|
174
|
+
ProjectLogger.new(stdout: $stdout, logdev: logfile, level: Core::Util.to_logger_level(configuration.log_level))
|
175
|
+
end
|
176
|
+
|
177
|
+
# The {Omnitest::TestManifest} that describes the test scenarios known to Omnitest.
|
178
|
+
def manifest
|
179
|
+
configuration.skeptic.manifest
|
180
|
+
end
|
181
|
+
|
182
|
+
# The set of {Omnitest::Project}s registered with Omnitest.
|
183
|
+
def projects
|
184
|
+
configuration.project_set.projects.values
|
185
|
+
end
|
186
|
+
|
187
|
+
# @api private
|
188
|
+
def psychic
|
189
|
+
@psychic ||= Omnitest::Psychic.new(cwd: Omnitest.basedir, logger: logger, travis: Omnitest.configuration.travis)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns whether or not standard output is associated with a terminal
|
193
|
+
# device (tty).
|
194
|
+
#
|
195
|
+
# @return [true,false] is there a tty?
|
196
|
+
def tty?
|
197
|
+
$stdout.tty?
|
198
|
+
end
|
199
|
+
|
200
|
+
protected
|
201
|
+
|
202
|
+
def autoload_omnitest_files(dir)
|
203
|
+
$LOAD_PATH.unshift dir
|
204
|
+
Dir["#{dir}/**/*.rb"].each do | file_to_require |
|
205
|
+
# TODO: Need a better way to skip generators or only load validators
|
206
|
+
next if file_to_require.match %r{generators/.*/files/}
|
207
|
+
require Omnitest::Core::FileSystem.relativize(file_to_require, dir).to_s.gsub('.rb', '')
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|