polytrix 0.1.0.pre → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +7 -2
- data/.travis.yml +2 -1
- data/Gemfile +1 -0
- data/README.md +190 -98
- data/Rakefile +8 -6
- data/bin/polytrix +2 -1
- data/docs/samples/code2doc/java/HelloWorld.md +4 -0
- data/docs/samples/code2doc/java/Quine.md +2 -0
- data/docs/samples/code2doc/python/hello_world.md +2 -0
- data/docs/samples/code2doc/python/quine.md +2 -0
- data/docs/samples/code2doc/ruby/hello_world.md +4 -0
- data/features/bootstrapping.feature +36 -0
- data/features/cloning.feature +34 -0
- data/features/execution.feature +2 -16
- data/features/fixtures/configs/empty.yml +12 -1
- data/features/fixtures/configs/hello_world.yml +11 -1
- data/features/fixtures/spec/polytrix_spec.rb +1 -4
- data/features/solo.feature +12 -0
- data/features/states.feature +40 -0
- data/features/step_definitions/sdk_steps.rb +11 -1
- data/features/support/env.rb +2 -1
- data/lib/polytrix/challenge.rb +211 -13
- data/lib/polytrix/challenge_result.rb +9 -0
- data/lib/polytrix/challenge_runner.rb +4 -11
- data/lib/polytrix/challenges.rb +16 -0
- data/lib/polytrix/cli/report.rb +0 -4
- data/lib/polytrix/cli.rb +229 -137
- data/lib/polytrix/color.rb +40 -0
- data/lib/polytrix/command/action.rb +26 -0
- data/lib/polytrix/command/list.rb +53 -0
- data/lib/polytrix/command/rundoc.rb +27 -0
- data/lib/polytrix/command/test.rb +24 -0
- data/lib/polytrix/command.rb +209 -0
- data/lib/polytrix/configuration.rb +30 -40
- data/lib/polytrix/core/file_system_helper.rb +2 -5
- data/lib/polytrix/core/hashie.rb +14 -0
- data/lib/polytrix/core/implementor.rb +52 -12
- data/lib/polytrix/core/manifest_section.rb +4 -0
- data/lib/polytrix/core/string_helpers.rb +15 -0
- data/lib/polytrix/documentation/helpers/code_helper.rb +3 -1
- data/lib/polytrix/error.rb +209 -0
- data/lib/polytrix/logger.rb +365 -8
- data/lib/polytrix/logging.rb +34 -0
- data/lib/polytrix/manifest.rb +40 -26
- data/lib/polytrix/result.rb +1 -0
- data/lib/polytrix/rspec.rb +7 -5
- data/lib/polytrix/runners/buff_shellout_executor.rb +19 -0
- data/lib/polytrix/runners/executor.rb +32 -0
- data/lib/polytrix/runners/mixlib_shellout_executor.rb +83 -0
- data/lib/polytrix/state_file.rb +60 -0
- data/lib/polytrix/util.rb +155 -0
- data/lib/polytrix/validation.rb +1 -1
- data/lib/polytrix/validator.rb +9 -5
- data/lib/polytrix/version.rb +1 -1
- data/lib/polytrix.rb +55 -33
- data/polytrix.gemspec +4 -2
- data/polytrix.rb +0 -5
- data/{polytrix_tests.yml → polytrix.yml} +5 -0
- data/samples/default_bootstrap.rb +0 -7
- data/samples/polytrix.rb +0 -9
- data/samples/{polytrix_tests.yml → polytrix.yml} +11 -0
- data/samples/polytrix_cli.sh +1 -1
- data/spec/fabricators/implementor_fabricator.rb +20 -0
- data/spec/fabricators/manifest_fabricator.rb +4 -1
- data/spec/fixtures/{polytrix_tests.yml → polytrix.yml} +10 -0
- data/spec/polytrix/challenge_runner_spec.rb +3 -2
- data/spec/polytrix/challenge_spec.rb +5 -4
- data/spec/polytrix/cli_spec.rb +23 -26
- data/spec/polytrix/configuration_spec.rb +4 -43
- data/spec/polytrix/documentation/helpers/code_helper_spec.rb +1 -1
- data/spec/polytrix/documentation_generator_spec.rb +2 -0
- data/spec/polytrix/implementor_spec.rb +44 -2
- data/spec/polytrix/manifest_spec.rb +7 -4
- data/spec/polytrix_spec.rb +9 -11
- data/spec/thor_spy.rb +2 -0
- metadata +66 -16
- data/features/fixtures/spec/polytrix_merge.rb +0 -5
- data/features/reporting.feature +0 -140
- data/lib/polytrix/executor.rb +0 -89
- data/samples/sdks/custom/polytrix.yml +0 -2
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
module Polytrix
|
4
|
+
class StateFileLoadError < StandardError; end
|
5
|
+
class StateFile
|
6
|
+
def initialize(polytrix_root, name)
|
7
|
+
@file_name = File.expand_path(
|
8
|
+
File.join(polytrix_root, '.polytrix', "#{name}.yml")
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def read
|
13
|
+
if File.exist?(file_name)
|
14
|
+
Hashie::Mash.load(file_name).dup
|
15
|
+
else
|
16
|
+
Hashie::Mash.new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(state)
|
21
|
+
dir = File.dirname(file_name)
|
22
|
+
serialized_string = serialize_hash(Util.stringified_hash(state))
|
23
|
+
|
24
|
+
FileUtils.mkdir_p(dir) unless File.directory?(dir)
|
25
|
+
File.open(file_name, 'wb') { |f| f.write(serialized_string) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy
|
29
|
+
FileUtils.rm_f(file_name) if File.exist?(file_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def diagnose
|
33
|
+
raw = read
|
34
|
+
result = {}
|
35
|
+
raw.keys.sort.each { |k| result[k] = raw[k] }
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :file_name
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
def read_file
|
45
|
+
IO.read(file_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @api private
|
49
|
+
def deserialize_string(string)
|
50
|
+
SafeYAML.load(string)
|
51
|
+
rescue SyntaxError, Psych::SyntaxError => ex
|
52
|
+
raise StateFileLoadError, "Error parsing #{file_name} (#{ex.message})"
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
def serialize_hash(hash)
|
57
|
+
::YAML.dump(hash)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, 2013, 2014, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
module Polytrix
|
20
|
+
# Stateless utility methods used in different contexts. Essentially a mini
|
21
|
+
# PassiveSupport library.
|
22
|
+
module Util
|
23
|
+
# Returns the standard library Logger level constants for a given symbol
|
24
|
+
# representation.
|
25
|
+
#
|
26
|
+
# @param symbol [Symbol] symbol representation of a logger level (:debug,
|
27
|
+
# :info, :warn, :error, :fatal)
|
28
|
+
# @return [Integer] Logger::Severity constant value or nil if input is not
|
29
|
+
# valid
|
30
|
+
def self.to_logger_level(symbol)
|
31
|
+
return nil unless [:debug, :info, :warn, :error, :fatal].include?(symbol)
|
32
|
+
|
33
|
+
Logger.const_get(symbol.to_s.upcase)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the symbol represenation of a logging levels for a given
|
37
|
+
# standard library Logger::Severity constant.
|
38
|
+
#
|
39
|
+
# @param const [Integer] Logger::Severity constant value for a logging
|
40
|
+
# level (Logger::DEBUG, Logger::INFO, Logger::WARN, Logger::ERROR,
|
41
|
+
# Logger::FATAL)
|
42
|
+
# @return [Symbol] symbol representation of the logging level
|
43
|
+
def self.from_logger_level(const)
|
44
|
+
case const
|
45
|
+
when Logger::DEBUG then :debug
|
46
|
+
when Logger::INFO then :info
|
47
|
+
when Logger::WARN then :warn
|
48
|
+
when Logger::ERROR then :error
|
49
|
+
else :fatal
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns a new Hash with all key values coerced to symbols. All keys
|
54
|
+
# within a Hash are coerced by calling #to_sym and hashes within arrays
|
55
|
+
# and other hashes are traversed.
|
56
|
+
#
|
57
|
+
# @param obj [Object] the hash to be processed. While intended for
|
58
|
+
# hashes, this method safely processes arbitrary objects
|
59
|
+
# @return [Object] a converted hash with all keys as symbols
|
60
|
+
def self.symbolized_hash(obj)
|
61
|
+
if obj.is_a?(Hash)
|
62
|
+
obj.reduce({}) do |h, (k, v)|
|
63
|
+
h[k.to_sym] = symbolized_hash(v)
|
64
|
+
h
|
65
|
+
end
|
66
|
+
elsif obj.is_a?(Array)
|
67
|
+
obj.reduce([]) do |a, e|
|
68
|
+
a << symbolized_hash(e)
|
69
|
+
a
|
70
|
+
end
|
71
|
+
else
|
72
|
+
obj
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns a new Hash with all key values coerced to strings. All keys
|
77
|
+
# within a Hash are coerced by calling #to_s and hashes with arrays
|
78
|
+
# and other hashes are traversed.
|
79
|
+
#
|
80
|
+
# @param obj [Object] the hash to be processed. While intended for
|
81
|
+
# hashes, this method safely processes arbitrary objects
|
82
|
+
# @return [Object] a converted hash with all keys as strings
|
83
|
+
def self.stringified_hash(obj)
|
84
|
+
if obj.is_a?(Hash)
|
85
|
+
obj.reduce({}) do |h, (k, v)|
|
86
|
+
h[k.to_s] = stringified_hash(v)
|
87
|
+
h
|
88
|
+
end
|
89
|
+
elsif obj.is_a?(Array)
|
90
|
+
obj.reduce([]) do |a, e|
|
91
|
+
a << stringified_hash(e)
|
92
|
+
a
|
93
|
+
end
|
94
|
+
else
|
95
|
+
obj
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns a formatted string representing a duration in seconds.
|
100
|
+
#
|
101
|
+
# @param total [Integer] the total number of seconds
|
102
|
+
# @return [String] a formatted string of the form (XmYY.00s)
|
103
|
+
def self.duration(total)
|
104
|
+
total = 0 if total.nil?
|
105
|
+
minutes = (total / 60).to_i
|
106
|
+
seconds = (total - (minutes * 60))
|
107
|
+
format('(%dm%.2fs)', minutes, seconds)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Generates a command (or series of commands) wrapped so that it can be
|
111
|
+
# invoked on a remote instance or locally.
|
112
|
+
#
|
113
|
+
# This method uses the Bourne shell (/bin/sh) to maximize the chance of
|
114
|
+
# cross platform portability on Unixlike systems.
|
115
|
+
#
|
116
|
+
# @param [String] the command
|
117
|
+
# @return [String] a wrapped command string
|
118
|
+
def self.wrap_command(cmd)
|
119
|
+
cmd = 'false' if cmd.nil?
|
120
|
+
cmd = 'true' if cmd.to_s.empty?
|
121
|
+
cmd = cmd.sub(/\n\Z/, '') if cmd =~ /\n\Z/
|
122
|
+
|
123
|
+
"sh -c '\n#{cmd}\n'"
|
124
|
+
end
|
125
|
+
|
126
|
+
# Modifes the given string to strip leading whitespace on each line, the
|
127
|
+
# amount which is calculated by using the first line of text.
|
128
|
+
#
|
129
|
+
# @example
|
130
|
+
#
|
131
|
+
# string = <<-STRING
|
132
|
+
# a
|
133
|
+
# b
|
134
|
+
# c
|
135
|
+
# STRING
|
136
|
+
# Util.outdent!(string) # => "a\n b\nc\n"
|
137
|
+
#
|
138
|
+
# @param string [String] the string that will be modified
|
139
|
+
# @return [String] the modified string
|
140
|
+
def self.outdent!(string)
|
141
|
+
string.gsub!(/^ {#{string.index(/[^ ]/)}}/, '')
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns a set of Bourne Shell (AKA /bin/sh) compatible helper
|
145
|
+
# functions. This function is usually called inline in a string that
|
146
|
+
# will be executed remotely on a test instance.
|
147
|
+
#
|
148
|
+
# @return [String] a string representation of useful helper functions
|
149
|
+
def self.shell_helpers
|
150
|
+
IO.read(File.join(
|
151
|
+
File.dirname(__FILE__), %w[.. .. support download_helpers.sh]
|
152
|
+
))
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
data/lib/polytrix/validation.rb
CHANGED
data/lib/polytrix/validator.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
1
3
|
module Polytrix
|
2
4
|
class Validator
|
5
|
+
include RSpec::Matchers
|
6
|
+
|
3
7
|
UNIVERSAL_MATCHER = //
|
4
|
-
attr_reader :suite, :sample, :callback
|
8
|
+
attr_reader :suite, :sample, :level, :callback
|
5
9
|
|
6
10
|
def initialize(scope = {}, &validator)
|
7
11
|
@suite = scope[:suite] ||= UNIVERSAL_MATCHER
|
@@ -10,11 +14,11 @@ module Polytrix
|
|
10
14
|
end
|
11
15
|
|
12
16
|
def should_validate?(challenge)
|
13
|
-
!!(@suite.match(challenge.suite) && @sample.match(challenge.name))
|
17
|
+
!!(@suite.match(challenge.suite.to_s) && @sample.match(challenge.name.to_s))
|
14
18
|
end
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
def validate(challenge)
|
21
|
+
instance_exec challenge, &@callback if should_validate?(challenge)
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
data/lib/polytrix/version.rb
CHANGED
data/lib/polytrix.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require '
|
3
|
-
require 'hashie
|
4
|
-
require '
|
2
|
+
require 'polytrix/error'
|
3
|
+
require 'polytrix/core/hashie'
|
4
|
+
require 'polytrix/core/string_helpers'
|
5
5
|
require 'polytrix/version'
|
6
|
+
require 'polytrix/util'
|
7
|
+
require 'polytrix/color'
|
6
8
|
require 'polytrix/logger'
|
9
|
+
require 'polytrix/logging'
|
10
|
+
require 'polytrix/state_file'
|
7
11
|
require 'polytrix/core/file_system_helper'
|
8
|
-
require 'polytrix/executor'
|
12
|
+
require 'polytrix/runners/executor'
|
13
|
+
require 'polytrix/core/manifest_section'
|
9
14
|
require 'polytrix/core/implementor'
|
10
15
|
require 'polytrix/challenge_runner'
|
16
|
+
require 'polytrix/challenge_result'
|
11
17
|
require 'polytrix/challenge'
|
18
|
+
require 'polytrix/challenges'
|
12
19
|
require 'polytrix/manifest'
|
13
20
|
require 'polytrix/configuration'
|
14
21
|
require 'polytrix/validation'
|
@@ -21,11 +28,15 @@ require 'polytrix/validator_registry'
|
|
21
28
|
require 'polytrix/rspec'
|
22
29
|
|
23
30
|
module Polytrix
|
24
|
-
include Polytrix::
|
31
|
+
include Polytrix::DefaultLogger
|
32
|
+
include Polytrix::Logging
|
25
33
|
|
26
34
|
class << self
|
27
35
|
include Polytrix::Core::FileSystemHelper
|
28
36
|
|
37
|
+
# @return [Mutex] a common mutex for global coordination
|
38
|
+
attr_accessor :mutex
|
39
|
+
|
29
40
|
def reset
|
30
41
|
@configuration = nil
|
31
42
|
Polytrix::ValidatorRegistry.clear
|
@@ -33,12 +44,12 @@ module Polytrix
|
|
33
44
|
|
34
45
|
# The {Polytrix::Manifest} that describes the test scenarios known to Polytrix.
|
35
46
|
def manifest
|
36
|
-
configuration.
|
47
|
+
configuration.manifest
|
37
48
|
end
|
38
49
|
|
39
50
|
# The set of {Polytrix::Implementor}s registered with Polytrix.
|
40
51
|
def implementors
|
41
|
-
|
52
|
+
manifest.implementors.values
|
42
53
|
end
|
43
54
|
|
44
55
|
def find_implementor(file)
|
@@ -49,12 +60,17 @@ module Polytrix
|
|
49
60
|
end
|
50
61
|
return existing_implementor if existing_implementor
|
51
62
|
|
52
|
-
implementor_basedir = recursive_parent_search(File.dirname(file), 'polytrix.yml')
|
53
|
-
return Polytrix.configuration.implementor implementor_basedir if implementor_basedir
|
54
|
-
|
55
63
|
nil
|
56
64
|
end
|
57
65
|
|
66
|
+
# Invokes the clone action for each SDK.
|
67
|
+
# @see Polytrix::Implementor#clone
|
68
|
+
def clone(*sdks)
|
69
|
+
select_implementors(sdks).each do |implementor|
|
70
|
+
implementor.clone
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
58
74
|
# Invokes the bootstrap action for each SDK.
|
59
75
|
# @see Polytrix::Implementor#bootstrap
|
60
76
|
def bootstrap(*sdks)
|
@@ -63,18 +79,24 @@ module Polytrix
|
|
63
79
|
end
|
64
80
|
end
|
65
81
|
|
66
|
-
def exec(
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
82
|
+
def exec(*files)
|
83
|
+
# files.map do | file |
|
84
|
+
# Dir.glob file
|
85
|
+
# end.flatten
|
86
|
+
|
87
|
+
files.each do | file |
|
88
|
+
implementor = find_implementor(file) # || exec_options[:default_implementor]
|
89
|
+
|
90
|
+
extension = File.extname(file)
|
91
|
+
name = File.basename(file, extension)
|
92
|
+
challenge_data = {
|
93
|
+
name: name,
|
94
|
+
# language: extension,
|
95
|
+
source_file: File.expand_path(file, Dir.pwd)
|
96
|
+
}
|
97
|
+
challenge = implementor.build_challenge challenge_data
|
98
|
+
challenge.exec
|
99
|
+
end
|
78
100
|
end
|
79
101
|
|
80
102
|
# Registers a {Polytrix::Validator} that will be used during test
|
@@ -91,11 +113,12 @@ module Polytrix
|
|
91
113
|
end
|
92
114
|
|
93
115
|
def load_tests
|
116
|
+
manifest.build_challenges
|
94
117
|
Polytrix::RSpec.run_manifest(manifest)
|
95
118
|
end
|
96
119
|
|
97
120
|
# Runs all of the tests described in the {manifest}
|
98
|
-
def
|
121
|
+
def verify(implementors = [])
|
99
122
|
test_env = ENV['TEST_ENV_NUMBER'].to_i
|
100
123
|
rspec_options = %W[--color -f documentation -f Polytrix::RSpec::YAMLReport -o reports/test_report#{test_env}.yaml]
|
101
124
|
rspec_options.concat Polytrix.configuration.rspec_options.split if Polytrix.configuration.rspec_options
|
@@ -128,15 +151,12 @@ module Polytrix
|
|
128
151
|
yield(configuration)
|
129
152
|
end
|
130
153
|
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
merged_results.deep_merge! YAML.load(File.read(result_file))
|
138
|
-
end
|
139
|
-
YAML.dump(merged_results.to_hash)
|
154
|
+
# Returns whether or not standard output is associated with a terminal
|
155
|
+
# device (tty).
|
156
|
+
#
|
157
|
+
# @return [true,false] is there a tty?
|
158
|
+
def tty?
|
159
|
+
$stdout.tty?
|
140
160
|
end
|
141
161
|
|
142
162
|
protected
|
@@ -149,7 +169,7 @@ module Polytrix
|
|
149
169
|
sdk_dir = File.absolute_path(sdk)
|
150
170
|
implementors.find { |i| File.absolute_path(i.basedir) == sdk_dir } || configuration.implementor(sdk_dir)
|
151
171
|
else
|
152
|
-
implementor = implementors.find { |i| i.name == sdk }
|
172
|
+
implementor = implementors.find { |i| i.name.to_s.downcase == sdk.to_s.downcase }
|
153
173
|
fail ArgumentError, "SDK #{sdk} not found" if implementor.nil?
|
154
174
|
implementor
|
155
175
|
end
|
@@ -157,3 +177,5 @@ module Polytrix
|
|
157
177
|
end
|
158
178
|
end
|
159
179
|
end
|
180
|
+
|
181
|
+
Polytrix.mutex = Mutex.new
|
data/polytrix.gemspec
CHANGED
@@ -19,10 +19,12 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "thor", "~> 0.19"
|
22
|
-
spec.add_dependency "
|
22
|
+
spec.add_dependency "logging", "~> 1.8"
|
23
|
+
spec.add_dependency "mixlib-shellout", "~> 1.3" # Used for MRI
|
24
|
+
spec.add_dependency "buff-shell_out", "~> 0.1" # Used for JRuby
|
23
25
|
spec.add_dependency "middleware", "~> 0.1"
|
24
26
|
spec.add_dependency "rspec", "~> 2.99"
|
25
|
-
spec.add_dependency "hashie", "~>
|
27
|
+
spec.add_dependency "hashie", "~> 3.0"
|
26
28
|
spec.add_dependency "padrino-helpers", "~> 0.12"
|
27
29
|
spec.add_development_dependency "bundler", "~> 1.5"
|
28
30
|
spec.add_development_dependency "rake"
|
data/polytrix.rb
CHANGED
@@ -3,12 +3,5 @@
|
|
3
3
|
# This example shows the default behavior of `Polytrix#bootstrap`
|
4
4
|
require 'polytrix'
|
5
5
|
|
6
|
-
Polytrix.configure do |polytrix|
|
7
|
-
Dir['sdks/*'].each do |sdk|
|
8
|
-
name = File.basename(sdk)
|
9
|
-
polytrix.implementor name: name, basedir: sdk
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
6
|
# Snippet: bootstrap
|
14
7
|
Polytrix.bootstrap
|
data/samples/polytrix.rb
CHANGED
@@ -1,14 +1,5 @@
|
|
1
1
|
require 'polytrix'
|
2
2
|
|
3
|
-
basedir = File.expand_path('..', __FILE__)
|
4
|
-
|
5
|
-
Polytrix.configure do |polytrix|
|
6
|
-
Dir["#{basedir}/sdks/*"].each do |sdk|
|
7
|
-
name = File.basename(sdk)
|
8
|
-
polytrix.implementor name: name, basedir: sdk
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
3
|
RSpec.configure do |c|
|
13
4
|
c.expose_current_running_example_as :example
|
14
5
|
end
|
@@ -1,4 +1,15 @@
|
|
1
1
|
---
|
2
|
+
implementors:
|
3
|
+
ruby:
|
4
|
+
language: 'ruby'
|
5
|
+
basedir: 'sdks/ruby'
|
6
|
+
java:
|
7
|
+
language: 'java'
|
8
|
+
basedir: 'sdks/java'
|
9
|
+
python:
|
10
|
+
language: 'python'
|
11
|
+
basedir: 'sdks/python'
|
12
|
+
|
2
13
|
global_env: # global_env defines input available for all scenarios
|
3
14
|
LOCALE: <%= ENV['LANG'] %> # templating is allowed
|
4
15
|
suites:
|
data/samples/polytrix_cli.sh
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env bash -e
|
2
2
|
bundle exec polytrix bootstrap
|
3
3
|
bundle exec polytrix exec sdks/ruby/challenges/*.rb --code2doc --target-dir=docs/ruby/
|
4
|
-
bundle exec polytrix test
|
4
|
+
# bundle exec polytrix test
|
5
5
|
bundle exec polytrix report summary
|
6
6
|
bundle exec polytrix report summary --format=markdown
|
7
7
|
bundle exec polytrix report summary --format=yaml
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'hashie/mash'
|
2
|
+
|
3
|
+
# Fabricates test manifests (.polytrix.yml files)
|
4
|
+
LANGUAGES = %w(java ruby python nodejs c# golang php)
|
5
|
+
SAMPLE_NAMES = [
|
6
|
+
'hello world',
|
7
|
+
'quine',
|
8
|
+
'my_kata'
|
9
|
+
]
|
10
|
+
|
11
|
+
Fabricator(:implementor, from: Polytrix::Implementor) do
|
12
|
+
initialize_with { @_klass.new to_hash } # Hash based initialization
|
13
|
+
language { LANGUAGES.sample }
|
14
|
+
name do |attr|
|
15
|
+
"my_#{attr[:language]}_project"
|
16
|
+
end
|
17
|
+
basedir do |attr|
|
18
|
+
"sdks/#{attr[:name]}"
|
19
|
+
end
|
20
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'hashie/mash'
|
2
2
|
|
3
|
-
# Fabricates test manifests (.
|
3
|
+
# Fabricates test manifests (.polytrix.yml files)
|
4
4
|
LANGUAGES = %w(java ruby python nodejs c# golang php)
|
5
5
|
SAMPLE_NAMES = [
|
6
6
|
'hello world',
|
@@ -12,6 +12,9 @@ Fabricator(:manifest, from: Polytrix::Manifest) do
|
|
12
12
|
initialize_with { @_klass.new to_hash } # Hash based initialization
|
13
13
|
transient suite_count: 3
|
14
14
|
transient samples_per_suite: 3
|
15
|
+
implementors do
|
16
|
+
Fabricate(:implementor)
|
17
|
+
end
|
15
18
|
global_env do
|
16
19
|
{
|
17
20
|
VAR1: 1,
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module Polytrix
|
2
2
|
describe ChallengeRunner do
|
3
3
|
subject(:runner) { ChallengeRunner.create_runner }
|
4
|
+
let(:implementor) { Fabricate(:implementor) }
|
4
5
|
let(:challenge) do
|
5
|
-
Fabricate(:challenge, name: 'factorial', source_file: 'spec/fixtures/factorial.py', basedir: 'spec/fixtures')
|
6
|
+
Fabricate(:challenge, name: 'factorial', source_file: 'spec/fixtures/factorial.py', basedir: 'spec/fixtures', implementor: implementor)
|
6
7
|
end
|
7
8
|
|
8
9
|
describe '#run_challenge' do
|
9
10
|
it 'executes a challenge' do
|
10
|
-
expect(runner.run_challenge challenge).to be_an_instance_of
|
11
|
+
expect(runner.run_challenge challenge).to be_an_instance_of Result
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
@@ -5,14 +5,15 @@ module Polytrix
|
|
5
5
|
implementor.build_challenge name: 'factorial', vars: {}
|
6
6
|
end
|
7
7
|
|
8
|
-
describe '#
|
8
|
+
describe '#exec' do
|
9
9
|
it 'executes the challenge and returns itself' do
|
10
|
-
expect(challenge.
|
11
|
-
expect(challenge.
|
10
|
+
expect(challenge.exec).to be_an_instance_of Challenge
|
11
|
+
expect(challenge.exec).to eq(challenge)
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'stores the result' do
|
15
|
-
|
15
|
+
result = challenge.exec[:result]
|
16
|
+
expect(result).to be_an_instance_of Result
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/spec/polytrix/cli_spec.rb
CHANGED
@@ -2,36 +2,33 @@ require 'spec_helper'
|
|
2
2
|
require 'polytrix/cli'
|
3
3
|
|
4
4
|
module Polytrix
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
5
|
+
describe CLI do
|
6
|
+
let(:kernel) { double(:kernel) }
|
7
|
+
subject { ThorSpy.on(described_class, kernel) }
|
8
|
+
describe 'bootstrap' do
|
9
|
+
context 'with no args' do
|
10
|
+
it 'calls bootstrap on each implementor' do
|
11
|
+
expect(kernel).to receive(:exit).with(0)
|
12
|
+
# TODO: Any way to test each implementor is called? We can't use
|
13
|
+
# `Polytrix.implementors` because it will be reloaded.
|
14
|
+
subject.bootstrap
|
16
15
|
end
|
16
|
+
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
expect(@implementor).to receive(:bootstrap)
|
25
|
-
expect(kernel).to receive(:exit).with(0)
|
26
|
-
expect(subject.stderr.string).to eq('')
|
27
|
-
subject.bootstrap('test')
|
28
|
-
end
|
18
|
+
context 'with an existing SDK' do
|
19
|
+
xit 'calls bootstrap on the SDK' do
|
20
|
+
# expect(@implementor).to receive(:bootstrap)
|
21
|
+
expect(kernel).to receive(:exit).with(0)
|
22
|
+
expect(subject.stderr.string).to eq('')
|
23
|
+
subject.bootstrap('test')
|
29
24
|
end
|
25
|
+
end
|
30
26
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
context 'with an non-existant SDK' do
|
28
|
+
it 'fails' do
|
29
|
+
expect(kernel).to receive(:exit).with(1)
|
30
|
+
subject.bootstrap('missing')
|
31
|
+
expect(subject.stdout.string).to include('No scenarios for regex')
|
35
32
|
end
|
36
33
|
end
|
37
34
|
end
|