lopata 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ad9bc72f5e0429f18b12bc247e3fbf4346278b5c6b487a02c665e3c020bd5f7
4
- data.tar.gz: bde38469c56e1ef03b1480fa09d9d879867660983fcd9abe807ee8be553aaaed
3
+ metadata.gz: 9233d9fba2a55749f02037d5ca106c0cb9249debda448aac58ccc2cc724a378e
4
+ data.tar.gz: 65ea743e92f5084b6f04b52595296cb80a3d4540f4cb8ba8bc2c774cbc448aaf
5
5
  SHA512:
6
- metadata.gz: ba6f140682c330ca68eb2a8d3f27aed552bd376c1a1c773ebe1914b4738da39adfe500a4254e06c2ea3865bd5fedc7246e5301eca6e130683bc4119e7db30071
7
- data.tar.gz: 0d6b7e1f4ae029539a1c65fd0e9ca4546610bbe6e8da8b37250ec71a106cc3cfe0445b4a6b299de9cbd5a2b1a5e4949b7bad6f178af32e702252755553b69474
6
+ metadata.gz: a706fde4a5acc83b27400ce50c19137b7fd9f296bfb2ac4baeec55e50e5fe48b4bf6e90110611f4f69cd2dc9571a15d1de34e54e8bec094f0c2c2d5cc5ca1a87
7
+ data.tar.gz: 2d0764e801260489815f30b8572ffdff7bdf6572fc64b55d0e53c091f8f125925374ae9cf706b1fe0bc956a6d56ef23b6dd1bd767b7ce13de550b4878dc86f4f
data/README.md CHANGED
@@ -14,7 +14,7 @@ Create new lopata project:
14
14
 
15
15
  Setup environment: edit <project-name>/config/environments/qa.yml for setup project for testing.
16
16
 
17
- Write tests: puts RSpec tests in <project-name>/spec folder.
17
+ Write tests: puts tests in <project-name>/scenarios folder. Define shared steps in <project-name>/shared_steps folder.
18
18
 
19
19
  Run tests:
20
20
 
@@ -10,8 +10,8 @@ module Lopata
10
10
  Lopata::ScenarioBuilder.define(*args, &block)
11
11
  end
12
12
 
13
+ # Skip scenario definition. Option to temporary ignore scenario
13
14
  def self.xdefine(*args, &block)
14
- Lopata::ScenarioBuilder.xdefine(*args, &block)
15
15
  end
16
16
 
17
17
  def self.shared_step(name, &block)
@@ -0,0 +1,30 @@
1
+ module Lopata
2
+ class Condition
3
+ attr_reader :condition, :positive
4
+ def initialize(condition, positive: true)
5
+ @condition, @positive = condition, positive
6
+ end
7
+
8
+ EMPTY = new({})
9
+
10
+ alias positive? positive
11
+
12
+ def match?(scenario)
13
+ matched = match_metadata?(scenario)
14
+ positive? ? matched : !matched
15
+ end
16
+
17
+ def match_metadata?(scenario)
18
+ metadata = scenario.metadata
19
+ case condition
20
+ when Hash
21
+ condition.keys.all? { |k| metadata[k] == condition[k] }
22
+ when Array
23
+ condition.map { |key| metadata[key] }.none?(&:nil?)
24
+ else
25
+ metadata[condition]
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -49,10 +49,8 @@ module Lopata
49
49
 
50
50
  def init_lopata_logging(build)
51
51
  self.build_number = build
52
- ::RSpec.configure do |c|
53
- require 'lopata/rspec/formatter' # class cross-loading, avoid auto-loading
54
- c.add_formatter Lopata::RSpec::Formatter
55
- end
52
+ require 'lopata/observers/web_logger'
53
+ add_observer Lopata::Observers::WebLogger.new
56
54
  end
57
55
 
58
56
  def init_rerun
@@ -95,5 +93,9 @@ module Lopata
95
93
  def world
96
94
  @world ||= Lopata::World.new
97
95
  end
96
+
97
+ def add_observer(observer)
98
+ world.observers << observer
99
+ end
98
100
  end
99
101
  end
@@ -0,0 +1,26 @@
1
+ module Lopata::Loader
2
+ extend self
3
+
4
+ # Loads scenarios for running in current session
5
+ #
6
+ # @param args [Array<String>] files to be load.
7
+ # All files from default location to be loaded if empty.
8
+ def load_scenarios(*args)
9
+ if args.empty?
10
+ load_all_scenarios
11
+ else
12
+ args.each do |file|
13
+ load File.expand_path(file)
14
+ end
15
+ end
16
+ end
17
+
18
+ # Loads all scenarios from predefined paths
19
+ def load_all_scenarios
20
+ Dir["scenarios/**/*.rb"].each { |f| load File.expand_path(f) }
21
+ end
22
+
23
+ def load_shared_steps
24
+ Dir["shared_steps/**/*rb"].each { |f| load File.expand_path(f) }
25
+ end
26
+ end
@@ -0,0 +1,129 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ module Lopata
5
+ module Observers
6
+ class WebLogger < BaseObserver
7
+ def started(world)
8
+ raise "Build number is not initailzed in Lopata::Config" unless Lopata::Config.build_number
9
+ @client = Lopata::Client.new(Lopata::Config.build_number)
10
+ @client.start(world.scenarios.count)
11
+ end
12
+
13
+ def scenario_finished(scenario)
14
+ if scenario.failed?
15
+ backtrace = backtrace_for(scenario)
16
+ @client.add_attempt(scenario, Lopata::FAILED, error_message_for(scenario), backtrace)
17
+ else
18
+ @client.add_attempt(scenario, Lopata::PASSED)
19
+ end
20
+ end
21
+
22
+ # def example_pending(notification)
23
+ # example = notification.example
24
+ # @client.add_attempt(example, Lopata::PENDING, example.execution_result.pending_message)
25
+ # end
26
+
27
+ private
28
+
29
+ def error_message_for(scenario)
30
+ exception = scenario.steps.map(&:exception).compact.last
31
+ msg = ''
32
+ if exception
33
+ msg << "#{exception.class.name}: " unless exception.class.name =~ /RSpec/
34
+ msg << "#{exception.message.to_s}" if exception.message
35
+ end
36
+ (msg.length == 0) ? 'Empty message' : msg
37
+ end
38
+
39
+ def backtrace_for(scenario)
40
+ exception = scenario.steps.map(&:exception).compact.last
41
+ msg = ''
42
+ if exception
43
+ msg = exception.backtrace.join("\n")
44
+ msg << "\n"
45
+ end
46
+ msg
47
+ end
48
+ end
49
+ end
50
+
51
+ PASSED = 0
52
+ FAILED = 1
53
+ PENDING = 2
54
+
55
+ class Client
56
+ include HTTParty
57
+ base_uri Lopata::Config.lopata_host
58
+
59
+ attr_accessor :build_number
60
+
61
+ def initialize(build_number)
62
+ @build_number = build_number
63
+ end
64
+
65
+ def start(count)
66
+ @launch_id = JSON.parse(post("/projects/#{project_code}/builds/#{build_number}/launches.json", body: {total: count}).body)['id']
67
+ end
68
+
69
+ def add_attempt(scenario, status, msg = nil, backtrace = nil)
70
+ test = test_id(scenario)
71
+ request = { status: status}
72
+ request[:message] = msg if msg
73
+ request[:backtrace] = backtrace if backtrace
74
+ post("/tests/#{test}/attempts.json", body: request)
75
+ inc_finished
76
+ end
77
+
78
+ def test_id(scenario)
79
+ request = {
80
+ test: {
81
+ project_code: project_code,
82
+ title: scenario.title,
83
+ scenario: scenario.title,
84
+ build_number: build_number
85
+ }
86
+ }
87
+ response = post("/tests.json", body: request)
88
+ JSON.parse(response.body)["id"]
89
+ end
90
+
91
+ def to_rerun
92
+ get_json("/projects/#{project_code}/builds/#{build_number}/suspects.json")
93
+ end
94
+
95
+ def to_full_rescan
96
+ to_rerun + get_json("/projects/#{project_code}/builds/#{build_number}/failures.json")
97
+ end
98
+
99
+ private
100
+
101
+ def get_json(url)
102
+ JSON.parse(self.class.get(url).body)
103
+ end
104
+
105
+ def post(*args)
106
+ self.class.post(*args)
107
+ end
108
+
109
+ def patch(*args)
110
+ self.class.patch(*args)
111
+ end
112
+
113
+ def inc_finished
114
+ @finished ||= 0
115
+ @finished += 1
116
+ response = patch("/launches/#{@launch_id}",
117
+ body: { finished: @finished }.to_json,
118
+ headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
119
+ if response.code == 404
120
+ puts 'Launch has been cancelled. Exit.'
121
+ exit!
122
+ end
123
+ end
124
+
125
+ def project_code
126
+ Lopata::Config.lopata_code
127
+ end
128
+ end
129
+ end
@@ -2,8 +2,10 @@ require 'thor'
2
2
  require_relative 'generators/app'
3
3
  require_relative 'config'
4
4
  require_relative 'world'
5
+ require_relative 'loader'
5
6
  require_relative '../lopata'
6
7
  require_relative 'observers'
8
+ require_relative 'condition'
7
9
 
8
10
  module Lopata
9
11
  class Runner < Thor
@@ -18,12 +20,10 @@ module Lopata
18
20
  option :text, aliases: 't'
19
21
  def test(*args)
20
22
  configure_from_options
21
-
22
- # Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
23
+ Lopata::Loader.load_shared_steps
24
+ Lopata::Loader.load_scenarios(*args)
23
25
  world = Lopata::Config.world
24
- world.setup_observers
25
- world.load_shared_steps
26
- world.load_scenarios(*args)
26
+ world.start
27
27
  world.scenarios.each { |s| s.run }
28
28
  world.finish
29
29
  end
@@ -49,8 +49,6 @@ module Lopata
49
49
  }
50
50
  Lopata::Config.init(options[:env])
51
51
  Lopata::Config.initialize_test
52
- # ENV['HOME'] = File.absolute_path('.') # disable warning on rspec loading on windows
53
- # Lopata::Config.init_rspec
54
52
  end
55
53
  end
56
54
  end
@@ -5,9 +5,9 @@ class Lopata::Scenario
5
5
 
6
6
  attr_reader :title, :metadata, :steps, :status
7
7
 
8
- def initialize(*args)
9
- @title = args.first
10
- @metadata = args.last.is_a?(Hash) ? args.last : {}
8
+ def initialize(title, options_title, metadata = {})
9
+ @title = [title, options_title].compact.reject(&:empty?).join(' ')
10
+ @metadata = metadata
11
11
  @steps = []
12
12
  @status = :not_runned
13
13
  end
@@ -33,29 +33,10 @@ class Lopata::Scenario
33
33
  end
34
34
  end
35
35
 
36
- def run_step(method_name, *args, &block)
37
- instance_exec(&block)
38
- end
39
-
40
36
  def world
41
37
  @world ||= Lopata::Config.world
42
38
  end
43
39
 
44
- def convert_args(*args)
45
- args.map do |arg|
46
- case arg
47
- # trait symbols as link to metadata.
48
- when Symbol then metadata[arg]
49
- else
50
- arg
51
- end
52
- end.flatten
53
- end
54
-
55
- def separate_args(args)
56
- args.map { |a| a.is_a?(String) && a =~ /,/ ? a.split(',').map(&:strip) : a }.flatten
57
- end
58
-
59
40
  def failed?
60
41
  status == :failed
61
42
  end
@@ -1,28 +1,30 @@
1
1
  class Lopata::ScenarioBuilder
2
- def self.define(title, metadata = nil, &block)
3
- builder = new
4
- builder.title(title)
5
- builder.metadata(metadata) if metadata
2
+ attr_reader :title, :common_metadata
3
+
4
+ def self.define(title, metadata = {}, &block)
5
+ builder = new(title, metadata)
6
6
  builder.instance_exec &block
7
7
  builder.build
8
8
  end
9
9
 
10
- # Do noting. Exclude defined scenario from suite.
11
- def self.xdefine(*attrs)
10
+ def initialize(title, metadata = {})
11
+ @title, @common_metadata = title, metadata
12
12
  end
13
13
 
14
14
  def build
15
- world = Lopata::Config.world
16
- option_combinations.map do |option_set|
17
- args = prepare_args(option_set)
18
- raise "scenario required a name in first argument" unless args.first.is_a? String
19
- scenario = Lopata::Scenario.new(*args)
15
+ option_combinations.each do |option_set|
16
+ metadata = common_metadata.merge(option_set.metadata)
17
+ scenario = Lopata::Scenario.new(title, option_set.title, metadata)
20
18
 
21
19
  steps.each do |step|
20
+ next if step.condition && !step.condition.match?(scenario)
21
+ step.pre_steps(scenario).each { |s| scenario.steps << s }
22
22
  scenario.steps << step
23
23
  end
24
24
 
25
- scenario.steps << Lopata::Config.after_scenario if Lopata::Config.after_scenario
25
+ if Lopata::Config.after_scenario
26
+ scenario.steps << Lopata::Step.new(:after_scenario, &Lopata::Config.after_scenario)
27
+ end
26
28
 
27
29
  world.scenarios << scenario
28
30
  end
@@ -56,36 +58,22 @@ class Lopata::ScenarioBuilder
56
58
  @skip_when && @skip_when.call(option_set)
57
59
  end
58
60
 
59
- %i{setup action it teardown}.each do |name|
61
+ %i{ setup action it teardown }.each do |name|
60
62
  name_if = "%s_if" % name
61
63
  name_unless = "%s_unless" % name
62
64
  define_method name, ->(*args, &block) { add_step(name, *args, &block) }
63
- define_method name_if, ->(condition, *args, &block) { add_step(name, *args, if_cond: condition, &block) }
64
- define_method name_unless, ->(condition, *args, &block) { add_step(name, *args, unless_cond: condition, &block) }
65
+ define_method name_if, ->(condition, *args, &block) { add_step(name, *args, condition: Lopata::Condition.new(condition), &block) }
66
+ define_method name_unless, ->(condition, *args, &block) { add_step(name, *args, condition: Lopata::Condition.new(condition, positive: false), &block) }
65
67
  end
66
68
 
67
- def add_step(method_name, *args, if_cond: nil, unless_cond: nil, &block)
68
- steps << Lopata::Step.new(method_name, *args) do
69
- # will be called in context of scenario
70
- next if if_cond && !match_metadata?(if_cond)
71
- next if unless_cond && match_metadata?(unless_cond)
72
-
73
- flat_args = args.flatten
74
- flat_args = separate_args(flat_args) if method_name =~ /^(setup|action)/
75
- converted_args = convert_args(*flat_args)
76
- converted_args.shift if method_name =~ /^it$/
77
- converted_args.each do |step|
78
- if step.is_a?(String)
79
- Lopata::SharedStep.find(step).steps.each do |shared_step|
80
- instance_exec(&shared_step.block)
81
- end
82
- elsif step.is_a?(Proc)
83
- instance_exec(&step)
84
- end
69
+ def add_step(method_name, *args, condition: nil, &block)
70
+ step_class =
71
+ if method_name =~ /^(setup|action|teardown)/
72
+ Lopata::ActionStep
73
+ else
74
+ Lopata::Step
85
75
  end
86
- # run_step method_name, *converted_args, &block
87
- instance_exec(&block) if block
88
- end
76
+ steps << step_class.new(method_name, *args, condition: condition, &block)
89
77
  end
90
78
 
91
79
  def steps
@@ -120,10 +108,6 @@ class Lopata::ScenarioBuilder
120
108
  @roles ||= [Lopata::Config.default_role].compact
121
109
  end
122
110
 
123
- def title(value)
124
- @title = value
125
- end
126
-
127
111
  def option(metadata_key, variants)
128
112
  options << Option.new(metadata_key, variants)
129
113
  end
@@ -161,22 +145,8 @@ class Lopata::ScenarioBuilder
161
145
  combine(combinations, rest_options)
162
146
  end
163
147
 
164
- def prepare_args(option_set, *args)
165
- options_title, metadata = option_set.title, option_set.metadata
166
- if args[0].is_a? String
167
- args[0] = [@title, options_title, args[0]].compact.reject(&:empty?).join(' ')
168
- else
169
- args.unshift([@title, options_title].compact.reject(&:empty?).join(' '))
170
- end
171
-
172
- metadata.merge!(@common_metadata) if @common_metadata
173
-
174
- if args.last.is_a? Hash
175
- args.last.merge!(metadata)
176
- else
177
- args << metadata
178
- end
179
- args
148
+ def world
149
+ @world ||= Lopata::Config.world
180
150
  end
181
151
 
182
152
  # Набор вариантов, собранный для одного теста
@@ -1,21 +1,21 @@
1
1
  module Lopata
2
2
  class SharedStep
3
- attr_reader :block
3
+ attr_reader :name, :block
4
4
 
5
5
  class SharedStepNotFound < StandardError; end
6
6
 
7
7
  def self.register(name, &block)
8
8
  raise ArgumentError, "Comma is not allowed in shared step name: '%s'" % name if name =~ /,/
9
9
  @shared_steps ||= {}
10
- @shared_steps[name] = new(&block)
10
+ @shared_steps[name] = new(name, &block)
11
11
  end
12
12
 
13
13
  def self.find(name)
14
14
  @shared_steps[name] or raise StandardError, "Shared step '%s' not found" % name
15
15
  end
16
16
 
17
- def initialize(&block)
18
- @block = block
17
+ def initialize(name, &block)
18
+ @name, @block = name, block
19
19
  end
20
20
 
21
21
  def steps
@@ -23,7 +23,7 @@ module Lopata
23
23
  end
24
24
 
25
25
  def build_steps
26
- builder = Lopata::ScenarioBuilder.new
26
+ builder = Lopata::ScenarioBuilder.new(name)
27
27
  builder.instance_exec(&block)
28
28
  builder.steps
29
29
  end
@@ -1,20 +1,21 @@
1
1
  module Lopata
2
2
  class Step
3
- attr_reader :block, :status, :exception
3
+ attr_reader :block, :status, :exception, :args, :condition
4
4
 
5
- def initialize(method_name, *args, &block)
5
+ def initialize(method_name, *args, condition: nil, &block)
6
6
  @method_name = method_name
7
7
  @args = args
8
8
  @status = :not_started
9
9
  @block = block
10
10
  @exception = nil
11
+ @condition = condition || Lopata::Condition::EMPTY
11
12
  end
12
13
 
13
14
  def run(scenario)
14
15
  @status = :running
15
16
  world.notify_observers(:step_started, self)
16
17
  begin
17
- scenario.instance_exec(&block)
18
+ run_step(scenario)
18
19
  @status = :passed
19
20
  rescue Exception => e
20
21
  @status = :failed
@@ -23,6 +24,10 @@ module Lopata
23
24
  world.notify_observers(:step_finished, self)
24
25
  end
25
26
 
27
+ def run_step(scenario)
28
+ scenario.instance_exec(&block) if block
29
+ end
30
+
26
31
  def world
27
32
  @world ||= Lopata::Config.world
28
33
  end
@@ -38,5 +43,44 @@ module Lopata
38
43
  def teardown?
39
44
  %i{ teardown cleanup }.include?(@method_name)
40
45
  end
46
+
47
+ def pre_steps(scenario)
48
+ []
49
+ end
50
+ end
51
+
52
+ # Used for action, setup, teardown
53
+ class ActionStep < Step
54
+ def pre_steps(scenario)
55
+ steps = []
56
+ convert_args(scenario).each do |step|
57
+ if step.is_a?(String)
58
+ Lopata::SharedStep.find(step).steps.each do |shared_step|
59
+ steps += shared_step.pre_steps(scenario)
60
+ steps << shared_step
61
+ end
62
+ elsif step.is_a?(Proc)
63
+ steps << Lopata::Step.new(method_name, &step)
64
+ end
65
+ end
66
+ steps
67
+ end
68
+
69
+ def separate_args(args)
70
+ args.map { |a| a.is_a?(String) && a =~ /,/ ? a.split(',').map(&:strip) : a }.flatten
71
+ end
72
+
73
+ def convert_args(scenario)
74
+ flat_args = separate_args(args.flatten)
75
+ flat_args.map do |arg|
76
+ case arg
77
+ # trait symbols as link to metadata.
78
+ when Symbol then scenario.metadata[arg]
79
+ else
80
+ arg
81
+ end
82
+ end.flatten
83
+ end
84
+
41
85
  end
42
86
  end
@@ -1,5 +1,5 @@
1
1
  module Lopata
2
2
  module Version
3
- STRING = '0.1.0'
3
+ STRING = '0.1.1'
4
4
  end
5
5
  end
@@ -1,32 +1,12 @@
1
1
  class Lopata::World
2
- attr_reader :scenarios, :observers
2
+ attr_reader :scenarios
3
3
 
4
4
  def initialize
5
5
  @scenarios = []
6
- @observers = []
7
6
  end
8
7
 
9
- # Loads scenarios for running in current session
10
- #
11
- # @param args [Array<String>] files to be load.
12
- # All files from default location to be loaded if empty.
13
- def load_scenarios(*args)
14
- if args.empty?
15
- load_all_scenarios
16
- else
17
- args.each do |file|
18
- load File.expand_path(file)
19
- end
20
- end
21
- end
22
-
23
- # Loads all scenarios from predefined paths
24
- def load_all_scenarios
25
- Dir["scenarios/**/*.rb"].each { |f| load File.expand_path(f) }
26
- end
27
-
28
- def load_shared_steps
29
- Dir["shared_steps/**/*rb"].each { |f| load File.expand_path(f) }
8
+ def start
9
+ notify_observers(:started, self)
30
10
  end
31
11
 
32
12
  # Called at the end of test running.
@@ -37,13 +17,13 @@ class Lopata::World
37
17
  end
38
18
 
39
19
  def notify_observers(event, context)
40
- @observers.each do |observer|
20
+ observers.each do |observer|
41
21
  observer.send event, context
42
22
  end
43
23
  end
44
24
 
45
25
  # Define observers based on configuration
46
- def setup_observers
47
- @observers = [Lopata::Observers::ConsoleOutputObserver.new]
26
+ def observers
27
+ @observers ||= [Lopata::Observers::ConsoleOutputObserver.new]
48
28
  end
49
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lopata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Volochnev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-12 00:00:00.000000000 Z
11
+ date: 2020-05-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -90,8 +90,8 @@ files:
90
90
  - README.md
91
91
  - exe/lopata
92
92
  - lib/lopata.rb
93
+ - lib/lopata/condition.rb
93
94
  - lib/lopata/config.rb
94
- - lib/lopata/download_dir.rb
95
95
  - lib/lopata/generators/app.rb
96
96
  - lib/lopata/generators/templates/.rspec
97
97
  - lib/lopata/generators/templates/Gemfile
@@ -100,12 +100,13 @@ files:
100
100
  - lib/lopata/generators/templates/config/initializers/capybara.rb
101
101
  - lib/lopata/generators/templates/spec/spec_helper.rb
102
102
  - lib/lopata/id.rb
103
+ - lib/lopata/loader.rb
103
104
  - lib/lopata/observers.rb
104
105
  - lib/lopata/observers/base_observer.rb
105
106
  - lib/lopata/observers/console_output_observer.rb
107
+ - lib/lopata/observers/web_logger.rb
106
108
  - lib/lopata/rspec/ar_dsl.rb
107
109
  - lib/lopata/rspec/dsl.rb
108
- - lib/lopata/rspec/formatter.rb
109
110
  - lib/lopata/rspec/role.rb
110
111
  - lib/lopata/runner.rb
111
112
  - lib/lopata/scenario.rb
@@ -136,5 +137,5 @@ requirements: []
136
137
  rubygems_version: 3.0.3
137
138
  signing_key:
138
139
  specification_version: 4
139
- summary: lopata-0.1.0
140
+ summary: lopata-0.1.1
140
141
  test_files: []
@@ -1,70 +0,0 @@
1
- module Lopata
2
- module DownloadDir
3
- RELATIVE_PATH = File.join('.', 'tmp', 'target')
4
-
5
- extend self
6
-
7
- def path
8
- @path ||= File.absolute_path(RELATIVE_PATH)
9
- end
10
-
11
- def empty!
12
- FileUtils.rm Dir.glob(File.join(path, '*'))
13
- end
14
-
15
- def ensure_exist
16
- FileUtils::mkdir_p path unless Dir.exist?(path)
17
- end
18
-
19
- def has_file?(file_name)
20
- require 'timeout'
21
- target_file = filepath(file_name)
22
- Timeout.timeout(10) do
23
- sleep 0.1 until File.exist?(target_file)
24
- true
25
- end
26
- rescue Timeout::Error
27
- false
28
- end
29
-
30
- def filepath(name)
31
- File.join(path, name)
32
- end
33
-
34
- def init_capybara
35
- target_path = path
36
- target_path = target_path.gsub('/', '\\') if Gem.win_platform?
37
-
38
- profile = Selenium::WebDriver::Firefox::Profile.new
39
- profile['browser.download.folderList'] = 2
40
- profile['browser.download.manager.showWhenStarting'] = false
41
- ensure_exist
42
- profile['browser.download.dir'] = target_path
43
- profile['browser.download.downloadDir'] = target_path
44
- profile['browser.download.defaultFolder'] = target_path
45
- profile['browser.helperApps.alwaysAsk.force'] = false
46
- profile['browser.download.useDownloadDir'] = true
47
- profile['browser.helperApps.neverAsk.saveToDisk'] =
48
- %w{
49
- application/octet-stream
50
- application/msword
51
- application/pdf
52
- application/x-pdf
53
- application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
54
- application/vnd.ms-excel
55
- application/xml
56
- application/json
57
- }.join(', ')
58
- profile['pdfjs.disabled'] = true
59
- profile['plugin.scan.Acrobat'] = "99.0"
60
- profile['plugin.scan.plid.all'] = false
61
-
62
- Capybara.register_driver :selenium_with_download do |app|
63
- Capybara::Selenium::Driver.new(app, browser: :firefox, profile: profile)
64
- end
65
-
66
- Capybara.default_driver = :selenium_with_download
67
- # Capybara.default_max_wait_time = 10
68
- end
69
- end
70
- end
@@ -1,143 +0,0 @@
1
- require 'rspec/core/formatters/base_formatter'
2
- require 'httparty'
3
- require 'json'
4
- require 'lopata/config'
5
-
6
- module Lopata
7
- module RSpec
8
- class Formatter < ::RSpec::Core::Formatters::BaseFormatter
9
- ::RSpec::Core::Formatters.register self, :start, :example_passed, :example_pending, :example_failed
10
-
11
- def start(notification)
12
- raise "Build number is not initailzed in Lopata::Config" unless Lopata::Config.build_number
13
- @client = Lopata::Client.new(Lopata::Config.build_number)
14
- @client.start(notification.count)
15
- end
16
-
17
- def example_passed(notification)
18
- @client.add_attempt(notification.example, Lopata::PASSED)
19
- end
20
-
21
- def example_failed(notification)
22
- example = notification.example
23
- backtrace = backtrace_for(notification)
24
- @client.add_attempt(example, Lopata::FAILED, error_message_for(example), backtrace)
25
- end
26
-
27
- def example_pending(notification)
28
- example = notification.example
29
- @client.add_attempt(example, Lopata::PENDING, example.execution_result.pending_message)
30
- end
31
-
32
- private
33
-
34
- def error_message_for(example)
35
- exception = example.execution_result.exception
36
- msg = ''
37
- msg << "#{exception.class.name}: " unless exception.class.name =~ /RSpec/
38
- msg << "#{exception.message.to_s}" if exception.message
39
- msg.blank? ? 'Empty message' : msg
40
- end
41
-
42
- def backtrace_for(notification)
43
- example = notification.example
44
- exception = example.execution_result.exception
45
- msg = notification.formatted_backtrace.map(&:strip).join("\n")
46
- msg << "\n"
47
- if shared_group = find_shared_group(example)
48
- msg << "# Shared Example Group: \"#{shared_group.metadata[:shared_group_name]}\" called from "
49
- msg << "#{backtrace_line(shared_group.metadata[:example_group][:location])}\n"
50
- end
51
- msg
52
- end
53
-
54
- def find_shared_group(example)
55
- group_and_parent_groups(example).find {|group| group.metadata[:shared_group_name]}
56
- end
57
-
58
- def group_and_parent_groups(example)
59
- example.example_group.parent_groups + [example.example_group]
60
- end
61
- end
62
- end
63
-
64
- PASSED = 0
65
- FAILED = 1
66
- PENDING = 2
67
-
68
- class Client
69
- include HTTParty
70
- base_uri Lopata::Config.lopata_host
71
-
72
- attr_accessor :build_number
73
-
74
- def initialize(build_number)
75
- @build_number = build_number
76
- end
77
-
78
- def start(count)
79
- @launch_id = JSON.parse(post("/projects/#{project_code}/builds/#{build_number}/launches.json", body: {total: count}).body)['id']
80
- end
81
-
82
- def add_attempt(example, status, msg = nil, backtrace = nil)
83
- test = test_id(example)
84
- request = { status: status}
85
- request[:message] = msg if msg
86
- request[:backtrace] = backtrace if backtrace
87
- post("/tests/#{test}/attempts.json", body: request)
88
- inc_finished
89
- end
90
-
91
- def test_id(example)
92
- request = {
93
- test: {
94
- project_code: project_code,
95
- title: example.full_description,
96
- scenario: example.metadata[:example_group][:full_description],
97
- build_number: build_number
98
- }
99
- }
100
- response = post("/tests.json", body: request)
101
- JSON.parse(response.body)["id"]
102
- end
103
-
104
- def to_rerun
105
- get_json("/projects/#{project_code}/builds/#{build_number}/suspects.json")
106
- end
107
-
108
- def to_full_rescan
109
- to_rerun + get_json("/projects/#{project_code}/builds/#{build_number}/failures.json")
110
- end
111
-
112
- private
113
-
114
- def get_json(url)
115
- JSON.parse(self.class.get(url).body)
116
- end
117
-
118
- def post(*args)
119
- self.class.post(*args)
120
- end
121
-
122
- def patch(*args)
123
- self.class.patch(*args)
124
- end
125
-
126
- def inc_finished
127
- @finished ||= 0
128
- @finished += 1
129
- response = patch("/launches/#{@launch_id}",
130
- body: { finished: @finished }.to_json,
131
- headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
132
- if response.code == 404
133
- puts 'Launch has been cancelled. Exit.'
134
- exit!
135
- end
136
- end
137
-
138
- def project_code
139
- Lopata::Config.lopata_code
140
- end
141
- end
142
- end
143
-