cucumber-pro 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/TODO.md +1 -1
- data/lib/cucumber/pro.rb +8 -20
- data/lib/cucumber/pro/errors.rb +25 -0
- data/lib/cucumber/pro/version +1 -1
- data/lib/cucumber/pro/web_socket/session.rb +26 -5
- data/spec/cucumber/pro/web_socket/worker_spec.rb +80 -56
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c1ea22ade2589bfaba0ea2b8b452133995630c9
|
4
|
+
data.tar.gz: 31a0837902dfacd353adf063083d2a5c6d9d1681
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ba8796ca612b363c444fb9308687d6dfdcc66e0620eb2d197e9461dacec93bb019cb2a5d13d9621d62753ac70113bc09b66183a02d528d4bc71e22c02b2a401
|
7
|
+
data.tar.gz: 4f3a0bf99cdd27ac75142da244443a1f5378b03e36cf66be3a2fed14db919d82d4fa5110635600b2a85d749bd0c79a74f8db810fd3503cd8b863dfcf7d197149
|
data/Rakefile
CHANGED
data/TODO.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
- Unit tests for Messaging
|
2
2
|
- Handle cases where some messages sent are not ack'd with a timeout
|
3
3
|
- Handle cases where some messages sent come back with an error
|
4
|
-
|
4
|
+
- e.g. upgrade your client error
|
5
5
|
- Allow configuration of git remote
|
6
6
|
- Build against Cucumber 2.0 and 1.3.x
|
7
7
|
- SVN support
|
data/lib/cucumber/pro.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'cucumber/pro/formatter'
|
3
3
|
require 'cucumber/pro/web_socket/session'
|
4
|
+
require 'cucumber/pro/errors'
|
4
5
|
|
5
6
|
module Cucumber
|
6
7
|
module Pro
|
@@ -8,7 +9,7 @@ module Cucumber
|
|
8
9
|
class << self
|
9
10
|
def new(runtime, output, options)
|
10
11
|
create_logger(output)
|
11
|
-
session = WebSocket::Session.new(url, logger)
|
12
|
+
session = WebSocket::Session.new(url, logger, timeout: config.timeout)
|
12
13
|
Formatter.new(session)
|
13
14
|
end
|
14
15
|
|
@@ -41,31 +42,18 @@ module Cucumber
|
|
41
42
|
end
|
42
43
|
|
43
44
|
class Config
|
44
|
-
attr_accessor :url, :logger, :token
|
45
|
+
attr_accessor :url, :logger, :token, :timeout
|
45
46
|
end
|
46
47
|
|
47
48
|
# Default config
|
48
49
|
configure do |config|
|
49
|
-
config.url
|
50
|
-
config.token
|
51
|
-
|
52
|
-
|
50
|
+
config.url = ENV['CUCUMBER_PRO_URL'] || 'wss://results.cucumber.pro/ws'
|
51
|
+
config.token = ENV['CUCUMBER_PRO_TOKEN']
|
52
|
+
config.timeout = 5
|
53
|
+
if file = ENV['CUCUMBER_PRO_LOG_FILE']
|
54
|
+
config.logger = Logger.new(file)
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
module Error
|
57
|
-
AccessDenied = Class.new(StandardError) {
|
58
|
-
def initialize
|
59
|
-
super "Access denied."
|
60
|
-
end
|
61
|
-
}
|
62
|
-
|
63
|
-
MissingToken = Class.new(StandardError) {
|
64
|
-
def initialize
|
65
|
-
super "Missing access token. Please visit https://app.cucumber.pro/api-token for instructions."
|
66
|
-
end
|
67
|
-
}
|
68
|
-
end
|
69
|
-
|
70
58
|
end
|
71
59
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Pro
|
3
|
+
|
4
|
+
module Error
|
5
|
+
AccessDenied = Class.new(StandardError) {
|
6
|
+
def initialize
|
7
|
+
super "Access denied."
|
8
|
+
end
|
9
|
+
}
|
10
|
+
|
11
|
+
MissingToken = Class.new(StandardError) {
|
12
|
+
def initialize
|
13
|
+
super "Missing access token. Please visit https://app.cucumber.pro/my/profile for instructions."
|
14
|
+
end
|
15
|
+
}
|
16
|
+
|
17
|
+
Timeout = Class.new(StandardError) {
|
18
|
+
def initialize
|
19
|
+
super "Timed out waiting for a reply from the Cucumber Pro server."
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/lib/cucumber/pro/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.12
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'json'
|
2
2
|
require 'faye/websocket'
|
3
3
|
require 'eventmachine'
|
4
|
+
require 'cucumber/pro/errors'
|
4
5
|
|
5
6
|
module Cucumber
|
6
7
|
module Pro
|
@@ -8,7 +9,7 @@ module Cucumber
|
|
8
9
|
|
9
10
|
class Session
|
10
11
|
|
11
|
-
def initialize(url, logger)
|
12
|
+
def initialize(url, logger, options)
|
12
13
|
@url, @logger = url, logger
|
13
14
|
create_socket = -> worker {
|
14
15
|
ws = Faye::WebSocket::Client.new(@url, nil, ping: 15)
|
@@ -19,7 +20,7 @@ module Cucumber
|
|
19
20
|
ws
|
20
21
|
}
|
21
22
|
@queue = Queue.new
|
22
|
-
@socket = Worker.new(create_socket, logger, self)
|
23
|
+
@socket = Worker.new(create_socket, logger, self, options)
|
23
24
|
end
|
24
25
|
|
25
26
|
def send(message)
|
@@ -49,8 +50,9 @@ module Cucumber
|
|
49
50
|
|
50
51
|
class Worker
|
51
52
|
|
52
|
-
def initialize(create_socket, logger, error_handler)
|
53
|
+
def initialize(create_socket, logger, error_handler, options = {})
|
53
54
|
@create_socket, @logger, @error_handler = create_socket, logger, error_handler
|
55
|
+
@timeout = options.fetch(:timeout) { raise ArgumentError("Please specify timeout") }
|
54
56
|
@q = Queue.new
|
55
57
|
@em = Thread.new { start_client }
|
56
58
|
@ack_count = 0
|
@@ -59,8 +61,9 @@ module Cucumber
|
|
59
61
|
def close
|
60
62
|
@q << -> {
|
61
63
|
if @ack_count == 0
|
62
|
-
|
64
|
+
close_websocket
|
63
65
|
else
|
66
|
+
ensure_close_timer_started
|
64
67
|
EM.next_tick { close }
|
65
68
|
end
|
66
69
|
}
|
@@ -81,7 +84,25 @@ module Cucumber
|
|
81
84
|
|
82
85
|
private
|
83
86
|
|
84
|
-
attr_reader :logger, :error_handler, :next_task
|
87
|
+
attr_reader :logger, :error_handler, :next_task, :timeout
|
88
|
+
|
89
|
+
def ensure_close_timer_started
|
90
|
+
return if @close_timer
|
91
|
+
logger.debug [:ws, :set_close_timeout, timeout]
|
92
|
+
@close_timer = EM.add_timer(timeout) { handle_close_timeout }
|
93
|
+
end
|
94
|
+
|
95
|
+
def handle_close_timeout
|
96
|
+
logger.debug [:ws, :handle_close_timeout]
|
97
|
+
return unless @ws
|
98
|
+
error_handler.error Error::Timeout.new
|
99
|
+
close_websocket
|
100
|
+
end
|
101
|
+
|
102
|
+
def close_websocket
|
103
|
+
logger.debug [:ws, :close_socket]
|
104
|
+
@ws.close
|
105
|
+
end
|
85
106
|
|
86
107
|
def start_client
|
87
108
|
EM.run do
|
@@ -1,79 +1,103 @@
|
|
1
1
|
require 'cucumber/pro/web_socket/session'
|
2
2
|
require 'logger'
|
3
3
|
|
4
|
-
module Cucumber::Pro
|
4
|
+
module Cucumber::Pro
|
5
|
+
module WebSocket
|
6
|
+
|
7
|
+
describe Worker do
|
8
|
+
let(:good_data) { double('good data') }
|
9
|
+
let(:error_handler) { double('error handler') }
|
10
|
+
let(:logger) { Logger.new(ENV['CUCUMBER_PRO_LOG_PATH'] || STDOUT) }
|
11
|
+
let!(:socket) { SpySocket.new }
|
12
|
+
let(:worker) { Worker.new(self.method(:create_fake_socket), logger, error_handler, timeout: 0.5) }
|
13
|
+
|
14
|
+
before { logger.level = Logger::DEBUG }
|
15
|
+
|
16
|
+
it "closes once all messages have been acknowledged (but not before)" do
|
17
|
+
worker.send(good_data)
|
18
|
+
worker.close
|
19
|
+
eventually do
|
20
|
+
socket.data.last.should == good_data
|
21
|
+
end
|
22
|
+
eventually do
|
23
|
+
expect( worker ).to_not be_closed
|
24
|
+
end
|
25
|
+
socket.send_ack
|
26
|
+
eventually do
|
27
|
+
expect( worker ).to be_closed
|
28
|
+
end
|
29
|
+
end
|
5
30
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
31
|
+
it "throws an error and closes if all messages are not acknowledged within a timeout period" do
|
32
|
+
expect( error_handler ).to receive(:error).with(Error::Timeout.new)
|
33
|
+
worker.send(good_data)
|
34
|
+
worker.close
|
35
|
+
eventually do
|
36
|
+
expect( worker ).to be_closed
|
37
|
+
end
|
38
|
+
end
|
11
39
|
|
12
|
-
|
40
|
+
it "throws an error if the server responds with an error"
|
13
41
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
eventually do
|
21
|
-
expect( worker ).to_not be_closed
|
22
|
-
end
|
23
|
-
socket.send_ack
|
24
|
-
eventually do
|
25
|
-
expect( worker ).to be_closed
|
42
|
+
def create_fake_socket(worker)
|
43
|
+
socket.worker = worker
|
44
|
+
EM.next_tick {
|
45
|
+
worker.method(:on_open).call(double('ws event'))
|
46
|
+
}
|
47
|
+
socket
|
26
48
|
end
|
27
|
-
end
|
28
49
|
|
29
|
-
def create_fake_socket(worker)
|
30
|
-
socket.worker = worker
|
31
|
-
EM.next_tick {
|
32
|
-
worker.method(:on_open).call(double('ws event'))
|
33
|
-
}
|
34
|
-
socket
|
35
|
-
end
|
36
50
|
|
51
|
+
class SpySocket
|
52
|
+
include RSpec::Mocks::ExampleMethods
|
37
53
|
|
38
|
-
|
39
|
-
|
54
|
+
attr_accessor :worker
|
55
|
+
attr_reader :data
|
40
56
|
|
41
|
-
|
42
|
-
|
57
|
+
def initialize
|
58
|
+
@q = Queue.new
|
59
|
+
end
|
43
60
|
|
44
|
-
|
45
|
-
|
46
|
-
|
61
|
+
def close
|
62
|
+
worker.method(:on_close).call(ws_event(1000))
|
63
|
+
end
|
47
64
|
|
48
|
-
|
49
|
-
|
50
|
-
|
65
|
+
def send(data)
|
66
|
+
@q << data
|
67
|
+
self
|
68
|
+
end
|
51
69
|
|
52
|
-
|
53
|
-
|
54
|
-
|
70
|
+
def send_ack
|
71
|
+
event = ws_event(1000, { 'type' => 'metadata_saved' })
|
72
|
+
worker.method(:on_message).call(event)
|
73
|
+
end
|
55
74
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
75
|
+
def data
|
76
|
+
@data ||= []
|
77
|
+
while !@q.empty?
|
78
|
+
@data << @q.pop
|
79
|
+
end
|
80
|
+
@data
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
60
84
|
|
61
|
-
|
85
|
+
def ws_event(code, data = {})
|
86
|
+
double('ws event', code: 1000, data: data)
|
87
|
+
end
|
62
88
|
|
63
|
-
def ws_event(code, data = {})
|
64
|
-
double('ws event', code: 1000, data: data)
|
65
89
|
end
|
66
|
-
end
|
67
90
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
91
|
+
require 'anticipate'
|
92
|
+
include Anticipate
|
93
|
+
def eventually(&block)
|
94
|
+
result = nil
|
95
|
+
sleeping(0.1).seconds.between_tries.failing_after(50).tries do
|
96
|
+
result = block.call
|
97
|
+
end
|
98
|
+
result
|
74
99
|
end
|
75
|
-
result
|
76
100
|
end
|
77
|
-
end
|
78
101
|
|
102
|
+
end
|
79
103
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cucumber-pro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Wynne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faye-websocket
|
@@ -158,6 +158,7 @@ files:
|
|
158
158
|
- features/support/fake_results_service.rb
|
159
159
|
- features/support/world.rb
|
160
160
|
- lib/cucumber/pro.rb
|
161
|
+
- lib/cucumber/pro/errors.rb
|
161
162
|
- lib/cucumber/pro/formatter.rb
|
162
163
|
- lib/cucumber/pro/info.rb
|
163
164
|
- lib/cucumber/pro/scm/working_copy.rb
|
@@ -190,7 +191,7 @@ rubyforge_project:
|
|
190
191
|
rubygems_version: 2.0.14
|
191
192
|
signing_key:
|
192
193
|
specification_version: 4
|
193
|
-
summary: cucumber-pro-0.0.
|
194
|
+
summary: cucumber-pro-0.0.12
|
194
195
|
test_files:
|
195
196
|
- features/publish_results.feature
|
196
197
|
- features/security.feature
|