whisperer 0.0.1
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.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +13 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +293 -0
- data/Rakefile +1 -0
- data/TODO.md +47 -0
- data/lib/whisperer.rb +102 -0
- data/lib/whisperer/config.rb +40 -0
- data/lib/whisperer/convertors/hash.rb +39 -0
- data/lib/whisperer/convertors/interaction.rb +21 -0
- data/lib/whisperer/dsl.rb +19 -0
- data/lib/whisperer/dsl/base.rb +47 -0
- data/lib/whisperer/dsl/body.rb +33 -0
- data/lib/whisperer/dsl/headers.rb +20 -0
- data/lib/whisperer/dsl/request.rb +15 -0
- data/lib/whisperer/dsl/response.rb +15 -0
- data/lib/whisperer/dsl/response/status.rb +10 -0
- data/lib/whisperer/generator.rb +43 -0
- data/lib/whisperer/helpers.rb +16 -0
- data/lib/whisperer/placeholder.rb +14 -0
- data/lib/whisperer/preprocessors.rb +19 -0
- data/lib/whisperer/preprocessors/base.rb +13 -0
- data/lib/whisperer/preprocessors/content_length.rb +17 -0
- data/lib/whisperer/preprocessors/response_body.rb +23 -0
- data/lib/whisperer/record.rb +48 -0
- data/lib/whisperer/record/body.rb +15 -0
- data/lib/whisperer/record/headers.rb +22 -0
- data/lib/whisperer/record/request.rb +16 -0
- data/lib/whisperer/record/response.rb +18 -0
- data/lib/whisperer/record/response/status.rb +10 -0
- data/lib/whisperer/samples/cassette_builder.rb +24 -0
- data/lib/whisperer/serializers/base.rb +24 -0
- data/lib/whisperer/serializers/json.rb +33 -0
- data/lib/whisperer/serializers/json_multiple.rb +14 -0
- data/lib/whisperer/tasks/whisperer.rake +88 -0
- data/lib/whisperer/version.rb +3 -0
- data/spec/cassette_builders/arya_stark.rb +26 -0
- data/spec/cassette_builders/bran_stark.rb +19 -0
- data/spec/cassette_builders/empty_robb_stark.rb +20 -0
- data/spec/cassette_builders/robb_stark.rb +30 -0
- data/spec/cassette_builders/robb_stark_without_content_length.rb +20 -0
- data/spec/cassette_builders/sansa_stark.rb +9 -0
- data/spec/cassette_builders/starks.rb +31 -0
- data/spec/cassette_builders/wolfs.rb +7 -0
- data/spec/cassettes/empty_robb_stark.yml +22 -0
- data/spec/cassettes/girls/arya_stark.yml +24 -0
- data/spec/cassettes/robb_stark.yml +28 -0
- data/spec/cassettes/robb_stark_without_content_length.yml +22 -0
- data/spec/cassettes/sansa_stark.yml +24 -0
- data/spec/cassettes/starks.yml +28 -0
- data/spec/cassettes/wolfs.yml +28 -0
- data/spec/factories/arya_stark.rb +7 -0
- data/spec/factories/bran_stark.rb +7 -0
- data/spec/factories/ned_stark.rb +7 -0
- data/spec/factories/robb_stark.rb +7 -0
- data/spec/factories/sansa_stark.rb +7 -0
- data/spec/integration/whisperer_spec.rb +51 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/spec_integration_helper.rb +6 -0
- data/spec/support/cassettes.rb +16 -0
- data/spec/support/custom_serializer.rb +5 -0
- data/spec/unit/config_spec.rb +94 -0
- data/spec/unit/convertors/hash_spec.rb +59 -0
- data/spec/unit/convertors/interaction_spec.rb +46 -0
- data/spec/unit/dsl/base_spec.rb +99 -0
- data/spec/unit/dsl/body_spec.rb +73 -0
- data/spec/unit/dsl/headers_spec.rb +31 -0
- data/spec/unit/dsl/request_spec.rb +4 -0
- data/spec/unit/dsl/response_spec.rb +4 -0
- data/spec/unit/dsl/status_spec.rb +4 -0
- data/spec/unit/dsl_spec.rb +4 -0
- data/spec/unit/generator_spec.rb +77 -0
- data/spec/unit/helpers_spec.rb +38 -0
- data/spec/unit/preprocessors/content_length_spec.rb +39 -0
- data/spec/unit/preprocessors/response_body_spec.rb +55 -0
- data/spec/unit/preprocessors_spec.rb +8 -0
- data/spec/unit/record/headers_spec.rb +21 -0
- data/spec/unit/record/response_spec.rb +11 -0
- data/spec/unit/record_spec.rb +77 -0
- data/spec/unit/serializers/base_spec.rb +19 -0
- data/spec/unit/serializers/json_multiple_spec.rb +24 -0
- data/spec/unit/serializers/json_spec.rb +37 -0
- data/spec/unit/whisperer_spec.rb +189 -0
- data/whisperer.gemspec +28 -0
- metadata +277 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module Whisperer
|
2
|
+
# This class is used for request and response parts of HTTP
|
3
|
+
# interactions, it should include only common attributes and methods.
|
4
|
+
class Body
|
5
|
+
include Virtus.model
|
6
|
+
|
7
|
+
attribute :encoding, String
|
8
|
+
attribute :string, String
|
9
|
+
|
10
|
+
# Attributes which are not part of Vcr response
|
11
|
+
attribute :data_obj, Object
|
12
|
+
attribute :serializer, Symbol, default: proc { :json }
|
13
|
+
attribute :serializer_opts, Hash, default: {}
|
14
|
+
end # class Body
|
15
|
+
end # module Whisperer
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Whisperer
|
2
|
+
class Headers
|
3
|
+
include Virtus.model
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
extend Virtus.model
|
7
|
+
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_hash
|
12
|
+
prepared_attrs, attrs = {}, super
|
13
|
+
|
14
|
+
attrs.each do |key, val|
|
15
|
+
key = key.to_s.titleize.split(' ').join('-')
|
16
|
+
prepared_attrs[key] = val
|
17
|
+
end
|
18
|
+
|
19
|
+
prepared_attrs
|
20
|
+
end
|
21
|
+
end # class Header
|
22
|
+
end # module Whisperer
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative 'headers'
|
2
|
+
require_relative 'body'
|
3
|
+
|
4
|
+
module Whisperer
|
5
|
+
class Request
|
6
|
+
include Virtus.model
|
7
|
+
|
8
|
+
attribute :uri, String
|
9
|
+
attribute :method, Symbol
|
10
|
+
attribute :headers, Whisperer::Headers, default: proc {
|
11
|
+
Whisperer::Headers.new
|
12
|
+
}
|
13
|
+
|
14
|
+
attribute :body, Body, default: proc { Body.new }
|
15
|
+
end # class Request
|
16
|
+
end # module Whisperer
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'headers'
|
2
|
+
require_relative 'body'
|
3
|
+
require_relative 'response/status'
|
4
|
+
|
5
|
+
module Whisperer
|
6
|
+
class Response
|
7
|
+
include Virtus.model
|
8
|
+
|
9
|
+
attribute :headers, Whisperer::Headers, default: proc {
|
10
|
+
header = Whisperer::Headers.new
|
11
|
+
header.attribute(:content_length, String)
|
12
|
+
header
|
13
|
+
}
|
14
|
+
|
15
|
+
attribute :body, Body, default: proc { Body.new }
|
16
|
+
attribute :status, Status, default: proc { Status.new }
|
17
|
+
end # class Response
|
18
|
+
end # module Whisperer
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Whisperer.define(:my_fixture_builder) do
|
2
|
+
request do
|
3
|
+
uri 'http://example.com/users/1'
|
4
|
+
method :get
|
5
|
+
end
|
6
|
+
|
7
|
+
response do
|
8
|
+
status do
|
9
|
+
code 200
|
10
|
+
message 'OK'
|
11
|
+
end
|
12
|
+
|
13
|
+
headers do
|
14
|
+
content_type 'application/json;charset=utf-8'
|
15
|
+
end
|
16
|
+
|
17
|
+
body do
|
18
|
+
encoding 'UTF-8'
|
19
|
+
factory 'my_factory', :json
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
recorded_at Time.new
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
module Whisperer
|
6
|
+
module Serializers
|
7
|
+
class Base
|
8
|
+
extend Helpers
|
9
|
+
|
10
|
+
add_builder :serialize
|
11
|
+
|
12
|
+
attr_reader :options
|
13
|
+
|
14
|
+
def initialize(obj, options: {})
|
15
|
+
@obj = obj
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def serialize
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
end # class Base
|
23
|
+
end # module Serializers
|
24
|
+
end # module Whisperer
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
require_relative 'base'
|
3
|
+
|
4
|
+
module Whisperer
|
5
|
+
module Serializers
|
6
|
+
class Json < Base
|
7
|
+
def initialize(obj, options: {}, json_dumper: MultiJson)
|
8
|
+
super obj, options: options
|
9
|
+
|
10
|
+
@json_dumper = json_dumper
|
11
|
+
end
|
12
|
+
|
13
|
+
def serialize
|
14
|
+
data = prepare_data
|
15
|
+
data = post_prepare_data(data)
|
16
|
+
|
17
|
+
@json_dumper.dump(data)
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
def prepare_data
|
22
|
+
@obj.marshal_dump
|
23
|
+
end
|
24
|
+
|
25
|
+
# This method returns give data as it is.
|
26
|
+
# The purpose of this method is to give a way in child classes
|
27
|
+
# to alter data structure before converting data.
|
28
|
+
def post_prepare_data(data)
|
29
|
+
data
|
30
|
+
end
|
31
|
+
end # class Json
|
32
|
+
end # module Serializers
|
33
|
+
end # module Whisperer
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'json'
|
2
|
+
|
3
|
+
module Whisperer
|
4
|
+
module Serializers
|
5
|
+
class JsonMultiple < Json
|
6
|
+
protected
|
7
|
+
def prepare_data
|
8
|
+
@obj.map do |item|
|
9
|
+
item.marshal_dump
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end # class JsonMultiple
|
13
|
+
end # module Serializers
|
14
|
+
end # module Whisperer
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'whisperer'
|
2
|
+
|
3
|
+
require 'active_support/core_ext/hash/deep_merge'
|
4
|
+
require 'factory_girl'
|
5
|
+
require 'rainbow'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
config = Whisperer::Config.load('.whisperer.yml')
|
9
|
+
|
10
|
+
Dir[
|
11
|
+
config.factories_matcher,
|
12
|
+
config.builders_matcher
|
13
|
+
].each {|f| require f }
|
14
|
+
|
15
|
+
namespace :whisperer do
|
16
|
+
desc 'Creates minimal structure of directories, creates a config file with default options'
|
17
|
+
task install: ['config:create'] do
|
18
|
+
path_to_builders = 'spec/cassette_builders'
|
19
|
+
|
20
|
+
if Dir.exists?(path_to_builders)
|
21
|
+
puts Rainbow("Skipped creating of #{path_to_builders} since it already exists").green
|
22
|
+
else
|
23
|
+
Dir.mkdir(path_to_builders)
|
24
|
+
|
25
|
+
puts Rainbow("Created directory for cassette builders: #{path_to_builders}").green
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :config do
|
30
|
+
desc 'Creates a config file with default options'
|
31
|
+
task :create do
|
32
|
+
if File.exists?('.whisperer.yml')
|
33
|
+
puts Rainbow("Skipped creating the sample of config (.whisperer.yml) since it already exists").green
|
34
|
+
else
|
35
|
+
File.open(
|
36
|
+
'.whisperer.yml',
|
37
|
+
File::CREAT|File::RDWR,
|
38
|
+
0644
|
39
|
+
) do |f|
|
40
|
+
f.write(config.to_yml)
|
41
|
+
|
42
|
+
f.close
|
43
|
+
end
|
44
|
+
|
45
|
+
puts Rainbow("Created the sample of config: .whisperer.yml").green
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
namespace :cassettes do
|
51
|
+
desc 'Takes all cassette builders and generates cassettes for VCR'
|
52
|
+
task :generate_all do
|
53
|
+
begin
|
54
|
+
Whisperer.generate_all
|
55
|
+
|
56
|
+
puts Rainbow('cassettes are generated').green
|
57
|
+
rescue Whisperer::NocassetteRecordError => error
|
58
|
+
puts Rainbow("Any cassette builder was found. Please, make sure you define at least one (We are looking for it like: #{config.builders_matcher}).").yellow
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'Takes a specific cassette builder and generates one specific cassette for VCR'
|
63
|
+
task :generate, :name do |t, args|
|
64
|
+
name = args[:name]
|
65
|
+
|
66
|
+
begin
|
67
|
+
Whisperer::generate(name)
|
68
|
+
|
69
|
+
puts Rainbow("The cassette '#{name}' is generated").green
|
70
|
+
rescue Whisperer::NocassetteRecordError => error
|
71
|
+
puts Rainbow(error.message).red
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
namespace :builders do
|
76
|
+
desc 'Creates a sample of the cassette builder'
|
77
|
+
task :sample do
|
78
|
+
sample = File.join(File.dirname(__FILE__), '../samples/cassette_builder.rb')
|
79
|
+
|
80
|
+
path_to_save = config.path_to_builders + '/sample.rb'
|
81
|
+
|
82
|
+
FileUtils.cp(sample, path_to_save)
|
83
|
+
|
84
|
+
puts Rainbow("Created the sample of the cassette builder: #{path_to_save}").green
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
Whisperer.define(:arya_stark) do
|
2
|
+
request do
|
3
|
+
uri 'http://example.com/users/1'
|
4
|
+
method :get
|
5
|
+
end
|
6
|
+
|
7
|
+
response do
|
8
|
+
status do
|
9
|
+
code 200
|
10
|
+
message 'OK'
|
11
|
+
end
|
12
|
+
|
13
|
+
headers do
|
14
|
+
content_type 'application/json;charset=utf-8'
|
15
|
+
end
|
16
|
+
|
17
|
+
body do
|
18
|
+
encoding 'UTF-8'
|
19
|
+
factory 'arya_stark'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
recorded_at 'Mon, 13 Jan 2014 21:01:47 GMT'
|
24
|
+
|
25
|
+
sub_path 'girls'
|
26
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Whisperer.define(:bran_stark) do
|
2
|
+
request do
|
3
|
+
uri 'http://example.com/users/2'
|
4
|
+
method :get
|
5
|
+
|
6
|
+
headers do
|
7
|
+
accept '*/*'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
response do
|
12
|
+
body do
|
13
|
+
serializer :custom
|
14
|
+
factory 'bran_stark'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
recorded_at 'Mon, 13 Jan 2014 21:01:47 GMT'
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Whisperer.define(:empty_robb_stark) do
|
2
|
+
request do
|
3
|
+
uri 'http://example.com/users/2'
|
4
|
+
method :get
|
5
|
+
end
|
6
|
+
|
7
|
+
response do
|
8
|
+
status do
|
9
|
+
code 200
|
10
|
+
message 'OK'
|
11
|
+
end
|
12
|
+
|
13
|
+
body do
|
14
|
+
encoding 'UTF-8'
|
15
|
+
string '{"empty":true}'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
recorded_at 'Mon, 13 Jan 2014 21:01:47 GMT'
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Whisperer.define(:robb_stark) do
|
2
|
+
request do
|
3
|
+
uri 'http://example.com/users/1'
|
4
|
+
method :get
|
5
|
+
|
6
|
+
headers do
|
7
|
+
accept '*/*'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
response do
|
12
|
+
status do
|
13
|
+
code 200
|
14
|
+
message 'OK'
|
15
|
+
end
|
16
|
+
|
17
|
+
headers do
|
18
|
+
content_type 'application/json;charset=utf-8'
|
19
|
+
content_length 57
|
20
|
+
x_content_type_options 'nosniff'
|
21
|
+
end
|
22
|
+
|
23
|
+
body do
|
24
|
+
encoding 'UTF-8'
|
25
|
+
factory 'robb_stark'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
recorded_at 'Mon, 13 Jan 2014 21:01:47 GMT'
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Whisperer.define(:robb_stark_without_content_length) do
|
2
|
+
request do
|
3
|
+
uri 'http://example.com/users/2'
|
4
|
+
method :get
|
5
|
+
end
|
6
|
+
|
7
|
+
response do
|
8
|
+
status do
|
9
|
+
code 200
|
10
|
+
message 'OK'
|
11
|
+
end
|
12
|
+
|
13
|
+
body do
|
14
|
+
encoding 'UTF-8'
|
15
|
+
factory 'robb_stark'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
recorded_at 'Mon, 13 Jan 2014 21:01:47 GMT'
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Whisperer.define(:starks) do
|
2
|
+
request do
|
3
|
+
uri 'http://example.com/users'
|
4
|
+
method :get
|
5
|
+
|
6
|
+
headers do
|
7
|
+
accept '*/*'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
response do
|
12
|
+
status do
|
13
|
+
code 200
|
14
|
+
message 'OK'
|
15
|
+
end
|
16
|
+
|
17
|
+
headers do
|
18
|
+
content_type 'application/json;charset=utf-8'
|
19
|
+
content_length 57
|
20
|
+
x_content_type_options 'nosniff'
|
21
|
+
end
|
22
|
+
|
23
|
+
body do
|
24
|
+
encoding 'UTF-8'
|
25
|
+
serializer :json_multiple
|
26
|
+
factories ['robb_stark', 'ned_stark']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
recorded_at 'Mon, 13 Jan 2014 21:01:47 GMT'
|
31
|
+
end
|