isomorfeus-puppetmaster 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +191 -0
- data/lib/isomorfeus-puppetmaster.rb +43 -0
- data/lib/isomorfeus/puppetmaster.rb +62 -0
- data/lib/isomorfeus/puppetmaster/console_message.rb +19 -0
- data/lib/isomorfeus/puppetmaster/cookie.rb +46 -0
- data/lib/isomorfeus/puppetmaster/document.rb +160 -0
- data/lib/isomorfeus/puppetmaster/driver/jsdom.rb +370 -0
- data/lib/isomorfeus/puppetmaster/driver/jsdom_document.rb +908 -0
- data/lib/isomorfeus/puppetmaster/driver/jsdom_node.rb +836 -0
- data/lib/isomorfeus/puppetmaster/driver/puppeteer.rb +401 -0
- data/lib/isomorfeus/puppetmaster/driver/puppeteer_document.rb +944 -0
- data/lib/isomorfeus/puppetmaster/driver/puppeteer_node.rb +866 -0
- data/lib/isomorfeus/puppetmaster/driver_registration.rb +19 -0
- data/lib/isomorfeus/puppetmaster/dsl.rb +40 -0
- data/lib/isomorfeus/puppetmaster/errors.rb +90 -0
- data/lib/isomorfeus/puppetmaster/iframe.rb +17 -0
- data/lib/isomorfeus/puppetmaster/node.rb +241 -0
- data/lib/isomorfeus/puppetmaster/node/checkbox.rb +17 -0
- data/lib/isomorfeus/puppetmaster/node/content_editable.rb +18 -0
- data/lib/isomorfeus/puppetmaster/node/filechooser.rb +9 -0
- data/lib/isomorfeus/puppetmaster/node/input.rb +21 -0
- data/lib/isomorfeus/puppetmaster/node/radiobutton.rb +13 -0
- data/lib/isomorfeus/puppetmaster/node/select.rb +36 -0
- data/lib/isomorfeus/puppetmaster/node/textarea.rb +7 -0
- data/lib/isomorfeus/puppetmaster/request.rb +17 -0
- data/lib/isomorfeus/puppetmaster/response.rb +26 -0
- data/lib/isomorfeus/puppetmaster/rspec/features.rb +23 -0
- data/lib/isomorfeus/puppetmaster/rspec/matcher_proxies.rb +80 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers.rb +164 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/base.rb +98 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/become_closed.rb +33 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/compound.rb +88 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_current_path.rb +29 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_selector.rb +69 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_text.rb +33 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/have_title.rb +29 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/match_selector.rb +27 -0
- data/lib/isomorfeus/puppetmaster/rspec/matchers/match_style.rb +38 -0
- data/lib/isomorfeus/puppetmaster/self_forwardable.rb +31 -0
- data/lib/isomorfeus/puppetmaster/server.rb +128 -0
- data/lib/isomorfeus/puppetmaster/server/checker.rb +40 -0
- data/lib/isomorfeus/puppetmaster/server/middleware.rb +60 -0
- data/lib/isomorfeus/puppetmaster/server_registration.rb +37 -0
- data/lib/isomorfeus/puppetmaster/version.rb +3 -0
- metadata +282 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara
|
4
|
+
module RSpecMatchers
|
5
|
+
module Matchers
|
6
|
+
class BecomeClosed
|
7
|
+
def initialize(options)
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(window)
|
12
|
+
@window = window
|
13
|
+
@wait_time = Capybara::Queries::BaseQuery.wait(@options, window.session.config.default_max_wait_time)
|
14
|
+
timer = Capybara::Helpers.timer(expire_in: @wait_time)
|
15
|
+
while window.exists?
|
16
|
+
return false if timer.expired?
|
17
|
+
|
18
|
+
sleep 0.01
|
19
|
+
end
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def failure_message
|
24
|
+
"expected #{@window.inspect} to become closed after #{@wait_time} seconds"
|
25
|
+
end
|
26
|
+
|
27
|
+
def failure_message_when_negated
|
28
|
+
"expected #{@window.inspect} not to become closed after #{@wait_time} seconds"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(::RSpec::Expectations::Version)
|
4
|
+
module Capybara
|
5
|
+
module RSpecMatchers
|
6
|
+
module Matchers
|
7
|
+
module Compound
|
8
|
+
include ::RSpec::Matchers::Composable
|
9
|
+
|
10
|
+
def and(matcher)
|
11
|
+
And.new(self, matcher)
|
12
|
+
end
|
13
|
+
|
14
|
+
def and_then(matcher)
|
15
|
+
::RSpec::Matchers::BuiltIn::Compound::And.new(self, matcher)
|
16
|
+
end
|
17
|
+
|
18
|
+
def or(matcher)
|
19
|
+
Or.new(self, matcher)
|
20
|
+
end
|
21
|
+
|
22
|
+
class CapybaraEvaluator
|
23
|
+
def initialize(actual)
|
24
|
+
@actual = actual
|
25
|
+
@match_results = Hash.new { |hsh, matcher| hsh[matcher] = matcher.matches?(@actual) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def matcher_matches?(matcher)
|
29
|
+
@match_results[matcher]
|
30
|
+
end
|
31
|
+
|
32
|
+
def reset
|
33
|
+
@match_results.clear
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api private
|
38
|
+
module Synchronizer
|
39
|
+
def match(_expected, actual)
|
40
|
+
@evaluator = CapybaraEvaluator.new(actual)
|
41
|
+
syncer = sync_element(actual)
|
42
|
+
begin
|
43
|
+
syncer.synchronize do
|
44
|
+
@evaluator.reset
|
45
|
+
raise ::Capybara::ElementNotFound unless synchronized_match?
|
46
|
+
|
47
|
+
true
|
48
|
+
end
|
49
|
+
rescue StandardError
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def sync_element(el)
|
55
|
+
if el.respond_to? :synchronize
|
56
|
+
el
|
57
|
+
elsif el.respond_to? :current_scope
|
58
|
+
el.current_scope
|
59
|
+
else
|
60
|
+
Capybara.string(el)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class And < ::RSpec::Matchers::BuiltIn::Compound::And
|
66
|
+
include Synchronizer
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def synchronized_match?
|
71
|
+
[matcher_1_matches?, matcher_2_matches?].all?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Or < ::RSpec::Matchers::BuiltIn::Compound::Or
|
76
|
+
include Synchronizer
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def synchronized_match?
|
81
|
+
[matcher_1_matches?, matcher_2_matches?].any?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveCurrentPath < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_current_path(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_current_path(*@args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"have current path #{current_path.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def current_path
|
24
|
+
@args.first
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveSelector < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_selector(*@args, &@filter_block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_selector(*@args, &@filter_block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"have #{query.description}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def query
|
22
|
+
@query ||= Capybara::Queries::SelectorQuery.new(*session_query_args, &@filter_block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class HaveAllSelectors < WrappedElementMatcher
|
27
|
+
def element_matches?(el)
|
28
|
+
el.assert_all_of_selectors(*@args, &@filter_block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def does_not_match?(_actual)
|
32
|
+
raise ArgumentError, 'The have_all_selectors matcher does not support use with not_to/should_not'
|
33
|
+
end
|
34
|
+
|
35
|
+
def description
|
36
|
+
'have all selectors'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class HaveNoSelectors < WrappedElementMatcher
|
41
|
+
def element_matches?(el)
|
42
|
+
el.assert_none_of_selectors(*@args, &@filter_block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def does_not_match?(_actual)
|
46
|
+
raise ArgumentError, 'The have_none_of_selectors matcher does not support use with not_to/should_not'
|
47
|
+
end
|
48
|
+
|
49
|
+
def description
|
50
|
+
'have no selectors'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class HaveAnySelectors < WrappedElementMatcher
|
55
|
+
def element_matches?(el)
|
56
|
+
el.assert_any_of_selectors(*@args, &@filter_block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def does_not_match?(_actual)
|
60
|
+
el.assert_none_of_selectors(*@args, &@filter_block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def description
|
64
|
+
'have any selectors'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveText < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_text(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_text(*@args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"text #{format(text)}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def format(content)
|
22
|
+
content.inspect
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def text
|
28
|
+
@args[0].is_a?(Symbol) ? @args[1] : @args[0]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class HaveTitle < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_title(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_no_title(*@args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"have title #{title.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def title
|
24
|
+
@args.first
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/have_selector'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class MatchSelector < HaveSelector
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_matches_selector(*@args, &@filter_block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def element_does_not_match?(el)
|
14
|
+
el.assert_not_matches_selector(*@args, &@filter_block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
"match #{query.description}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def query
|
22
|
+
@query ||= Capybara::Queries::MatchQuery.new(*session_query_args, &@filter_block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/rspec/matchers/base'
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module RSpecMatchers
|
7
|
+
module Matchers
|
8
|
+
class MatchStyle < WrappedElementMatcher
|
9
|
+
def element_matches?(el)
|
10
|
+
el.assert_matches_style(*@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def does_not_match?(_actual)
|
14
|
+
raise ArgumentError, 'The match_style matcher does not support use with not_to/should_not'
|
15
|
+
end
|
16
|
+
|
17
|
+
def description
|
18
|
+
'match style'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Capybara
|
26
|
+
module RSpecMatchers
|
27
|
+
module Matchers
|
28
|
+
##
|
29
|
+
# @deprecated
|
30
|
+
class HaveStyle < MatchStyle
|
31
|
+
def initialize(*args, &filter_block)
|
32
|
+
warn 'HaveStyle matcher is deprecated, please use the MatchStyle matcher instead'
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Puppetmaster
|
3
|
+
module SelfForwardable
|
4
|
+
def self.extended(base)
|
5
|
+
base.define_singleton_method(:document_forward) do |methods|
|
6
|
+
methods.each do |method|
|
7
|
+
define_method(method) do |*args, &block|
|
8
|
+
@driver.send("document_#{method}", self, *args, &block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
base.define_singleton_method(:frame_forward) do |methods|
|
14
|
+
methods.each do |method|
|
15
|
+
define_method(method) do |*args|
|
16
|
+
@driver.send("frame_#{method}", self, *args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
base.define_singleton_method(:node_forward) do |methods|
|
22
|
+
methods.each do |method|
|
23
|
+
define_method(method) do |*args|
|
24
|
+
@driver.send("node_#{method}", self, *args)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Isomorfeus
|
2
|
+
module Puppetmaster
|
3
|
+
class Server
|
4
|
+
class Timer
|
5
|
+
def initialize(expire_in:)
|
6
|
+
@start = current
|
7
|
+
@expire_in = expire_in
|
8
|
+
end
|
9
|
+
|
10
|
+
def expired?
|
11
|
+
raise Isomorfeus::Puppetmaster::FrozenInTime, 'Time appears to be frozen. Puppetmaster does not work with libraries which freeze time, consider using time travelling instead' if stalled?
|
12
|
+
|
13
|
+
current - @start >= @expire_in
|
14
|
+
end
|
15
|
+
|
16
|
+
def stalled?
|
17
|
+
@start == current
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
if defined?(Process::CLOCK_MONOTONIC)
|
23
|
+
def current; Process.clock_gettime Process::CLOCK_MONOTONIC; end
|
24
|
+
else
|
25
|
+
def current; Time.now.to_f; end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def ports
|
31
|
+
@ports ||= {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :app, :port, :host
|
36
|
+
|
37
|
+
def initialize(app,
|
38
|
+
port: Isomorfeus::Puppetmaster.server_port,
|
39
|
+
host: Isomorfeus::Puppetmaster.server_host,
|
40
|
+
extra_middleware: [])
|
41
|
+
@app = app
|
42
|
+
@extra_middleware = extra_middleware
|
43
|
+
@server_thread = nil # suppress warnings
|
44
|
+
@host = host
|
45
|
+
@port = port
|
46
|
+
@port ||= Isomorfeus::Puppetmaster::Server.ports[port_key]
|
47
|
+
@port ||= find_available_port(host)
|
48
|
+
@checker = Isomorfeus::Puppetmaster::Server::Checker.new(@host, @port)
|
49
|
+
end
|
50
|
+
|
51
|
+
def reset_error!
|
52
|
+
middleware.clear_error
|
53
|
+
end
|
54
|
+
|
55
|
+
def error
|
56
|
+
middleware.error
|
57
|
+
end
|
58
|
+
|
59
|
+
def using_ssl?
|
60
|
+
@checker.ssl?
|
61
|
+
end
|
62
|
+
|
63
|
+
def scheme
|
64
|
+
using_ssl? ? 'https' : 'http'
|
65
|
+
end
|
66
|
+
|
67
|
+
def responsive?
|
68
|
+
return false if @server_thread&.join(0)
|
69
|
+
|
70
|
+
res = @checker.request { |http| http.get('/__identify__') }
|
71
|
+
|
72
|
+
return res.body == app.object_id.to_s if res.is_a?(Net::HTTPSuccess) || res.is_a?(Net::HTTPRedirection)
|
73
|
+
rescue SystemCallError, Net::ReadTimeout, OpenSSL::SSL::SSLError
|
74
|
+
false
|
75
|
+
end
|
76
|
+
|
77
|
+
def wait_for_pending_requests
|
78
|
+
timer = Isomorfeus::Puppetmaster::Server::Timer.new(expire_in: 60)
|
79
|
+
while pending_requests?
|
80
|
+
raise 'Requests did not finish in 60 seconds' if timer.expired?
|
81
|
+
|
82
|
+
sleep 0.01
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def boot
|
87
|
+
unless responsive?
|
88
|
+
Isomorfeus::Puppetmaster::Server.ports[port_key] = port
|
89
|
+
|
90
|
+
@server_thread = Thread.new do
|
91
|
+
Isomorfeus::Puppetmaster.server.call(middleware, port, host)
|
92
|
+
end
|
93
|
+
|
94
|
+
timer = Isomorfeus::Puppetmaster::Server::Timer.new(expire_in: 60)
|
95
|
+
until responsive?
|
96
|
+
raise 'Rack application timed out during boot' if timer.expired?
|
97
|
+
|
98
|
+
@server_thread.join(0.1)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def middleware
|
108
|
+
@middleware ||= ::Isomorfeus::Puppetmaster::Server::Middleware.new(app, @extra_middleware)
|
109
|
+
end
|
110
|
+
|
111
|
+
def port_key
|
112
|
+
app.object_id
|
113
|
+
end
|
114
|
+
|
115
|
+
def pending_requests?
|
116
|
+
middleware.pending_requests?
|
117
|
+
end
|
118
|
+
|
119
|
+
def find_available_port(host)
|
120
|
+
server = TCPServer.new(host, 0)
|
121
|
+
server.addr[1]
|
122
|
+
ensure
|
123
|
+
server&.close
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|