chemistrykit 2.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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