proxy_rb 0.4.0 → 0.5.0

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