http_baseline 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +60 -0
- data/Rakefile +14 -0
- data/cucumber.yml +7 -0
- data/features/step_definitions/generic/debugging_steps.rb +34 -0
- data/features/step_definitions/generic/header_steps.rb +56 -0
- data/features/step_definitions/generic/request_steps.rb +69 -0
- data/features/step_definitions/generic/response_steps.rb +133 -0
- data/features/step_definitions/generic/user_story_steps.rb +11 -0
- data/features/step_definitions/internal_test_steps.rb +42 -0
- data/features/support/env.rb +3 -0
- data/http_baseline.gemspec +36 -0
- data/lib/ext_core/array.rb +10 -0
- data/lib/ext_core/hash.rb +3 -0
- data/lib/ext_core/object.rb +9 -0
- data/lib/ext_core/query.rb +58 -0
- data/lib/ext_core/string.rb +142 -0
- data/lib/http_baseline/adapter/abstract.rb +25 -0
- data/lib/http_baseline/adapter/rest/response/logger.rb +37 -0
- data/lib/http_baseline/adapter/rest.rb +63 -0
- data/lib/http_baseline/evf.rb +21 -0
- data/lib/http_baseline/methods.rb +17 -0
- data/lib/http_baseline/null_broadcaster.rb +21 -0
- data/lib/http_baseline/version.rb +8 -0
- data/lib/http_baseline.rb +67 -0
- data/spec/lib/root_spec.rb +14 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/fixtures.rb +23 -0
- data/spec/support/simplecov_setup.rb +12 -0
- metadata +270 -0
@@ -0,0 +1,142 @@
|
|
1
|
+
class ::String
|
2
|
+
|
3
|
+
unless method_defined? :camelize
|
4
|
+
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
|
5
|
+
# is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
|
6
|
+
#
|
7
|
+
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
|
8
|
+
#
|
9
|
+
# As a rule of thumb you can think of +camelize+ as the inverse of +underscore+,
|
10
|
+
# though there are cases where that does not hold:
|
11
|
+
#
|
12
|
+
# "SSLError".underscore.camelize # => "SslError"
|
13
|
+
#
|
14
|
+
def camelize(first_letter_in_uppercase = true)
|
15
|
+
lower_case_and_underscored_word = self
|
16
|
+
if first_letter_in_uppercase
|
17
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
18
|
+
else
|
19
|
+
lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
unless method_defined? :underscore
|
25
|
+
# Makes an underscored, lowercase form from the expression in the string.
|
26
|
+
#
|
27
|
+
# Changes '::' to '/' to convert namespaces to paths.
|
28
|
+
#
|
29
|
+
# Examples:
|
30
|
+
# "FooBar".underscore # => "foo_bar"
|
31
|
+
# "FooBar::Errors".underscore # => foo_bar/errors
|
32
|
+
#
|
33
|
+
# As a rule of thumb you can think of +underscore+ as the inverse of +camelize+,
|
34
|
+
# though there are cases where that does not hold:
|
35
|
+
#
|
36
|
+
# "SSLError".underscore.camelize # => "SslError"
|
37
|
+
#
|
38
|
+
def underscore()
|
39
|
+
camel_cased_word = self
|
40
|
+
word = camel_cased_word.to_s.dup
|
41
|
+
word.gsub!(/::/, '/')
|
42
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
43
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
44
|
+
word.tr!("-", "_")
|
45
|
+
word.downcase!
|
46
|
+
word
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
unless method_defined? :constantize
|
51
|
+
# Ruby 1.9 introduces an inherit argument for Module#const_get and
|
52
|
+
# #const_defined? and changes their default behavior.
|
53
|
+
if Module.method(:const_get).arity == 1
|
54
|
+
# Tries to find a constant with the name specified in the argument string:
|
55
|
+
#
|
56
|
+
# "Module".constantize # => Module
|
57
|
+
# "Test::Unit".constantize # => Test::Unit
|
58
|
+
#
|
59
|
+
# The name is assumed to be the one of a top-level constant, no matter whether
|
60
|
+
# it starts with "::" or not. No lexical context is taken into account:
|
61
|
+
#
|
62
|
+
# C = 'outside'
|
63
|
+
# module M
|
64
|
+
# C = 'inside'
|
65
|
+
# C # => 'inside'
|
66
|
+
# "C".constantize # => 'outside', same as ::C
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# NameError is raised when the name is not in CamelCase or the constant is
|
70
|
+
# unknown.
|
71
|
+
def constantize()
|
72
|
+
camel_cased_word = self
|
73
|
+
names = camel_cased_word.split('::')
|
74
|
+
names.shift if names.empty? || names.first.empty?
|
75
|
+
|
76
|
+
constant = Object
|
77
|
+
names.each do |name|
|
78
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
79
|
+
end
|
80
|
+
constant
|
81
|
+
end
|
82
|
+
else
|
83
|
+
def constantize() #:nodoc:
|
84
|
+
camel_cased_word = self
|
85
|
+
names = camel_cased_word.split('::')
|
86
|
+
names.shift if names.empty? || names.first.empty?
|
87
|
+
|
88
|
+
constant = Object
|
89
|
+
names.each do |name|
|
90
|
+
constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
|
91
|
+
end
|
92
|
+
constant
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def squish
|
98
|
+
dup.squish!
|
99
|
+
end
|
100
|
+
|
101
|
+
# Performs a destructive squish. See String#squish.
|
102
|
+
def squish!
|
103
|
+
gsub!(/\A[[:space:]]+/, '')
|
104
|
+
gsub!(/[[:space:]]+\z/, '')
|
105
|
+
gsub!(/[[:space:]]+/, ' ')
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
|
110
|
+
#
|
111
|
+
# 'Once upon a time in a world far far away'.truncate(27)
|
112
|
+
# # => "Once upon a time in a wo..."
|
113
|
+
#
|
114
|
+
# Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
|
115
|
+
#
|
116
|
+
# 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
|
117
|
+
# # => "Once upon a time in a..."
|
118
|
+
#
|
119
|
+
# 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
|
120
|
+
# # => "Once upon a time in a..."
|
121
|
+
#
|
122
|
+
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
|
123
|
+
# for a total length not exceeding <tt>length</tt>:
|
124
|
+
#
|
125
|
+
# 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
|
126
|
+
# # => "And they f... (continued)"
|
127
|
+
def truncate(truncate_at, options = {})
|
128
|
+
return dup unless length > truncate_at
|
129
|
+
|
130
|
+
options[:omission] ||= '...'
|
131
|
+
length_with_room_for_omission = truncate_at - options[:omission].length
|
132
|
+
stop = \
|
133
|
+
if options[:separator]
|
134
|
+
rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
|
135
|
+
else
|
136
|
+
length_with_room_for_omission
|
137
|
+
end
|
138
|
+
|
139
|
+
"#{self[0...stop]}#{options[:omission]}"
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module HttpBaseline
|
5
|
+
module Adapter
|
6
|
+
class Abstract
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
@options = { :ssl => @config.ssl.enabled.true?, :ssl_options => { :verify => @config.ssl.verify } }
|
11
|
+
@protocol = @config.ssl.enabled.true? ? 'https' : 'http'
|
12
|
+
@uri = URI.parse("#{@protocol}://#{@config.domain}:#{@config.tcp_port}")
|
13
|
+
end
|
14
|
+
|
15
|
+
def ssl?
|
16
|
+
@uri.scheme == 'https'
|
17
|
+
end
|
18
|
+
|
19
|
+
def headers
|
20
|
+
@client.headers
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module HttpBaseline
|
2
|
+
module Adapter
|
3
|
+
class Rest
|
4
|
+
module Response
|
5
|
+
class Logger < Faraday::Response::Middleware
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def initialize(app, logger = nil)
|
9
|
+
super(app)
|
10
|
+
@logger = logger || HttpBaseline.logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
debug "#{env.method} #{env.url.to_s}"
|
17
|
+
debug('request') { dump_headers env.request_headers }
|
18
|
+
debug('request') { env.body }
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_complete(env)
|
23
|
+
debug('Status') { env.status.to_s }
|
24
|
+
debug('response') { dump_headers env.response_headers }
|
25
|
+
debug('response') { env.body }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def dump_headers(headers)
|
31
|
+
headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module HttpBaseline
|
2
|
+
module Adapter
|
3
|
+
class Rest < Abstract
|
4
|
+
require 'faraday'
|
5
|
+
require 'faraday/request/multipart'
|
6
|
+
require 'faraday_middleware'
|
7
|
+
require 'http_baseline/adapter/rest/response/logger'
|
8
|
+
|
9
|
+
attr_reader :uri
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
super
|
13
|
+
@client = Faraday.new do |pipe|
|
14
|
+
pipe.use Faraday::Request::UrlEncoded
|
15
|
+
pipe.use FaradayMiddleware::EncodeJson
|
16
|
+
pipe.use FaradayMiddleware::FollowRedirects
|
17
|
+
pipe.use FaradayMiddleware::Mashify
|
18
|
+
pipe.use Response::Logger
|
19
|
+
pipe.url_prefix = @uri
|
20
|
+
end
|
21
|
+
headers[:user_agent] = 'WS v%s' % HttpBaseline::VERSION
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def attach_extension(other_module)
|
26
|
+
@client.use other_module
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def get(url, *args)
|
31
|
+
@client.get(configured_path(url), *args)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def post(url, body = nil, *args)
|
36
|
+
@client.post(configured_path(url), body, *args)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def delete(url, *args)
|
41
|
+
@client.delete(configured_path(url), *args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def put(url, body = nil, *args)
|
45
|
+
@client.put(configured_path(url), body, *args)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def configured_path(url)
|
51
|
+
@config.path_prefix.to_s + url
|
52
|
+
end
|
53
|
+
|
54
|
+
def reset_config
|
55
|
+
@client.url_prefix = @uri.to_s
|
56
|
+
if @options[:ssl_options]
|
57
|
+
@client.ssl.merge!(@options[:ssl_options])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HttpBaseline
|
2
|
+
class Abstract < ::Evf::Abstract
|
3
|
+
|
4
|
+
config.comm = Evf::Support::Options.new unless config.respond_to?(:comm)
|
5
|
+
config.comm.http = Evf::Support::Options.new
|
6
|
+
config.comm.http.ssl = Evf::Support::Options.new
|
7
|
+
config.comm.http.ssl.enabled = 'no'
|
8
|
+
|
9
|
+
invocation 'init.http.config', :before => :load_context_config, group => :all do |env|
|
10
|
+
HttpBaseline.config = env.config
|
11
|
+
HttpBaseline.logger = env.config.logger
|
12
|
+
HttpBaseline.broadcaster = env.broadcaster
|
13
|
+
|
14
|
+
%w(debugging header request response user_story).each do |definition|
|
15
|
+
require HttpBaseline::SHARED_DEFINITIONS.join('%s_steps' % definition)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module HttpBaseline
|
2
|
+
module Methods
|
3
|
+
|
4
|
+
def set_headers_by(c_type)
|
5
|
+
type = case c_type
|
6
|
+
when /json/i
|
7
|
+
'application/json'
|
8
|
+
when /form/i
|
9
|
+
'application/x-www-form-urlencoded'
|
10
|
+
else
|
11
|
+
c_type
|
12
|
+
end
|
13
|
+
connection.add_header 'Content-Type', type unless c_type.nil? || c_type.empty?
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HttpBaseline
|
2
|
+
class NullBroadcaster
|
3
|
+
|
4
|
+
def initialize(logger)
|
5
|
+
@logger = logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def notify_all_with(object, notification_type, *args)
|
9
|
+
@logger.debug '[%s]: %s -> accepted :%s with %s' % [uname, object.class.name, notification_type, args.join(', ')]
|
10
|
+
end
|
11
|
+
|
12
|
+
def uname
|
13
|
+
@uname ||= self.class.name.split('::').last
|
14
|
+
end
|
15
|
+
|
16
|
+
def subscribe(other)
|
17
|
+
(@null_storage ||= []) << other
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
$:.unshift File.expand_path '../', __FILE__
|
2
|
+
require 'http_baseline/version'
|
3
|
+
require 'base64'
|
4
|
+
require 'bigdecimal'
|
5
|
+
require 'cgi'
|
6
|
+
require 'date'
|
7
|
+
require 'digest/sha1'
|
8
|
+
require 'enumerator'
|
9
|
+
require 'forwardable'
|
10
|
+
require 'net/http'
|
11
|
+
require 'net/https'
|
12
|
+
require 'openssl'
|
13
|
+
require 'stringio'
|
14
|
+
require 'time'
|
15
|
+
require 'zlib'
|
16
|
+
require 'builder'
|
17
|
+
require 'json'
|
18
|
+
require 'jsonpath'
|
19
|
+
require 'logger'
|
20
|
+
require 'addressable/uri'
|
21
|
+
require 'ext_core/query'
|
22
|
+
require 'ext_core/object'
|
23
|
+
require 'ext_core/array'
|
24
|
+
require 'ext_core/hash'
|
25
|
+
require 'ext_core/string'
|
26
|
+
require 'hashie'
|
27
|
+
|
28
|
+
module HttpBaseline
|
29
|
+
SHARED_DEFINITIONS = Pathname(__FILE__).join('..', '..', 'features', 'step_definitions', 'generic')
|
30
|
+
|
31
|
+
autoload :Methods, 'http_baseline/methods'
|
32
|
+
autoload :NullBroadcaster, 'http_baseline/null_broadcaster'
|
33
|
+
|
34
|
+
module Adapter
|
35
|
+
autoload :Abstract, 'http_baseline/adapter/abstract'
|
36
|
+
autoload :Rest, 'http_baseline/adapter/rest'
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
attr_writer :config
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.config
|
44
|
+
@config ||= Hashie::Mash.new
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.logger
|
48
|
+
@logger ||= begin
|
49
|
+
logger = ::Logger.new $stdout
|
50
|
+
logger.level = ::Logger::DEBUG
|
51
|
+
logger
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.logger=(val)
|
56
|
+
@logger = val
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.broadcaster
|
60
|
+
@broadcaster ||= NullBroadcaster.new(self.logger)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.broadcaster=(other_bundle)
|
64
|
+
@broadcaster = other_bundle
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
$:.unshift File.expand_path('../', File.dirname(__FILE__))
|
5
|
+
|
6
|
+
require 'http_baseline'
|
7
|
+
|
8
|
+
Dir[File.expand_path('support/**/*.rb', File.dirname(__FILE__))].each do |file|
|
9
|
+
require file if File.file?(file)
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.color = true
|
14
|
+
config.formatter = :documentation
|
15
|
+
config.include Fixtures
|
16
|
+
end
|
17
|
+
|
18
|
+
include Fixtures
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Fixtures
|
4
|
+
def fixture_path(name)
|
5
|
+
File.join '../fixtures', name
|
6
|
+
end
|
7
|
+
|
8
|
+
def absolute_fixture_path(name)
|
9
|
+
File.expand_path fixture_path(name), File.dirname(__FILE__)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fixture(name)
|
13
|
+
File.read absolute_fixture_path(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def binary_fixture(name)
|
17
|
+
File.open(absolute_fixture_path(name), "rb") { |f| f.read }
|
18
|
+
end
|
19
|
+
|
20
|
+
def fixtures_path
|
21
|
+
Pathname(absolute_fixture_path '')
|
22
|
+
end
|
23
|
+
end
|