chemistrykit 2.1.0 → 3.0.0

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.
@@ -0,0 +1,26 @@
1
+ Feature: Initialize a global configuration
2
+ In order to configure chemistrykit
3
+ As a chemistry kit harness developer
4
+ I want to specify configurations in a central file so they are available in test scripts
5
+
6
+ Scenario: Use a configuration option in a beaker
7
+ Given I run `ckit new global-config-test`
8
+ And I cd to "global-config-test"
9
+ And a file named "beakers/test_beaker.rb" with:
10
+ """
11
+ describe "Cheese", :depth => 'shallow' do
12
+ it "loads an external web page" do
13
+ @driver.get @config.base_url
14
+ @driver.title.should include("Google")
15
+ end
16
+ end
17
+ """
18
+ And I overwrite config.yaml with:
19
+ """
20
+ base_url: http://www.google.com
21
+ selenium_connect:
22
+ log: 'evidence'
23
+ host: 'localhost'
24
+ """
25
+ When I run `ckit brew`
26
+ Then the stdout should contain "1 example, 0 failures"
@@ -6,9 +6,9 @@ Formulas should be loaded in the correct order with thier dependencies
6
6
  And I cd to "big-project"
7
7
  And a file named "config.yaml" with:
8
8
  """
9
- jar: '../../../vendor/selenium-server-standalone-2.33.0.jar'
10
- log: 'evidence'
11
- host: 'localhost'
9
+ selenium_connect:
10
+ log: 'evidence'
11
+ host: 'localhost'
12
12
  """
13
13
  And a file named "formulas/big.rb" with:
14
14
  """
@@ -34,7 +34,7 @@ Formulas should be loaded in the correct order with thier dependencies
34
34
  end
35
35
  """
36
36
 
37
- And a file named "beaker/big_beaker.rb" with:
37
+ And a file named "beakers/big_beaker.rb" with:
38
38
  """
39
39
  describe "Big", :depth => 'shallow' do
40
40
  let(:book) { Formulas::BigProject.new(@driver) }
@@ -6,7 +6,7 @@ Feature: Support for multiple configuration files
6
6
  Background:
7
7
  Given I run `ckit new config-test`
8
8
  And I cd to "config-test"
9
- And a file named "beaker/test_beaker.rb" with:
9
+ And a file named "beakers/test_beaker.rb" with:
10
10
  """
11
11
  describe "Cheese", :depth => 'shallow' do
12
12
  it "loads an external web page" do
@@ -19,9 +19,9 @@ Feature: Support for multiple configuration files
19
19
  Given a directory named "evidence_config"
20
20
  When I overwrite config.yaml with:
21
21
  """
22
- jar: '../../../vendor/selenium-server-standalone-2.33.0.jar'
23
- log: 'evidence_config'
24
- host: 'localhost'
22
+ selenium_connect:
23
+ log: 'evidence_config'
24
+ host: 'localhost'
25
25
  """
26
26
  When I run `ckit brew`
27
27
  Then the stdout should contain "1 example, 0 failures"
@@ -32,9 +32,9 @@ Feature: Support for multiple configuration files
32
32
  Given a directory named "evidence_alternate"
33
33
  And a file named "alternate.yaml" with:
34
34
  """
35
- jar: '../../../vendor/selenium-server-standalone-2.33.0.jar'
36
- log: 'evidence_alternate'
37
- host: 'localhost'
35
+ selenium_connect:
36
+ log: 'evidence_alternate'
37
+ host: 'localhost'
38
38
  """
39
39
  When I run `ckit brew --config alternate.yaml`
40
40
  Then the stdout should contain "1 example, 0 failures"
@@ -45,9 +45,9 @@ Feature: Support for multiple configuration files
45
45
  Given a directory named "evidence_alternate"
46
46
  And a file named "alternate.yaml" with:
47
47
  """
48
- jar: '../../../vendor/selenium-server-standalone-2.33.0.jar'
49
- log: 'evidence_alternate'
50
- host: 'localhost'
48
+ selenium_connect:
49
+ log: 'evidence_alternate'
50
+ host: 'localhost'
51
51
  """
52
52
  When I run `ckit brew -c alternate.yaml`
53
53
  Then the stdout should contain "1 example, 0 failures"
@@ -1,10 +1,12 @@
1
- When /^I overwrite ([^"]*) with:$/ do |file_name, file_content|
2
- #Modified from https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber.rb
1
+ # Encoding: utf-8
2
+
3
+ When /^I overwrite ([^"]*) with:$/ do | file_name, file_content |
4
+ # Modified from https://github.com/cucumber/aruba/blob/master/lib/aruba/cucumber.rb
3
5
  require 'erb'
4
6
  data = ERB.new(file_content)
5
7
  overwrite_file(file_name, data.result)
6
8
  end
7
9
 
8
10
  Then(/^the exit code should be (\d+)$/) do |exit_status|
9
- $?.exitstatus.should == exit_status.to_i
11
+ @last_exit_status.should == exit_status.to_i
10
12
  end
@@ -1,7 +1,9 @@
1
+ # Encoding: utf-8
2
+
1
3
  require 'aruba/cucumber'
2
4
 
3
5
  Before do
4
- FileUtils.rm_rf("build/tmp")
6
+ FileUtils.rm_rf('build/tmp')
5
7
  @aruba_timeout_seconds = 90
6
- @dirs = ["build/tmp"]
8
+ @dirs = ['build/tmp']
7
9
  end
@@ -1 +1,3 @@
1
+ # Encoding: utf-8
2
+
1
3
  require 'chemistrykit/cli/cli'
@@ -1,8 +1,11 @@
1
+ # Encoding: utf-8
2
+
1
3
  require 'csv'
2
4
 
3
5
  module ChemistryKit
6
+ # Serves as a hash wrapper class for injecting data into formulas
4
7
  class Catalyst
5
- #this class serves as a standard container for data that can be injected into a formula
8
+ # this class serves as a standard container for data that can be injected into a formula
6
9
 
7
10
  def initialize(data_file)
8
11
  @data = {}
@@ -24,9 +27,7 @@ module ChemistryKit
24
27
  private
25
28
 
26
29
  def validate_key(key)
27
- unless @data.has_key?(key.to_sym)
28
- raise "Unknown \"#{key}\""
29
- end
30
+ raise "Unknown \"#{key}\"" unless @data.has_key?(key.to_sym)
30
31
  end
31
32
  end
32
33
  end
@@ -1,7 +1,10 @@
1
+ # Encoding: utf-8
2
+
1
3
  require 'thor/group'
2
4
 
3
5
  module ChemistryKit
4
6
  module CLI
7
+ # Creates a starting beaker from a template
5
8
  class BeakerGenerator < Thor::Group
6
9
  include Thor::Actions
7
10
  argument :name
@@ -1,3 +1,5 @@
1
+ # Encoding: utf-8
2
+
1
3
  require 'thor'
2
4
  require 'rspec'
3
5
  require 'ci/reporter/rake/rspec_loader'
@@ -7,45 +9,55 @@ require 'chemistrykit/cli/beaker'
7
9
  require 'chemistrykit/cli/helpers/formula_loader'
8
10
  require 'chemistrykit/catalyst'
9
11
  require 'chemistrykit/formula/base'
12
+ require 'selenium-connect'
13
+ require 'chemistrykit/configuration'
10
14
 
11
15
  module ChemistryKit
12
16
  module CLI
13
17
 
18
+ # Registers the formula and beaker commands
14
19
  class Generate < Thor
15
20
  register(ChemistryKit::CLI::FormulaGenerator, 'formula', 'formula [NAME]', 'generates a page object')
16
21
  register(ChemistryKit::CLI::BeakerGenerator, 'beaker', 'beaker [NAME]', 'generates a beaker')
17
22
  end
18
23
 
24
+ # Main Chemistry Kit CLI Class
19
25
  class CKitCLI < Thor
20
26
 
21
27
  register(ChemistryKit::CLI::New, 'new', 'new [NAME]', 'Creates a new ChemistryKit project')
22
28
  check_unknown_options!
23
29
  default_task :help
24
30
 
25
- desc "generate SUBCOMMAND", "generate <formula> or <beaker> [NAME]"
26
- subcommand "generate", Generate
31
+ desc 'generate SUBCOMMAND', 'generate <formula> or <beaker> [NAME]'
32
+ subcommand 'generate', Generate
27
33
 
28
- desc "brew", "Run ChemistryKit"
29
- method_option :params, :type => :hash
30
- method_option :tag, :default => ['depth:shallow'], :type => :array
31
- method_option :config, :default => 'config.yaml', :aliases => "-c", :desc => "Supply alternative config file."
32
- #TODO there should be a facility to simply pass a path to this command
33
- method_option :beaker, :type => :string
34
+ desc 'brew', 'Run ChemistryKit'
35
+ method_option :params, type: :hash
36
+ method_option :tag, default: ['depth:shallow'], type: :array
37
+ method_option :config, default: 'config.yaml', aliases: '-c', desc: 'Supply alternative config file.'
38
+ # TODO there should be a facility to simply pass a path to this command
39
+ method_option :beakers, type: :array
40
+ # This is set if the thread is being run in parallel so as not to trigger recursive concurency
41
+ method_option :parallel, default: false
34
42
 
35
43
  def brew
36
- load_config
37
- require 'chemistrykit/shared_context'
44
+ config = load_config options['config']
45
+ # TODO perhaps the params should be rolled into the available
46
+ # config object injected into the system?
38
47
  pass_params if options['params']
39
48
  turn_stdout_stderr_on_off
40
49
  set_logs_dir
41
50
  load_page_objects
42
51
  setup_tags
43
- rspec_config
44
-
45
- if options['beaker']
46
- run_rspec([options['beaker']])
52
+ # configure rspec
53
+ rspec_config(config)
54
+ # get those beakers that should be executed
55
+ beakers = options['beakers'] ? options['beakers'] : Dir.glob(File.join(Dir.getwd, 'beakers/*'))
56
+ # based on concurrency parameter run tests
57
+ if config.concurrency > 1 && ! options['parallel']
58
+ run_in_parallel beakers, config.concurrency
47
59
  else
48
- run_rspec(Dir.glob(File.join(Dir.getwd)))
60
+ run_rspec beakers
49
61
  end
50
62
  end
51
63
 
@@ -59,7 +71,7 @@ module ChemistryKit
59
71
 
60
72
  def load_page_objects
61
73
  loader = ChemistryKit::CLI::Helpers::FormulaLoader.new
62
- loader.get_formulas(File.join(Dir.getwd, 'formulas')).each {|file| require file }
74
+ loader.get_formulas(File.join(Dir.getwd, 'formulas')).each { |file| require file }
63
75
  end
64
76
 
65
77
  def set_logs_dir
@@ -70,10 +82,9 @@ module ChemistryKit
70
82
  ENV['CI_CAPTURE'] = 'on'
71
83
  end
72
84
 
73
- def load_config
74
- #not wild about using an env variable here... but maybe it makes sense
75
- #just not sure how to inject it into the shared context.
76
- ENV['CONFIG_FILE'] = options['config']
85
+ def load_config(file_name)
86
+ config_file = File.join(Dir.getwd, file_name)
87
+ ChemistryKit::Configuration.initialize_with_yaml config_file
77
88
  end
78
89
 
79
90
  def setup_tags
@@ -91,25 +102,40 @@ module ChemistryKit
91
102
  end
92
103
  end
93
104
 
94
- def rspec_config #Some of these bits work and others don't
105
+ def rspec_config(config) # Some of these bits work and others don't
106
+ SeleniumConnect.configure do |c|
107
+ c.populate_with_hash config.selenium_connect
108
+ end
95
109
  RSpec.configure do |c|
96
110
  c.treat_symbols_as_metadata_keys_with_true_values = true
97
111
  c.filter_run @tags[:filter] unless @tags[:filter].nil?
98
112
  c.filter_run_excluding @tags[:exclusion_filter] unless @tags[:exclusion_filter].nil?
99
- c.include ChemistryKit::SharedContext
113
+ c.before(:each) do
114
+ @driver = SeleniumConnect.start
115
+ @config = config
116
+ end
117
+ c.after(:each) do
118
+ @driver.quit
119
+ end
120
+ c.after(:all) do
121
+ SeleniumConnect.finish
122
+ end
100
123
  c.order = 'random'
101
124
  c.default_path = 'beakers'
102
125
  c.pattern = '**/*_beaker.rb'
103
126
  end
104
127
  end
105
128
 
106
- def run_rspec(beakers)
107
-
108
- #puts single_beaker.inspect
129
+ def run_in_parallel(beakers, concurrency)
130
+ require 'parallel_tests'
131
+ require 'chemistrykit/parallel_tests_mods'
132
+ ParallelTests::CLI.new.run(%w(--type rspec) + ['-n', concurrency.to_s] + %w(-o --beakers=) + beakers)
133
+ end
109
134
 
135
+ def run_rspec(beakers)
110
136
  RSpec::Core::Runner.run(beakers)
111
137
  end
112
138
 
113
- end
114
- end
115
- end
139
+ end # CkitCLI
140
+ end # CLI
141
+ end # ChemistryKit
@@ -1,7 +1,10 @@
1
+ # Encoding: utf-8
2
+
1
3
  require 'thor/group'
2
4
 
3
5
  module ChemistryKit
4
6
  module CLI
7
+ # Creates a starting formula from a template
5
8
  class FormulaGenerator < Thor::Group
6
9
  include Thor::Actions
7
10
 
@@ -12,8 +15,8 @@ module ChemistryKit
12
15
  end
13
16
 
14
17
  def copy_file
15
- template "formula.tt", "./formulas/#{name}.rb"
16
- template "beaker_with_formula.tt", "./beakers/#{name}_beaker.rb"
18
+ template 'formula.tt', "./formulas/#{name}.rb"
19
+ template 'beaker_with_formula.tt', "./beakers/#{name}_beaker.rb"
17
20
  end
18
21
 
19
22
  end
@@ -1,16 +1,18 @@
1
+ # Encoding: utf-8
2
+
1
3
  module ChemistryKit
2
4
  module CLI
3
5
  module Helpers
6
+ # this loader returns the formulas found in a path according to these rules:
7
+ # - directories loaded in alpha order
8
+ # - children directories loaded before parents
9
+ # - files loaded in alpha order
10
+ # - lib directories are loaded before any other
11
+ # - rules stack
4
12
  class FormulaLoader
5
- #this loader returns the formulas found in a path according to these rules:
6
- #- directories loaded in alpha order
7
- #- children directories loaded before parents
8
- #- files loaded in alpha order
9
- #- lib directories are loaded before any other
10
- #- rules stack
11
13
 
12
14
  def initialize
13
- @formulas = Array.new
15
+ @formulas = []
14
16
  end
15
17
 
16
18
  def get_formulas(path)
@@ -19,25 +21,36 @@ module ChemistryKit
19
21
  end
20
22
 
21
23
  private
24
+
22
25
  def gather(path)
23
- #get all the directories for path
24
- directories = Dir.entries(path).select {|entry| File.directory? File.join(path,entry) and !(entry =='.' || entry == '..') }
26
+ # get all the directories for path
27
+ directories = get_directories path
25
28
  if directories.empty?
26
- #if there are no directories is empty just get all the files and add it to the instance variable
27
- @formulas.concat Dir.glob(File.join(path, "*.rb")).sort
29
+ # if there are no directories is empty just get all the files and add it to the instance variable
30
+ @formulas.concat Dir.glob(File.join(path, '*.rb')).sort
28
31
  else
29
- #otherwise for each of them recurse into it
32
+ # otherwise for each of them recurse into it
30
33
  directories.sort!
31
- if directories.include? 'lib'
32
- #if there is a lib directory, put that at the front
33
- directories.delete('lib')
34
- directories.unshift('lib')
35
- end
34
+ move_lib_to_top_of_stack directories
36
35
  directories.each do |directory|
37
36
  gather(File.join(path, directory))
38
37
  end
39
- #and then after add the files in the original parent
40
- @formulas.concat Dir.glob(File.join(path, "*.rb")).sort
38
+ # and then after add the files in the original parent
39
+ @formulas.concat Dir.glob(File.join(path, '*.rb')).sort
40
+ end
41
+ end
42
+
43
+ def get_directories(path)
44
+ Dir.entries(path).select do |entry|
45
+ (File.directory? File.join(path, entry)) && !(entry == '.' || entry == '..')
46
+ end
47
+ end
48
+
49
+ def move_lib_to_top_of_stack(directories)
50
+ if directories.include? 'lib'
51
+ # if there is a lib directory, put that at the front
52
+ directories.delete('lib')
53
+ directories.unshift('lib')
41
54
  end
42
55
  end
43
56
  end
@@ -1,7 +1,10 @@
1
+ # Encoding: utf-8
2
+
1
3
  require 'thor/group'
2
4
 
3
5
  module ChemistryKit
4
6
  module CLI
7
+ # Creates a new test harness
5
8
  class New < Thor::Group
6
9
  include Thor::Actions
7
10
 
@@ -12,11 +15,11 @@ module ChemistryKit
12
15
  end
13
16
 
14
17
  def create_project
15
- directory "templates/chemistrykit", File.join(Dir.getwd, name)
18
+ directory 'templates/chemistrykit', File.join(Dir.getwd, name)
16
19
  end
17
20
 
18
21
  def notify
19
- say "Your test harness has been created."
22
+ say 'Your test harness has been created.'
20
23
  end
21
24
 
22
25
  end
@@ -0,0 +1,54 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ module ChemistryKit
6
+ # Default configuration class
7
+ class Configuration
8
+
9
+ attr_accessor :concurrency,
10
+ :base_url,
11
+ :selenium_connect
12
+
13
+ def initialize(hash)
14
+ # set defaults
15
+ @concurrency = 1
16
+
17
+ # overide with argument
18
+ populate_with_hash hash
19
+ validate_config
20
+ end
21
+
22
+ def self.initialize_with_yaml(file)
23
+ self.new symbolize_keys YAML.load_file file
24
+ end
25
+
26
+ private
27
+
28
+ def populate_with_hash(hash)
29
+ hash.each do |key, value|
30
+ begin
31
+ self.send "#{key}=", value unless value.nil?
32
+ rescue NoMethodError
33
+ raise ArgumentError.new "The config key: \"#{key}\" is unknown!"
34
+ end
35
+ end
36
+ end
37
+
38
+ def validate_config
39
+ if @selenium_connect && @selenium_connect[:host] != 'saucelabs' && @concurrency > 1
40
+ raise ArgumentError.new 'Concurrency is only supported for the host: "saucelabs"!'
41
+ end
42
+ end
43
+
44
+ # private static to symbolize recursivly a loaded yaml
45
+ def self.symbolize_keys(hash)
46
+ hash.reduce({}) do |result, (key, value)|
47
+ new_key = key.class == String ? key.to_sym : key
48
+ new_value = value.class == Hash ? symbolize_keys(value) : value
49
+ result[new_key] = new_value
50
+ result
51
+ end
52
+ end
53
+ end
54
+ end