proxy_rb 0.4.0 → 0.5.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +9 -4
  3. data/Gemfile +2 -2
  4. data/History.md +17 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +15 -4
  7. data/Rakefile +8 -2
  8. data/exe/proxy_rb +8 -0
  9. data/fixtures/empty/README.md +18 -0
  10. data/fixtures/empty/Rakefile +10 -0
  11. data/lib/proxy_rb/announcer.rb +162 -0
  12. data/lib/proxy_rb/{rspec/helpers → api}/.keep +0 -0
  13. data/lib/proxy_rb/api/core.rb +25 -0
  14. data/lib/proxy_rb/api/http_proxy.rb +94 -0
  15. data/lib/proxy_rb/api/passwords.rb +26 -0
  16. data/lib/proxy_rb/api.rb +19 -0
  17. data/lib/proxy_rb/basic_configuration/{in_config_wrapper.rb → in_configuration_wrapper.rb} +1 -1
  18. data/lib/proxy_rb/basic_configuration.rb +2 -2
  19. data/lib/proxy_rb/cli.rb +27 -0
  20. data/lib/proxy_rb/colorizer.rb +113 -0
  21. data/lib/proxy_rb/configuration.rb +1 -1
  22. data/lib/proxy_rb/configuration_wrapper.rb +59 -0
  23. data/lib/proxy_rb/console/help.rb +29 -0
  24. data/lib/proxy_rb/console.rb +62 -0
  25. data/lib/proxy_rb/credentials.rb +11 -0
  26. data/lib/proxy_rb/drivers/poltergeist_driver.rb +8 -2
  27. data/lib/proxy_rb/drivers/selenium_driver.rb +7 -1
  28. data/lib/proxy_rb/drivers/webkit_driver.rb +10 -1
  29. data/lib/proxy_rb/errors.rb +12 -0
  30. data/lib/proxy_rb/event_bus/name_resolver.rb +163 -0
  31. data/lib/proxy_rb/event_bus.rb +60 -0
  32. data/lib/proxy_rb/events.rb +34 -0
  33. data/lib/proxy_rb/http_proxy.rb +8 -0
  34. data/lib/proxy_rb/initializer.rb +132 -0
  35. data/lib/proxy_rb/{rspec/matchers → matchers}/.keep +0 -0
  36. data/lib/proxy_rb/matchers/be_forbidden.rb +14 -0
  37. data/lib/proxy_rb/matchers/be_successful.rb +14 -0
  38. data/lib/proxy_rb/matchers/have_mime_type.rb +9 -0
  39. data/lib/proxy_rb/password_fetchers/basic_password_fetcher.rb +25 -0
  40. data/lib/proxy_rb/password_fetchers/chaining_password_fetcher.rb +54 -0
  41. data/lib/proxy_rb/password_fetchers/environment_password_fetcher.rb +7 -1
  42. data/lib/proxy_rb/password_fetchers/vault_password_fetcher.rb +7 -1
  43. data/lib/proxy_rb/proxy_url.rb +8 -0
  44. data/lib/proxy_rb/request.rb +5 -21
  45. data/lib/proxy_rb/resource.rb +11 -7
  46. data/lib/proxy_rb/response.rb +5 -13
  47. data/lib/proxy_rb/rspec.rb +32 -13
  48. data/lib/proxy_rb/runtime.rb +49 -0
  49. data/lib/proxy_rb/setup.rb +60 -0
  50. data/lib/proxy_rb/version.rb +1 -1
  51. data/proxy_rb.gemspec +2 -2
  52. metadata +38 -29
  53. data/lib/proxy_rb/rspec/helpers/http_proxy.rb +0 -83
  54. data/lib/proxy_rb/rspec/helpers/passwords.rb +0 -29
  55. data/lib/proxy_rb/rspec/shared_contexts/.keep +0 -0
  56. data/lib/proxy_rb/rspec/shared_examples/.keep +0 -0
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+ require 'thor/group'
3
+ require 'thor/actions'
4
+
5
+ # ProxyRb
6
+ module ProxyRb
7
+ # Initializers
8
+ #
9
+ # Initialize project with proxy_rb configuration files
10
+ module Initializers
11
+ # Common initializer
12
+ #
13
+ # @private
14
+ class CommonInitializer < Thor::Group
15
+ include Thor::Actions
16
+
17
+ # Add gem to gemfile
18
+ def add_gem
19
+ file = 'Gemfile'
20
+ creator = if File.exist? file
21
+ :append_to_file
22
+ else
23
+ :create_file
24
+ end
25
+
26
+ content = if File.exist? file
27
+ %(gem 'proxy_rb', '~> #{ProxyRb::VERSION}')
28
+ else
29
+ %(source 'https://rubygems.org'\ngem 'proxy_rb', '~> #{ProxyRb::VERSION}'\n)
30
+ end
31
+ send creator, file, content
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ # ProxyRb
38
+ module ProxyRb
39
+ # Initializers
40
+ module Initializers
41
+ # Default Initializer
42
+ #
43
+ # This handles invalid values for initializer.
44
+ #
45
+ # @private
46
+ class FailingInitializer
47
+ class << self
48
+ def match?(*)
49
+ true
50
+ end
51
+
52
+ def start(*)
53
+ raise ArgumentError, %(Unknown test framework. Please use "rspec" )
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ # ProxyRb
61
+ module ProxyRb
62
+ # Initializer
63
+ module Initializers
64
+ # Add proxy_rb + rspec to project
65
+ #
66
+ # @private
67
+ class RSpecInitializer < Thor::Group
68
+ include Thor::Actions
69
+
70
+ no_commands do
71
+ def self.match?(framework)
72
+ :rspec == framework.downcase.to_sym
73
+ end
74
+ end
75
+
76
+ def create_helper
77
+ file = 'spec/spec_helper.rb'
78
+ creator = if File.exist? file
79
+ :append_to_file
80
+ else
81
+ :create_file
82
+ end
83
+
84
+ send creator, file, <<~EOS
85
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
86
+
87
+ ::Dir.glob(::File.expand_path('../support/*.rb', __FILE__)).each { |f| require_relative f }
88
+ ::Dir.glob(::File.expand_path('../support/**/*.rb', __FILE__)).each { |f| require_relative f }
89
+ EOS
90
+ end
91
+
92
+ def create_support_file
93
+ create_file 'spec/support/proxy_rb.rb', <<~EOS
94
+ require 'proxy_rb/rspec'
95
+ EOS
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ # ProxyRb
102
+ module ProxyRb
103
+ # The whole initializer
104
+ #
105
+ # This one uses the specific initializers to generate the needed files.
106
+ #
107
+ # @private
108
+ class Initializer
109
+ private
110
+
111
+ attr_reader :initializers
112
+
113
+ public
114
+
115
+ def initialize
116
+ @initializers = []
117
+ @initializers << Initializers::RSpecInitializer
118
+ end
119
+
120
+ # Create files etc.
121
+ def call(test_framework)
122
+ begin
123
+ initializers.find { |i| i.match? test_framework }.start [], {}
124
+ rescue ArgumentError => e
125
+ $stderr.puts e.message
126
+ exit 0
127
+ end
128
+
129
+ Initializers::CommonInitializer.start [], {}
130
+ end
131
+ end
132
+ end
File without changes
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ RSpec::Matchers.define :be_forbidden do
3
+ match do |actual|
4
+ values_match?(403, actual.status_code)
5
+ end
6
+
7
+ failure_message do |actual|
8
+ %(expected that response has status code 403, but has #{actual.status_code})
9
+ end
10
+
11
+ failure_message_when_negated do
12
+ %(expected that response does not have status code 403)
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ RSpec::Matchers.define :be_successful do
3
+ match do |actual|
4
+ actual.status_code.to_s.start_with?('2', '3')
5
+ end
6
+
7
+ failure_message do |actual|
8
+ %(expected that response has status code 2xx, but has #{actual.status_code})
9
+ end
10
+
11
+ failure_message_when_negated do
12
+ %(expected that response does not have status code 2xx)
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ RSpec::Matchers.define :have_mime_type do |expected|
3
+ match do |actual|
4
+ @actual = actual.mime_type
5
+ values_match?(expected, @actual)
6
+ end
7
+ end
8
+
9
+ RSpec::Matchers.alias_matcher :be_of_mime_type, :have_mime_type
@@ -7,6 +7,31 @@ module ProxyRb
7
7
  def call(_user_name)
8
8
  raise NotImplementedError, 'You need to implement `#call` for a valid password fetcher'
9
9
  end
10
+
11
+ private
12
+
13
+ def read(_string)
14
+ raise NotImplementedError, 'You need to implement `#read` for a valid password fetcher'
15
+ end
16
+
17
+ # @param [String] user_name
18
+ #
19
+ # @raise [ArgumentError]
20
+ # Raised if password cannot be retrieved for user
21
+ #
22
+ # @return [String]
23
+ # The password
24
+ def fetch_password_for_user(user_name)
25
+ if read(user_name.upcase)
26
+ read(user_name.upcase)
27
+ elsif read(user_name.downcase)
28
+ read(user_name.downcase)
29
+ elsif read(user_name)
30
+ read(user_name)
31
+ else
32
+ raise ArgumentError, %(Failed to fetch password for username "#{user_name}")
33
+ end
34
+ end
10
35
  end
11
36
  end
12
37
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require 'proxy_rb/password_fetchers/basic_password_fetcher'
3
+
4
+ module ProxyRb
5
+ # Fetch password for user...
6
+ module PasswordFetchers
7
+ # ... process environment
8
+ class ChainingPasswordFetcher < BasicPasswordFetcher
9
+ include Contracts::Core
10
+ include Contracts::Builtin
11
+
12
+ protected
13
+
14
+ attr_reader :fetchers
15
+
16
+ public
17
+
18
+ # Prefix of key in Environment
19
+ def initialize(fetchers)
20
+ @fetchers = Array(fetchers)
21
+ end
22
+
23
+ # @param [String] user_name
24
+ # Look up user name
25
+ Contract String => String
26
+ def call(user_name)
27
+ fetch_password_for_user(user_name)
28
+ end
29
+
30
+ private
31
+
32
+ def fetch_password_for_user(user_name)
33
+ result = nil
34
+
35
+ fetchers.each do |f|
36
+ begin
37
+ result = f.call(user_name)
38
+ rescue ArgumentError
39
+ result = nil
40
+ end
41
+
42
+ break unless result.nil?
43
+ end
44
+
45
+ raise ArgumentError, %(Failed to fetch password for username "#{user_name}") if result.nil?
46
+
47
+ result
48
+ end
49
+
50
+ # Not needed for this fetcher
51
+ def read(_string); end
52
+ end
53
+ end
54
+ end
@@ -26,9 +26,15 @@ module ProxyRb
26
26
  Contract String => String
27
27
  def call(user_name)
28
28
  UserPasswords::EnvironmentUserPassword.new(
29
- ENV[format('%s_%s', prefix, user_name.upcase)]
29
+ fetch_password_for_user(user_name)
30
30
  ).to_s
31
31
  end
32
+
33
+ private
34
+
35
+ def read(string)
36
+ ENV[format('%s_%s', prefix, string)]
37
+ end
32
38
  end
33
39
  end
34
40
  end
@@ -38,10 +38,16 @@ module ProxyRb
38
38
  def call(user_name)
39
39
  client.with_retries(::Vault::HTTPConnectionError, ::Vault::HTTPError) do |_attempt, _e|
40
40
  UserPasswords::VaultUserPassword.new(
41
- ::Vault.logical.read(File.join(prefix, user_name))
41
+ fetch_password_for_user(user_name)
42
42
  ).to_s
43
43
  end
44
44
  end
45
+
46
+ private
47
+
48
+ def read(string)
49
+ ::Vault.logical.read(File.join(prefix, string))
50
+ end
45
51
  end
46
52
  end
47
53
  end
@@ -78,5 +78,13 @@ module ProxyRb
78
78
 
79
79
  self.class.build(h)
80
80
  end
81
+
82
+ # Return url as hash
83
+ #
84
+ # @return [Hash]
85
+ # the converted url
86
+ def to_hash
87
+ url.to_hash
88
+ end
81
89
  end
82
90
  end
@@ -1,24 +1,16 @@
1
1
  # frozen_string_literal: true
2
+ require 'delegate'
3
+
2
4
  # ProxyRb
3
5
  module ProxyRb
4
6
  # An HTTP request
5
- class Request
6
- protected
7
-
8
- attr_reader :page
9
-
10
- public
11
-
12
- def initialize(page)
13
- @page = page
14
- end
15
-
7
+ class Request < SimpleDelegator
16
8
  # Was the request successful
17
9
  #
18
10
  # @return [TrueClass, FalseClass]
19
11
  # The result
20
12
  def successful?
21
- page.status_code.to_s.start_with?('2', '3')
13
+ __getobj__.status_code.to_s.start_with?('2', '3')
22
14
  end
23
15
 
24
16
  # The request is forbidden
@@ -26,15 +18,7 @@ module ProxyRb
26
18
  # @return [TrueClass, FalseClass]
27
19
  # The result
28
20
  def forbidden?
29
- page.status_code == 403
21
+ __getobj__.status_code == 403
30
22
  end
31
-
32
- # def invalid?
33
- # page.status_code == 401
34
- # end
35
-
36
- # def redirected?
37
- # page.status_code.to_s.start_with? '3'
38
- # end
39
23
  end
40
24
  end
@@ -1,27 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
  require 'addressable/uri'
3
+ require 'proxy_rb/credentials'
3
4
 
4
5
  # ProxyRb
5
6
  module ProxyRb
6
7
  # A resource
7
8
  class Resource
8
9
  attr_accessor :content
9
-
10
- private
11
-
12
- attr_reader :url
13
-
14
- public
10
+ attr_reader :credentials, :url
15
11
 
16
12
  def initialize(url)
17
13
  @url = Addressable::URI.parse(url)
18
14
  end
19
15
 
16
+ # Return credentials from url
17
+ #
18
+ # @return [Credentials]
19
+ # The credentials from url
20
+ def credentials
21
+ Credentials.new(url.user, url.password)
22
+ end
23
+
20
24
  # Convert resource to url
21
25
  #
22
26
  # @return [String] url
23
27
  # The url
24
- def to_url
28
+ def to_s
25
29
  url.to_s
26
30
  end
27
31
  end
@@ -1,20 +1,12 @@
1
1
  # frozen_string_literal: true
2
+ require 'delegate'
3
+
2
4
  # ProxyRb
3
5
  module ProxyRb
4
6
  # A response
5
- class Response
6
- protected
7
-
8
- attr_reader :page
9
-
10
- public
11
-
12
- def initialize(page)
13
- @page = page
7
+ class Response < SimpleDelegator
8
+ def mime_type
9
+ __getobj__.driver.response_headers['Content-Type']
14
10
  end
15
-
16
- # def forbidden?
17
- # page.status_code == 403
18
- # end
19
11
  end
20
12
  end
@@ -1,14 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'rspec'
3
- require 'capybara/rspec'
4
-
5
- require 'proxy_rb'
6
- require 'proxy_rb/no_proxy'
7
-
8
- ProxyRb.require_files_matching_pattern('rspec/helpers/*.rb')
9
- ProxyRb.require_files_matching_pattern('rspec/matchers/*.rb')
10
- ProxyRb.require_files_matching_pattern('rspec/shared_examples/*.rb')
11
- ProxyRb.require_files_matching_pattern('rspec/shared_contexts/*.rb')
2
+ require 'proxy_rb/api'
12
3
 
13
4
  # Main Module
14
5
  module ProxyRb
@@ -18,7 +9,35 @@ module ProxyRb
18
9
  end
19
10
 
20
11
  RSpec.configure do |config|
21
- config.include ProxyRb::Rspec::Helpers::HttpProxy, type: :http_proxy
22
- config.include ProxyRb::Rspec::Helpers::Passwords, type: :http_proxy
23
- config.include Capybara::RSpecMatchers, type: :http_proxy
12
+ config.include ProxyRb::Api, type: :http_proxy
13
+
14
+ # Setup ProxyRb
15
+ config.before :each do |_example|
16
+ next unless self.class.include? ProxyRb::Api
17
+
18
+ setup_proxy_rb
19
+ end
20
+
21
+ config.before :each do |example|
22
+ next unless self.class.include? ProxyRb::Api
23
+
24
+ example.metadata.each { |k, v| proxy_rb.config.set_if_option(k, v) }
25
+ end
26
+
27
+ # Activate announcers based on rspec metadata
28
+ config.before :each do |example|
29
+ next unless self.class.include? ProxyRb::Api
30
+
31
+ proxy_rb.announcer.activate(:proxy) if example.metadata[:announce_proxy]
32
+ proxy_rb.announcer.activate(:proxy_user) if example.metadata[:announce_proxy_user]
33
+ proxy_rb.announcer.activate(:resource) if example.metadata[:announce_resource]
34
+ proxy_rb.announcer.activate(:resource_user) if example.metadata[:announce_resource_user]
35
+
36
+ if example.metadata[:announce]
37
+ proxy_rb.announcer.activate(:proxy)
38
+ proxy_rb.announcer.activate(:proxy_user)
39
+ proxy_rb.announcer.activate(:resource)
40
+ proxy_rb.announcer.activate(:resource_user)
41
+ end
42
+ end
24
43
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ require 'proxy_rb/configuration'
3
+ require 'proxy_rb/configuration_wrapper'
4
+ require 'proxy_rb/events'
5
+ require 'proxy_rb/event_bus'
6
+ require 'proxy_rb/announcer'
7
+
8
+ module ProxyRb
9
+ # Runtime of proxy_rb
10
+ #
11
+ # Most methods are considered private. Please look for `(private)` in the
12
+ # attribute descriptions. Only a few like `#current_directory`,
13
+ # '#root_directory` and `#config` are considered to be part of the public
14
+ # API.
15
+ class Runtime
16
+ # @!attribute [r] config
17
+ # Access configuration of proxy_rb
18
+ #
19
+ # @!attribute [r] announcer
20
+ # Announce information
21
+ #
22
+ # @!attribute [r] event_bus
23
+ # Handle events (private)
24
+ #
25
+ attr_accessor :config, :announcer, :event_bus
26
+
27
+ def initialize(opts = {})
28
+ @event_bus = EventBus.new(EventBus::NameResolver.new(ProxyRb::Events))
29
+ @announcer = opts.fetch(:announcer, ProxyRb::Announcer.new)
30
+ @config = opts.fetch(:config, ConfigurationWrapper.new(ProxyRb.config.make_copy, @event_bus))
31
+
32
+ @setup_done = false
33
+ end
34
+
35
+ # @private
36
+ #
37
+ # Setup of proxy_rb is finshed. Should be used only internally.
38
+ def setup_done
39
+ @setup_done = true
40
+ end
41
+
42
+ # @private
43
+ #
44
+ # Has proxy_rb already been setup. Should be used only internally.
45
+ def setup_already_done?
46
+ @setup_done == true
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ # Proxy Rb
3
+ module ProxyRb
4
+ # Setup proxy rb
5
+ class Setup
6
+ private
7
+
8
+ attr_reader :runtime
9
+
10
+ public
11
+
12
+ def initialize(runtime)
13
+ @runtime = runtime
14
+ end
15
+
16
+ def call
17
+ return if runtime.setup_already_done?
18
+
19
+ events
20
+
21
+ runtime.setup_done
22
+
23
+ self
24
+ end
25
+
26
+ private
27
+
28
+ # disable Metrics/MethodLength
29
+ def events
30
+ runtime.event_bus.register(
31
+ :proxy_set,
32
+ proc do |event|
33
+ runtime.announcer.announce :proxy, event.entity
34
+ end
35
+ )
36
+
37
+ runtime.event_bus.register(
38
+ :proxy_user_set,
39
+ proc do |event|
40
+ runtime.announcer.announce :proxy_user, event.entity
41
+ end
42
+ )
43
+
44
+ runtime.event_bus.register(
45
+ :resource_set,
46
+ proc do |event|
47
+ runtime.announcer.announce :resource, event.entity
48
+ end
49
+ )
50
+
51
+ runtime.event_bus.register(
52
+ :resource_user_set,
53
+ proc do |event|
54
+ runtime.announcer.announce :resource_user, event.entity
55
+ end
56
+ )
57
+ end
58
+ # enable Metrics/MethodLength
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  # Main Module
3
3
  module ProxyRb
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
data/proxy_rb.gemspec CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.version = ProxyRb::VERSION
10
10
  spec.authors = ['Max Meyer']
11
11
  spec.email = ['dev@fedux.org']
12
+ spec.licenses = ['MIT']
12
13
 
13
14
  spec.summary = 'This gem makes testing your proxy easy.'
14
15
  spec.homepage = 'https://github.com/fedux-org/proxy_rb'
@@ -19,7 +20,6 @@ Gem::Specification.new do |spec|
19
20
  spec.require_paths = ['lib']
20
21
 
21
22
  spec.add_development_dependency 'bundler', '~> 1.9'
22
- spec.add_development_dependency 'rake', '~> 10.0'
23
23
 
24
24
  spec.add_runtime_dependency 'capybara'
25
25
  spec.add_runtime_dependency 'capybara-webkit'
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_runtime_dependency 'contracts'
29
29
  spec.add_runtime_dependency 'excon'
30
30
 
31
- spec.add_runtime_dependency 'rspec'
31
+ spec.add_runtime_dependency 'rspec', '~> 3.3'
32
32
 
33
33
  spec.required_ruby_version = '~> 2.3'
34
34
  end