paraduct 0.0.1.beta3 → 0.0.1.beta4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --markup markdown
2
+ --no-private
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## master
2
+ [full changelog](http://github.com/sue445/paraduct/compare/v0.0.1...master)
3
+
4
+ ## v0.0.1
5
+ * first release
data/README.md CHANGED
@@ -5,10 +5,13 @@
5
5
  [![Coverage Status](https://img.shields.io/coveralls/sue445/paraduct.svg)](https://coveralls.io/r/sue445/paraduct)
6
6
  [![Dependency Status](https://gemnasium.com/sue445/paraduct.svg)](https://gemnasium.com/sue445/paraduct)
7
7
 
8
- TODO: Write a gem description
8
+ Paraduct (**parallel** + **parameterize** + **product**) is matrix test runner
9
9
 
10
10
  [![Stories in Ready](https://badge.waffle.io/sue445/paraduct.svg?label=ready&title=Ready)](http://waffle.io/sue445/paraduct)
11
11
 
12
+ ## Requirements
13
+ ruby 1.9+
14
+
12
15
  ## Installation
13
16
 
14
17
  Add this line to your application's Gemfile:
@@ -26,8 +29,64 @@ Or install it yourself as:
26
29
  $ gem install paraduct
27
30
 
28
31
  ## Usage
32
+ ```bash
33
+ $ paraduct --help
34
+ Commands:
35
+ paraduct generate # generate .paraduct.yml
36
+ paraduct help [COMMAND] # Describe available commands or one specific command
37
+ paraduct test # run matrix test
38
+ ```
39
+
40
+ ### 1. Generate config file
41
+ ```bash
42
+ $ paraduct generate
43
+ create .paraduct.yml
44
+ ```
45
+
46
+ ### 2. Customize .paraduct.yml
47
+ ```bash
48
+ $ vi .paraduct.yml
49
+ ```
50
+
51
+ ### 3. Run test
52
+ ```bash
53
+ $ paraduct test
54
+ ```
55
+
56
+ ## Format
57
+ ```yaml
58
+ script: |-
59
+ echo "NAME1=${NAME1}, NAME2=${NAME2}"
60
+ work_dir: tmp/paraduct_workspace
61
+ variables:
62
+ name1:
63
+ - value1a
64
+ - value1b
65
+ name2:
66
+ - value2a
67
+ - value2b
68
+ ```
69
+
70
+ ### script
71
+ script to run
72
+
73
+ ### work_dir
74
+ diretory to run
75
+
76
+ * own job is run under `work_dir/JOB_NAME`
77
+
78
+ ### variables
79
+ Parameters to be combined
80
+
81
+ * key is capitalized (example. `name1` -> `NAME1`)
82
+ * JOB_NAME is generated with variables
29
83
 
30
- TODO: Write usage instructions here
84
+ name1 | name2 | JOB_NAME | current directory where the test is performed
85
+ ------- | ------- | ----------------------------- | ---------------------------------------
86
+ value1a | value2a | NAME1_value1a_NAME2_value2a | tmp/paraduct_workspace/NAME1_value1a_NAME2_value2a
87
+ value1a | value2b | NAME1_value1a_NAME2_value2b | tmp/paraduct_workspace/NAME1_value1a_NAME2_value2b
88
+ value1b | value2a | NAME1_value1b_NAME2_value2a | tmp/paraduct_workspace/NAME1_value1b_NAME2_value2a
89
+ value1b | value2b | NAME1_value1b_NAME2_value2b | tmp/paraduct_workspace/NAME1_value1b_NAME2_value2b
31
90
 
32
91
  ## Contributing
33
92
 
data/Rakefile CHANGED
@@ -1,7 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
+ require 'yard'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
5
6
 
6
7
  task :default => :spec
7
8
 
9
+ YARD::Rake::YardocTask.new
data/lib/paraduct.rb CHANGED
@@ -6,6 +6,8 @@ require "paraduct/configuration"
6
6
  require "paraduct/variable_converter"
7
7
  require "paraduct/runner"
8
8
  require "paraduct/parallel_runner"
9
+ require "paraduct/errors"
10
+ require "paraduct/test_response"
9
11
  require "pathname"
10
12
 
11
13
  module Paraduct
data/lib/paraduct/cli.rb CHANGED
@@ -14,7 +14,9 @@ module Paraduct
14
14
  raise "require variables" if variables.blank?
15
15
 
16
16
  product_variables = Paraduct::VariableConverter.product(variables)
17
- Paraduct::ParallelRunner.perform_all(script, product_variables)
17
+ test_response = Paraduct::ParallelRunner.perform_all(script, product_variables)
18
+ puts test_response.detail_message
19
+ raise Paraduct::TestFailureError if test_response.failure?
18
20
  end
19
21
 
20
22
  desc "generate", "generate .paraduct.yml"
@@ -10,23 +10,28 @@ module Paraduct
10
10
  @config = YAML.load_file(config_file)
11
11
  end
12
12
 
13
+ # @return [Pathname]
13
14
  def variables
14
15
  @config["variables"]
15
16
  end
16
17
 
18
+ # @return [String, Array<String>]
17
19
  def script
18
20
  @config["script"]
19
21
  end
20
22
 
23
+ # @return [Pathname]
21
24
  def work_dir
22
25
  _work_dir = @config["work_dir"] || "tmp/paraduct_workspace"
23
26
  root_dir.join(_work_dir)
24
27
  end
25
28
 
29
+ # @return [Pathname]
26
30
  def config_file
27
31
  root_dir.join(".paraduct.yml")
28
32
  end
29
33
 
34
+ # @return [Pathname]
30
35
  def root_dir
31
36
  Pathname.pwd
32
37
  end
@@ -0,0 +1,14 @@
1
+ module Paraduct
2
+ class TestFailureError < StandardError; end
3
+
4
+ class ProcessError < StandardError
5
+ attr_reader :status
6
+
7
+ # @param message [String] stdout and stderr
8
+ # @param status [Process::Status]
9
+ def initialize(message, status)
10
+ super(message)
11
+ @status = status
12
+ end
13
+ end
14
+ end
@@ -1,11 +1,12 @@
1
1
  module Paraduct
2
2
  class ParallelRunner
3
+ # run script with arguments
3
4
  # @param script [String, Array<String>] script file, script(s)
4
5
  # @param product_variables [Array<Hash{String => String}>]
5
- # @return [Array<String>] stdout messages of each job
6
+ # @return [Paraduct::TestResponse]
6
7
  def self.perform_all(script, product_variables)
7
8
  threads = []
8
- stdout_messages = []
9
+ test_response = Paraduct::TestResponse.new
9
10
  base_job_dir = Paraduct.config.work_dir
10
11
  FileUtils.mkdir_p(base_job_dir) unless base_job_dir.exist?
11
12
 
@@ -18,52 +19,42 @@ START matrix test
18
19
  end
19
20
 
20
21
  product_variables.each do |params|
21
- threads << Thread.new(base_job_dir, script, params) do |_base_job_dir, _script, _params|
22
- job_dir = setup_runner(_base_job_dir, _params)
23
- stdout =
24
- begin
25
- Paraduct::Runner.perform(_script, _params)
26
- rescue Paraduct::ProcessError => e
27
- e.message
28
- end
22
+ runner = Paraduct::Runner.new(
23
+ script: script,
24
+ params: params,
25
+ base_job_dir: base_job_dir,
26
+ )
27
+ threads << Thread.new(runner) do |_runner|
28
+ _runner.setup_dir
29
+ begin
30
+ stdout = _runner.perform
31
+ successful = true
32
+ rescue Paraduct::ProcessError => e
33
+ stdout = e.message
34
+ successful = false
35
+ end
29
36
 
30
37
  puts <<-EOS
31
38
  ======================================================
32
- params: #{_params}
33
- job_dir: #{job_dir}
39
+ params: #{_runner.formatted_params}
40
+ job_name: #{_runner.job_name}
41
+ job_dir: #{_runner.job_dir}
34
42
 
35
43
  #{stdout}
36
44
  EOS
37
45
 
38
- stdout_messages << stdout
46
+ test_response.jobs_push(
47
+ job_name: _runner.job_name,
48
+ params: _runner.params,
49
+ formatted_params: _runner.formatted_params,
50
+ successful: successful,
51
+ stdout: stdout,
52
+ )
39
53
  end
40
54
  end
41
55
  threads.map(&:join)
42
56
 
43
- stdout_messages
57
+ test_response
44
58
  end
45
-
46
- # @param source_dir [Pathname]
47
- # @param destination_dir [Pathname]
48
- def self.copy_recursive(source_dir, destination_dir)
49
- FileUtils.mkdir_p(destination_dir)
50
- source_dir.children.each do |source_child_dir|
51
- begin
52
- FileUtils.cp_r(source_child_dir, destination_dir)
53
- rescue ArgumentError => e
54
- # TODO: refactoring
55
- raise unless e.message =~ /^cannot copy directory .+ to itself /
56
- end
57
- end
58
- end
59
-
60
- def self.setup_runner(base_job_dir, params)
61
- job_dir = Paraduct::Runner.parameterized_job_dir(base_job_dir, params)
62
- FileUtils.mkdir_p(job_dir) unless job_dir.exist?
63
- copy_recursive(Paraduct.config.root_dir, job_dir)
64
- Dir.chdir(job_dir)
65
- job_dir
66
- end
67
- private_class_method :setup_runner
68
59
  end
69
60
  end
@@ -1,43 +1,66 @@
1
1
  module Paraduct
2
2
  require "open3"
3
3
 
4
- class ProcessError < StandardError
5
- attr_reader :status
4
+ class Runner
5
+ attr_reader :script, :params, :base_job_dir
6
6
 
7
- # @param message [String] stdout and stderr
8
- # @param status [Process::Status]
9
- def initialize(message, status)
10
- super(message)
11
- @status = status
7
+ # @param args
8
+ # @option args :script [String, Array<String>] script file, script(s)
9
+ # @option args :params [Hash{String => String}] key is capitalized and value is quoted (ex. foo=1 => FOO="1" )
10
+ # @option args :base_job_dir [String]
11
+ def initialize(args={})
12
+ @script = args[:script]
13
+ @params = args[:params]
14
+ @base_job_dir = args[:base_job_dir]
15
+ end
16
+
17
+ def setup_dir
18
+ FileUtils.mkdir_p(job_dir) unless job_dir.exist?
19
+ self.class.copy_recursive(Paraduct.config.root_dir, job_dir)
20
+ Dir.chdir(job_dir)
12
21
  end
13
- end
14
22
 
15
- class Runner
16
23
  # run script with params
17
- # @param script [String, Array<String>] script file, script(s)
18
- # @param params [Hash{String => String}] key is capitalized and value is quoted (ex. foo=1 => FOO="1" )
19
24
  # @return [String] stdout
20
25
  # @raise [Paraduct::ProcessError] command exited error status
21
- def self.perform(script, params)
22
- variable_string = capitalize_keys(params).map{ |key, value| %(export #{key}="#{value}";) }.join(" ")
26
+ def perform
27
+ variable_string = key_capitalized_params.map{ |key, value| %(export #{key}="#{value}";) }.join(" ")
23
28
 
24
- Array.wrap(script).inject("") do |stdout, command|
29
+ Array.wrap(@script).inject("") do |stdout, command|
25
30
  stdout << run_command("#{variable_string} #{command}")
26
31
  stdout
27
32
  end
28
33
  end
29
34
 
30
- def self.parameterized_job_dir(base_job_dir, params)
31
- dir_name = capitalize_keys(params).map{ |key, value| "#{key}_#{value}" }.join("_")
32
- Pathname(base_job_dir).join(dir_name)
35
+ def job_dir
36
+ Pathname(@base_job_dir).join(job_name)
33
37
  end
34
38
 
35
- def self.run_command(command)
36
- stdout, stderr, status = Open3.capture3(command)
37
- raise ProcessError.new("#{stdout}\n#{stderr}", status) unless status.success?
38
- stdout
39
+ def job_name
40
+ key_capitalized_params.map { |key, value| "#{key}_#{value}" }.join("_")
41
+ end
42
+
43
+ def key_capitalized_params
44
+ self.class.capitalize_keys(@params)
45
+ end
46
+
47
+ def formatted_params
48
+ @params.map{ |key, value| "#{key}=#{value}" }.join(", ")
49
+ end
50
+
51
+ # @param source_dir [Pathname]
52
+ # @param destination_dir [Pathname]
53
+ def self.copy_recursive(source_dir, destination_dir)
54
+ FileUtils.mkdir_p(destination_dir)
55
+ source_dir.children.each do |source_child_dir|
56
+ begin
57
+ FileUtils.cp_r(source_child_dir, destination_dir)
58
+ rescue ArgumentError => e
59
+ # TODO: refactoring
60
+ raise unless e.message =~ /^cannot copy directory .+ to itself /
61
+ end
62
+ end
39
63
  end
40
- private_class_method :run_command
41
64
 
42
65
  def self.capitalize_keys(params)
43
66
  params.inject({}) do |res, (key, value)|
@@ -45,6 +68,12 @@ module Paraduct
45
68
  res
46
69
  end
47
70
  end
48
- private_class_method :capitalize_keys
71
+
72
+ private
73
+ def run_command(command)
74
+ stdout, stderr, status = Open3.capture3(command)
75
+ raise Paraduct::ProcessError.new("#{stdout}\n#{stderr}", status) unless status.success?
76
+ stdout
77
+ end
49
78
  end
50
79
  end
@@ -0,0 +1,38 @@
1
+ module Paraduct
2
+ class TestResponse
3
+ attr_reader :jobs
4
+
5
+ def initialize
6
+ @jobs = []
7
+ end
8
+
9
+ delegate :push, to: :jobs, prefix: true
10
+
11
+ def successful?
12
+ @jobs.all?{ |result| result[:successful] }
13
+ end
14
+
15
+ def failure?
16
+ !successful?
17
+ end
18
+
19
+ def detail_message
20
+ all_count = @jobs.count
21
+ successful_count = @jobs.select{ |result| result[:successful] }.count
22
+ failure_count = all_count - successful_count
23
+
24
+ message = "======================================================\n"
25
+
26
+ if failure_count > 0
27
+ message << "Failures:\n\n"
28
+ @jobs.select{ |result| !result[:successful] }.each_with_index do |result, i|
29
+ message << " #{i + 1}) #{result[:formatted_params]}\n"
30
+ end
31
+ message << "\n"
32
+ end
33
+ message << "#{all_count} jobs, #{failure_count} failures, #{successful_count} passed\n"
34
+
35
+ message
36
+ end
37
+ end
38
+ end
@@ -1,3 +1,3 @@
1
1
  module Paraduct
2
- VERSION = "0.0.1.beta3"
2
+ VERSION = "0.0.1.beta4"
3
3
  end
data/paraduct.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["sue445"]
10
10
  spec.email = ["sue445@sue445.net"]
11
11
  spec.summary = %q{matrix test runner}
12
- spec.description = %q{matrix test runner}
12
+ spec.description = %q{Paraduct(parallel + parameterize + product) is matrix test runner}
13
13
  spec.homepage = "https://github.com/sue445/paraduct"
14
14
  spec.license = "MIT"
15
15
 
@@ -28,7 +28,10 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "pry-nav"
29
29
  spec.add_development_dependency "pry-remote"
30
30
  spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "redcarpet"
31
32
  spec.add_development_dependency "rspec", "~> 3.1.0"
32
33
  spec.add_development_dependency "rspec-collection_matchers"
34
+ spec.add_development_dependency "rspec-its"
33
35
  spec.add_development_dependency "rspec-temp_dir"
36
+ spec.add_development_dependency "yard"
34
37
  end
data/spec/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ inherit_from:
2
+ - ../.hound.yml
3
+
4
+ Style/Blocks:
5
+ Enabled: false
@@ -8,33 +8,50 @@ describe Paraduct::CLI do
8
8
 
9
9
  include_context :within_temp_work_dir
10
10
 
11
- let(:script){ "./script/build_success.sh" }
12
- let(:product_variables) do
13
- [
14
- { "ruby" => "1.9.3", "database" => "mysql" , "rails" => "3.2.0" },
15
- { "ruby" => "1.9.3", "database" => "mysql" , "rails" => "4.0.0" },
16
- { "ruby" => "1.9.3", "database" => "mysql" , "rails" => "4.1.0" },
17
- { "ruby" => "1.9.3", "database" => "postgresql", "rails" => "3.2.0" },
18
- { "ruby" => "1.9.3", "database" => "postgresql", "rails" => "4.0.0" },
19
- { "ruby" => "1.9.3", "database" => "postgresql", "rails" => "4.1.0" },
20
- { "ruby" => "2.0.0", "database" => "mysql" , "rails" => "3.2.0" },
21
- { "ruby" => "2.0.0", "database" => "mysql" , "rails" => "4.0.0" },
22
- { "ruby" => "2.0.0", "database" => "mysql" , "rails" => "4.1.0" },
23
- { "ruby" => "2.0.0", "database" => "postgresql", "rails" => "3.2.0" },
24
- { "ruby" => "2.0.0", "database" => "postgresql", "rails" => "4.0.0" },
25
- { "ruby" => "2.0.0", "database" => "postgresql", "rails" => "4.1.0" },
26
- { "ruby" => "2.1.2", "database" => "mysql" , "rails" => "3.2.0" },
27
- { "ruby" => "2.1.2", "database" => "mysql" , "rails" => "4.0.0" },
28
- { "ruby" => "2.1.2", "database" => "mysql" , "rails" => "4.1.0" },
29
- { "ruby" => "2.1.2", "database" => "postgresql", "rails" => "3.2.0" },
30
- { "ruby" => "2.1.2", "database" => "postgresql", "rails" => "4.0.0" },
31
- { "ruby" => "2.1.2", "database" => "postgresql", "rails" => "4.1.0" },
32
- ]
11
+ context "successful test" do
12
+ let(:script){ "./script/build_success.sh" }
13
+ let(:product_variables) do
14
+ [
15
+ { "ruby" => "1.9.3", "database" => "mysql" , "rails" => "3.2.0" },
16
+ { "ruby" => "1.9.3", "database" => "mysql" , "rails" => "4.0.0" },
17
+ { "ruby" => "1.9.3", "database" => "mysql" , "rails" => "4.1.0" },
18
+ { "ruby" => "1.9.3", "database" => "postgresql", "rails" => "3.2.0" },
19
+ { "ruby" => "1.9.3", "database" => "postgresql", "rails" => "4.0.0" },
20
+ { "ruby" => "1.9.3", "database" => "postgresql", "rails" => "4.1.0" },
21
+ { "ruby" => "2.0.0", "database" => "mysql" , "rails" => "3.2.0" },
22
+ { "ruby" => "2.0.0", "database" => "mysql" , "rails" => "4.0.0" },
23
+ { "ruby" => "2.0.0", "database" => "mysql" , "rails" => "4.1.0" },
24
+ { "ruby" => "2.0.0", "database" => "postgresql", "rails" => "3.2.0" },
25
+ { "ruby" => "2.0.0", "database" => "postgresql", "rails" => "4.0.0" },
26
+ { "ruby" => "2.0.0", "database" => "postgresql", "rails" => "4.1.0" },
27
+ { "ruby" => "2.1.2", "database" => "mysql" , "rails" => "3.2.0" },
28
+ { "ruby" => "2.1.2", "database" => "mysql" , "rails" => "4.0.0" },
29
+ { "ruby" => "2.1.2", "database" => "mysql" , "rails" => "4.1.0" },
30
+ { "ruby" => "2.1.2", "database" => "postgresql", "rails" => "3.2.0" },
31
+ { "ruby" => "2.1.2", "database" => "postgresql", "rails" => "4.0.0" },
32
+ { "ruby" => "2.1.2", "database" => "postgresql", "rails" => "4.1.0" },
33
+ ]
34
+ end
35
+
36
+ let(:test_response) do
37
+ test_response = Paraduct::TestResponse.new
38
+ test_response.jobs_push(successful: true)
39
+ test_response
40
+ end
41
+
42
+ it "should call perform_all" do
43
+ expect(Paraduct::ParallelRunner).to receive(:perform_all).with(script, product_variables){ test_response }
44
+ subject
45
+ end
33
46
  end
34
47
 
35
- it "should call perform_all" do
36
- expect(Paraduct::ParallelRunner).to receive(:perform_all).with(script, product_variables)
37
- subject
48
+ context "failure test" do
49
+ before do
50
+ allow(Paraduct.config).to receive(:script) { %q(exit ${STATUS}) }
51
+ allow(Paraduct.config).to receive(:variables){ { status: [0, 1] } }
52
+ end
53
+
54
+ it { expect{ subject }.to raise_error Paraduct::TestFailureError }
38
55
  end
39
56
  end
40
57
 
@@ -25,8 +25,25 @@ describe Paraduct::ParallelRunner do
25
25
  ]
26
26
  end
27
27
 
28
- it { should include "RUBY=1.9\nDATABASE=mysql\n" }
29
- it { should include "RUBY=2.0\nDATABASE=postgresql\n" }
28
+ its(:jobs) do
29
+ should include(
30
+ job_name: "RUBY_1.9_DATABASE_mysql",
31
+ params: { "ruby" => "1.9", "database" => "mysql" },
32
+ formatted_params: "ruby=1.9, database=mysql",
33
+ successful: true,
34
+ stdout: "RUBY=1.9\nDATABASE=mysql\n"
35
+ )
36
+ end
37
+
38
+ its(:jobs) do
39
+ should include(
40
+ job_name: "RUBY_2.0_DATABASE_postgresql",
41
+ params: { "ruby" => "2.0", "database" => "postgresql" },
42
+ formatted_params: "ruby=2.0, database=postgresql",
43
+ successful: true,
44
+ stdout: "RUBY=2.0\nDATABASE=postgresql\n"
45
+ )
46
+ end
30
47
 
31
48
  describe "should create job directories" do
32
49
  before do
@@ -53,8 +70,25 @@ describe Paraduct::ParallelRunner do
53
70
  ]
54
71
  end
55
72
 
56
- it { should include "RUBY=1.9 DATABASE=mysql\n" }
57
- it { should include "RUBY=2.0 DATABASE=postgresql\n" }
73
+ its(:jobs) do
74
+ should include(
75
+ job_name: "RUBY_1.9_DATABASE_mysql",
76
+ params: { "ruby" => "1.9", "database" => "mysql" },
77
+ formatted_params: "ruby=1.9, database=mysql",
78
+ successful: true,
79
+ stdout: "RUBY=1.9 DATABASE=mysql\n"
80
+ )
81
+ end
82
+
83
+ its(:jobs) do
84
+ should include(
85
+ job_name: "RUBY_2.0_DATABASE_postgresql",
86
+ params: { "ruby" => "2.0", "database" => "postgresql" },
87
+ formatted_params: "ruby=2.0, database=postgresql",
88
+ successful: true,
89
+ stdout: "RUBY=2.0 DATABASE=postgresql\n"
90
+ )
91
+ end
58
92
 
59
93
  describe "should create job directories" do
60
94
  before do
@@ -72,32 +106,4 @@ describe Paraduct::ParallelRunner do
72
106
  end
73
107
  end
74
108
  end
75
-
76
- describe "#copy_recursive" do
77
- subject{ Paraduct::ParallelRunner.copy_recursive(source_dir, destination_dir) }
78
-
79
- include_context "uses temp dir"
80
-
81
- let(:source_dir) { temp_dir_path }
82
- let(:destination_dir){ temp_dir_path.join("tmp/paraduct_workspace/RUBY_1.9_DATABASE_mysql") }
83
- let(:copied_file) { destination_dir.join("build_success.sh") }
84
- let(:not_copied_file){ destination_dir.join("tmp/paraduct_workspace/dummy.txt") }
85
-
86
- before do
87
- # setup
88
- FileUtils.cp_r(spec_dir.join("script/tmp/paraduct_workspace"), source_dir)
89
- FileUtils.cp_r(spec_dir.join("script/build_success.sh"), source_dir)
90
-
91
- # exercise
92
- subject
93
- end
94
-
95
- # after do
96
- # puts `tree #{source_dir}`
97
- # end
98
-
99
- it { expect(destination_dir).to be_exist }
100
- it { expect(copied_file).to be_exist }
101
- it { expect(not_copied_file).not_to be_exist }
102
- end
103
109
  end
@@ -1,6 +1,18 @@
1
1
  describe Paraduct::Runner do
2
+ let(:runner) do
3
+ Paraduct::Runner.new(
4
+ script: script,
5
+ params: params,
6
+ base_job_dir: base_job_dir,
7
+ )
8
+ end
9
+
10
+ let(:base_job_dir){ "/tmp/jobs" }
11
+ let(:script) { "" }
12
+ let(:params) { {} }
13
+
2
14
  describe "#perform" do
3
- subject{ Paraduct::Runner.perform(script, params) }
15
+ subject{ runner.perform }
4
16
 
5
17
  let(:script) { "./script/build_success.sh" }
6
18
  let(:params) { { "ruby" => "1.9", "database" => "mysql" } }
@@ -8,7 +20,7 @@ describe Paraduct::Runner do
8
20
 
9
21
  context "with mock system" do
10
22
  it "script is call with capitalized variable" do
11
- expect(Paraduct::Runner).to receive(:run_command).with(command).and_return("stdout")
23
+ expect(runner).to receive(:run_command).with(command).and_return("stdout")
12
24
  subject
13
25
  end
14
26
  end
@@ -49,12 +61,47 @@ DATABASE=mysql
49
61
  end
50
62
  end
51
63
 
52
- describe "#parameterized_job_dir" do
53
- subject{ Paraduct::Runner.parameterized_job_dir(base_job_dir, params) }
64
+ describe "#job_dir" do
65
+ subject{ runner.job_dir }
54
66
 
55
- let(:base_job_dir){ "/tmp/jobs" }
56
- let(:params) { { "ruby" => "1.9", "database" => "mysql" } }
67
+ let(:params) { { "ruby" => "1.9", "database" => "mysql" } }
57
68
 
58
69
  it { should eq Pathname("/tmp/jobs/RUBY_1.9_DATABASE_mysql") }
59
70
  end
71
+
72
+ describe "#copy_recursive" do
73
+ subject{ Paraduct::Runner.copy_recursive(source_dir, destination_dir) }
74
+
75
+ include_context "uses temp dir"
76
+
77
+ let(:source_dir) { temp_dir_path }
78
+ let(:destination_dir){ temp_dir_path.join("tmp/paraduct_workspace/RUBY_1.9_DATABASE_mysql") }
79
+ let(:copied_file) { destination_dir.join("build_success.sh") }
80
+ let(:not_copied_file){ destination_dir.join("tmp/paraduct_workspace/dummy.txt") }
81
+
82
+ before do
83
+ # setup
84
+ FileUtils.cp_r(spec_dir.join("script/tmp/paraduct_workspace"), source_dir)
85
+ FileUtils.cp_r(spec_dir.join("script/build_success.sh"), source_dir)
86
+
87
+ # exercise
88
+ subject
89
+ end
90
+
91
+ # after do
92
+ # puts `tree #{source_dir}`
93
+ # end
94
+
95
+ it { expect(destination_dir).to be_exist }
96
+ it { expect(copied_file).to be_exist }
97
+ it { expect(not_copied_file).not_to be_exist }
98
+ end
99
+
100
+ describe "#formatted_params" do
101
+ subject{ runner.formatted_params }
102
+
103
+ let(:params){ { "ruby" => "1.9", "database" => "mysql" } }
104
+
105
+ it{ should eq "ruby=1.9, database=mysql" }
106
+ end
60
107
  end
@@ -0,0 +1,64 @@
1
+ describe Paraduct::TestResponse do
2
+ let(:test_response){ Paraduct::TestResponse.new }
3
+
4
+ describe "#successful?" do
5
+ subject{ test_response.successful? }
6
+
7
+ context "not include failure" do
8
+ before do
9
+ test_response.jobs_push(successful: true)
10
+ test_response.jobs_push(successful: true)
11
+ end
12
+
13
+ it { should be true }
14
+ end
15
+
16
+ context "include failure" do
17
+ before do
18
+ test_response.jobs_push(successful: true)
19
+ test_response.jobs_push(successful: false)
20
+ end
21
+
22
+ it { should be false }
23
+ end
24
+ end
25
+
26
+ describe "#detail_message" do
27
+ subject{ test_response.detail_message }
28
+
29
+ context "when successful" do
30
+ before do
31
+ test_response.jobs_push(successful: true)
32
+ test_response.jobs_push(successful: true)
33
+ test_response.jobs_push(successful: true)
34
+ end
35
+
36
+ it do
37
+ should eq <<-EOS
38
+ ======================================================
39
+ 3 jobs, 0 failures, 3 passed
40
+ EOS
41
+ end
42
+ end
43
+
44
+ context "when failure" do
45
+ before do
46
+ test_response.jobs_push(successful: true)
47
+ test_response.jobs_push(successful: false, params: { "ruby" => "1.9", "database" => "mysql" } , formatted_params: "ruby=1.9, database=mysql")
48
+ test_response.jobs_push(successful: false, params: { "ruby" => "2.0", "database" => "postgresql" }, formatted_params: "ruby=2.0, database=postgresql")
49
+ end
50
+
51
+ it do
52
+ should eq <<-EOS
53
+ ======================================================
54
+ Failures:
55
+
56
+ 1) ruby=1.9, database=mysql
57
+ 2) ruby=2.0, database=postgresql
58
+
59
+ 3 jobs, 2 failures, 1 passed
60
+ EOS
61
+ end
62
+ end
63
+ end
64
+ end
data/spec/spec_helper.rb CHANGED
@@ -17,6 +17,7 @@ require 'paraduct'
17
17
  require 'paraduct/cli'
18
18
  require 'rspec/collection_matchers'
19
19
  require 'rspec/temp_dir'
20
+ require 'rspec/its'
20
21
  require 'pry'
21
22
 
22
23
  def spec_dir
@@ -115,4 +116,9 @@ RSpec.configure do |config|
115
116
  =end
116
117
 
117
118
  config.order = :random
119
+
120
+ config.before do
121
+ # quiet
122
+ allow(Object).to receive(:puts)
123
+ end
118
124
  end
metadata CHANGED
@@ -1,184 +1,257 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paraduct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.beta3
4
+ version: 0.0.1.beta4
5
+ prerelease: 6
5
6
  platform: ruby
6
7
  authors:
7
8
  - sue445
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-10-18 00:00:00.000000000 Z
12
+ date: 2014-10-19 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: activesupport
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - ">="
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - ">="
27
+ - - ! '>='
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0'
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: thor
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - ">="
35
+ - - ! '>='
32
36
  - !ruby/object:Gem::Version
33
37
  version: '0'
34
38
  type: :runtime
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - ">="
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
45
  version: '0'
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: bundler
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
- - - ">="
51
+ - - ! '>='
46
52
  - !ruby/object:Gem::Version
47
53
  version: '1.5'
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
- - - ">="
59
+ - - ! '>='
53
60
  - !ruby/object:Gem::Version
54
61
  version: '1.5'
55
62
  - !ruby/object:Gem::Dependency
56
63
  name: codeclimate-test-reporter
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
- - - ">="
67
+ - - ! '>='
60
68
  - !ruby/object:Gem::Version
61
69
  version: '0'
62
70
  type: :development
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
- - - ">="
75
+ - - ! '>='
67
76
  - !ruby/object:Gem::Version
68
77
  version: '0'
69
78
  - !ruby/object:Gem::Dependency
70
79
  name: coveralls
71
80
  requirement: !ruby/object:Gem::Requirement
81
+ none: false
72
82
  requirements:
73
- - - ">="
83
+ - - ! '>='
74
84
  - !ruby/object:Gem::Version
75
85
  version: '0'
76
86
  type: :development
77
87
  prerelease: false
78
88
  version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
79
90
  requirements:
80
- - - ">="
91
+ - - ! '>='
81
92
  - !ruby/object:Gem::Version
82
93
  version: '0'
83
94
  - !ruby/object:Gem::Dependency
84
95
  name: pry
85
96
  requirement: !ruby/object:Gem::Requirement
97
+ none: false
86
98
  requirements:
87
- - - ">="
99
+ - - ! '>='
88
100
  - !ruby/object:Gem::Version
89
101
  version: '0'
90
102
  type: :development
91
103
  prerelease: false
92
104
  version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
93
106
  requirements:
94
- - - ">="
107
+ - - ! '>='
95
108
  - !ruby/object:Gem::Version
96
109
  version: '0'
97
110
  - !ruby/object:Gem::Dependency
98
111
  name: pry-nav
99
112
  requirement: !ruby/object:Gem::Requirement
113
+ none: false
100
114
  requirements:
101
- - - ">="
115
+ - - ! '>='
102
116
  - !ruby/object:Gem::Version
103
117
  version: '0'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
107
122
  requirements:
108
- - - ">="
123
+ - - ! '>='
109
124
  - !ruby/object:Gem::Version
110
125
  version: '0'
111
126
  - !ruby/object:Gem::Dependency
112
127
  name: pry-remote
113
128
  requirement: !ruby/object:Gem::Requirement
129
+ none: false
114
130
  requirements:
115
- - - ">="
131
+ - - ! '>='
116
132
  - !ruby/object:Gem::Version
117
133
  version: '0'
118
134
  type: :development
119
135
  prerelease: false
120
136
  version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
121
138
  requirements:
122
- - - ">="
139
+ - - ! '>='
123
140
  - !ruby/object:Gem::Version
124
141
  version: '0'
125
142
  - !ruby/object:Gem::Dependency
126
143
  name: rake
127
144
  requirement: !ruby/object:Gem::Requirement
145
+ none: false
128
146
  requirements:
129
- - - "~>"
147
+ - - ~>
130
148
  - !ruby/object:Gem::Version
131
149
  version: '10.0'
132
150
  type: :development
133
151
  prerelease: false
134
152
  version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
135
154
  requirements:
136
- - - "~>"
155
+ - - ~>
137
156
  - !ruby/object:Gem::Version
138
157
  version: '10.0'
158
+ - !ruby/object:Gem::Dependency
159
+ name: redcarpet
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
139
174
  - !ruby/object:Gem::Dependency
140
175
  name: rspec
141
176
  requirement: !ruby/object:Gem::Requirement
177
+ none: false
142
178
  requirements:
143
- - - "~>"
179
+ - - ~>
144
180
  - !ruby/object:Gem::Version
145
181
  version: 3.1.0
146
182
  type: :development
147
183
  prerelease: false
148
184
  version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
149
186
  requirements:
150
- - - "~>"
187
+ - - ~>
151
188
  - !ruby/object:Gem::Version
152
189
  version: 3.1.0
153
190
  - !ruby/object:Gem::Dependency
154
191
  name: rspec-collection_matchers
155
192
  requirement: !ruby/object:Gem::Requirement
193
+ none: false
156
194
  requirements:
157
- - - ">="
195
+ - - ! '>='
158
196
  - !ruby/object:Gem::Version
159
197
  version: '0'
160
198
  type: :development
161
199
  prerelease: false
162
200
  version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
163
202
  requirements:
164
- - - ">="
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ - !ruby/object:Gem::Dependency
207
+ name: rspec-its
208
+ requirement: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ! '>='
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ! '>='
165
220
  - !ruby/object:Gem::Version
166
221
  version: '0'
167
222
  - !ruby/object:Gem::Dependency
168
223
  name: rspec-temp_dir
169
224
  requirement: !ruby/object:Gem::Requirement
225
+ none: false
226
+ requirements:
227
+ - - ! '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ - !ruby/object:Gem::Dependency
239
+ name: yard
240
+ requirement: !ruby/object:Gem::Requirement
241
+ none: false
170
242
  requirements:
171
- - - ">="
243
+ - - ! '>='
172
244
  - !ruby/object:Gem::Version
173
245
  version: '0'
174
246
  type: :development
175
247
  prerelease: false
176
248
  version_requirements: !ruby/object:Gem::Requirement
249
+ none: false
177
250
  requirements:
178
- - - ">="
251
+ - - ! '>='
179
252
  - !ruby/object:Gem::Version
180
253
  version: '0'
181
- description: matrix test runner
254
+ description: Paraduct(parallel + parameterize + product) is matrix test runner
182
255
  email:
183
256
  - sue445@sue445.net
184
257
  executables:
@@ -186,11 +259,13 @@ executables:
186
259
  extensions: []
187
260
  extra_rdoc_files: []
188
261
  files:
189
- - ".coveralls.yml"
190
- - ".gitignore"
191
- - ".hound.yml"
192
- - ".rspec"
193
- - ".travis.yml"
262
+ - .coveralls.yml
263
+ - .gitignore
264
+ - .hound.yml
265
+ - .rspec
266
+ - .travis.yml
267
+ - .yardopts
268
+ - CHANGELOG.md
194
269
  - Gemfile
195
270
  - LICENSE.txt
196
271
  - README.md
@@ -199,17 +274,21 @@ files:
199
274
  - lib/paraduct.rb
200
275
  - lib/paraduct/cli.rb
201
276
  - lib/paraduct/configuration.rb
277
+ - lib/paraduct/errors.rb
202
278
  - lib/paraduct/parallel_runner.rb
203
279
  - lib/paraduct/runner.rb
204
280
  - lib/paraduct/templates/.paraduct.yml.tt
281
+ - lib/paraduct/test_response.rb
205
282
  - lib/paraduct/variable_converter.rb
206
283
  - lib/paraduct/version.rb
207
284
  - paraduct.gemspec
208
285
  - spec/.paraduct.yml
286
+ - spec/.rubocop.yml
209
287
  - spec/paraduct/cli_spec.rb
210
288
  - spec/paraduct/configuration_spec.rb
211
289
  - spec/paraduct/parallel_runner_spec.rb
212
290
  - spec/paraduct/runner_spec.rb
291
+ - spec/paraduct/test_response_spec.rb
213
292
  - spec/paraduct/variable_converter_spec.rb
214
293
  - spec/paraduct_spec.rb
215
294
  - spec/script/build_error.sh
@@ -222,33 +301,39 @@ files:
222
301
  homepage: https://github.com/sue445/paraduct
223
302
  licenses:
224
303
  - MIT
225
- metadata: {}
226
304
  post_install_message:
227
305
  rdoc_options: []
228
306
  require_paths:
229
307
  - lib
230
308
  required_ruby_version: !ruby/object:Gem::Requirement
309
+ none: false
231
310
  requirements:
232
- - - ">="
311
+ - - ! '>='
233
312
  - !ruby/object:Gem::Version
234
313
  version: '0'
314
+ segments:
315
+ - 0
316
+ hash: 3632247312778024801
235
317
  required_rubygems_version: !ruby/object:Gem::Requirement
318
+ none: false
236
319
  requirements:
237
- - - ">"
320
+ - - ! '>'
238
321
  - !ruby/object:Gem::Version
239
322
  version: 1.3.1
240
323
  requirements: []
241
324
  rubyforge_project:
242
- rubygems_version: 2.2.2
325
+ rubygems_version: 1.8.23.2
243
326
  signing_key:
244
- specification_version: 4
327
+ specification_version: 3
245
328
  summary: matrix test runner
246
329
  test_files:
247
330
  - spec/.paraduct.yml
331
+ - spec/.rubocop.yml
248
332
  - spec/paraduct/cli_spec.rb
249
333
  - spec/paraduct/configuration_spec.rb
250
334
  - spec/paraduct/parallel_runner_spec.rb
251
335
  - spec/paraduct/runner_spec.rb
336
+ - spec/paraduct/test_response_spec.rb
252
337
  - spec/paraduct/variable_converter_spec.rb
253
338
  - spec/paraduct_spec.rb
254
339
  - spec/script/build_error.sh
@@ -257,3 +342,4 @@ test_files:
257
342
  - spec/spec_helper.rb
258
343
  - spec/support/contexts/within_spec_dir.rb
259
344
  - spec/support/contexts/within_temp_work_dir.rb
345
+ has_rdoc:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 2bfdf4b0f687c1c04c8bfc0f8c033f3caf15eea3
4
- data.tar.gz: 818e75eb679ccc987626cee5c2e230d0650040f8
5
- SHA512:
6
- metadata.gz: 2e5adbac7a7ae89fc4911a08cfcd98a8b25e5a3426dbfd60db7a933ebacb69240c32509ce9b0e8da1f75419bd2c418000b5ac57c89224ac56a139398ce95e3c7
7
- data.tar.gz: 20df8dfe7842b1ff4ef0ca5b5b130d0ae114aa063abb3ce84716f8c5c5d6a0c71c3d21ffb879bcd98b51d2549cdf5f86e08693f810e31919f80ca3e5e1d58e80