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.
Files changed (88) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +293 -0
  8. data/Rakefile +1 -0
  9. data/TODO.md +47 -0
  10. data/lib/whisperer.rb +102 -0
  11. data/lib/whisperer/config.rb +40 -0
  12. data/lib/whisperer/convertors/hash.rb +39 -0
  13. data/lib/whisperer/convertors/interaction.rb +21 -0
  14. data/lib/whisperer/dsl.rb +19 -0
  15. data/lib/whisperer/dsl/base.rb +47 -0
  16. data/lib/whisperer/dsl/body.rb +33 -0
  17. data/lib/whisperer/dsl/headers.rb +20 -0
  18. data/lib/whisperer/dsl/request.rb +15 -0
  19. data/lib/whisperer/dsl/response.rb +15 -0
  20. data/lib/whisperer/dsl/response/status.rb +10 -0
  21. data/lib/whisperer/generator.rb +43 -0
  22. data/lib/whisperer/helpers.rb +16 -0
  23. data/lib/whisperer/placeholder.rb +14 -0
  24. data/lib/whisperer/preprocessors.rb +19 -0
  25. data/lib/whisperer/preprocessors/base.rb +13 -0
  26. data/lib/whisperer/preprocessors/content_length.rb +17 -0
  27. data/lib/whisperer/preprocessors/response_body.rb +23 -0
  28. data/lib/whisperer/record.rb +48 -0
  29. data/lib/whisperer/record/body.rb +15 -0
  30. data/lib/whisperer/record/headers.rb +22 -0
  31. data/lib/whisperer/record/request.rb +16 -0
  32. data/lib/whisperer/record/response.rb +18 -0
  33. data/lib/whisperer/record/response/status.rb +10 -0
  34. data/lib/whisperer/samples/cassette_builder.rb +24 -0
  35. data/lib/whisperer/serializers/base.rb +24 -0
  36. data/lib/whisperer/serializers/json.rb +33 -0
  37. data/lib/whisperer/serializers/json_multiple.rb +14 -0
  38. data/lib/whisperer/tasks/whisperer.rake +88 -0
  39. data/lib/whisperer/version.rb +3 -0
  40. data/spec/cassette_builders/arya_stark.rb +26 -0
  41. data/spec/cassette_builders/bran_stark.rb +19 -0
  42. data/spec/cassette_builders/empty_robb_stark.rb +20 -0
  43. data/spec/cassette_builders/robb_stark.rb +30 -0
  44. data/spec/cassette_builders/robb_stark_without_content_length.rb +20 -0
  45. data/spec/cassette_builders/sansa_stark.rb +9 -0
  46. data/spec/cassette_builders/starks.rb +31 -0
  47. data/spec/cassette_builders/wolfs.rb +7 -0
  48. data/spec/cassettes/empty_robb_stark.yml +22 -0
  49. data/spec/cassettes/girls/arya_stark.yml +24 -0
  50. data/spec/cassettes/robb_stark.yml +28 -0
  51. data/spec/cassettes/robb_stark_without_content_length.yml +22 -0
  52. data/spec/cassettes/sansa_stark.yml +24 -0
  53. data/spec/cassettes/starks.yml +28 -0
  54. data/spec/cassettes/wolfs.yml +28 -0
  55. data/spec/factories/arya_stark.rb +7 -0
  56. data/spec/factories/bran_stark.rb +7 -0
  57. data/spec/factories/ned_stark.rb +7 -0
  58. data/spec/factories/robb_stark.rb +7 -0
  59. data/spec/factories/sansa_stark.rb +7 -0
  60. data/spec/integration/whisperer_spec.rb +51 -0
  61. data/spec/spec_helper.rb +25 -0
  62. data/spec/spec_integration_helper.rb +6 -0
  63. data/spec/support/cassettes.rb +16 -0
  64. data/spec/support/custom_serializer.rb +5 -0
  65. data/spec/unit/config_spec.rb +94 -0
  66. data/spec/unit/convertors/hash_spec.rb +59 -0
  67. data/spec/unit/convertors/interaction_spec.rb +46 -0
  68. data/spec/unit/dsl/base_spec.rb +99 -0
  69. data/spec/unit/dsl/body_spec.rb +73 -0
  70. data/spec/unit/dsl/headers_spec.rb +31 -0
  71. data/spec/unit/dsl/request_spec.rb +4 -0
  72. data/spec/unit/dsl/response_spec.rb +4 -0
  73. data/spec/unit/dsl/status_spec.rb +4 -0
  74. data/spec/unit/dsl_spec.rb +4 -0
  75. data/spec/unit/generator_spec.rb +77 -0
  76. data/spec/unit/helpers_spec.rb +38 -0
  77. data/spec/unit/preprocessors/content_length_spec.rb +39 -0
  78. data/spec/unit/preprocessors/response_body_spec.rb +55 -0
  79. data/spec/unit/preprocessors_spec.rb +8 -0
  80. data/spec/unit/record/headers_spec.rb +21 -0
  81. data/spec/unit/record/response_spec.rb +11 -0
  82. data/spec/unit/record_spec.rb +77 -0
  83. data/spec/unit/serializers/base_spec.rb +19 -0
  84. data/spec/unit/serializers/json_multiple_spec.rb +24 -0
  85. data/spec/unit/serializers/json_spec.rb +37 -0
  86. data/spec/unit/whisperer_spec.rb +189 -0
  87. data/whisperer.gemspec +28 -0
  88. metadata +277 -0
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Preprocessors::ContentLength do
4
+ describe '#process' do
5
+ subject { described_class.new(record) }
6
+
7
+ context 'when a content length for a response is defined' do
8
+ let(:record) {
9
+ r = Whisperer::Record.new
10
+ r.response.headers.content_length = '10'
11
+ r
12
+ }
13
+
14
+ it 'record has a unchanged content length' do
15
+ subject.process
16
+
17
+ expect(record.response.headers.content_length).to eq('10')
18
+ end
19
+ end
20
+
21
+ context 'when a content length for a response is not defined' do
22
+ let(:record) {
23
+ Whisperer::Record.new(
24
+ response: {
25
+ body: {
26
+ string: 'test'
27
+ }
28
+ }
29
+ )
30
+ }
31
+
32
+ it 'measures size of body and writes it to the content length header of the response' do
33
+ subject.process
34
+
35
+ expect(record.response.headers.content_length).to eq('4')
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Preprocessors::ResponseBody do
4
+ describe '#process' do
5
+ subject { described_class.new(record) }
6
+
7
+ context 'when there is not data object' do
8
+ let(:record) { Whisperer::Record.new }
9
+
10
+ it 'does not serialize anything' do
11
+ expect(Whisperer).to_not receive(:serializer)
12
+
13
+ subject.process
14
+ end
15
+ end
16
+
17
+ context 'when there is data object' do
18
+ let(:serialized_data) { 'serialized data' }
19
+ let(:serializer) { double('Serializer', serialize: true) }
20
+
21
+ let(:data_obj) { OpenStruct.new(test: 'obj') }
22
+
23
+ let(:record) {
24
+ r = Whisperer::Record.new
25
+ r.response.body.data_obj = data_obj
26
+ r.response.body.serializer = :json
27
+ r.response.body.serializer_opts = {some: 'options'}
28
+ r
29
+ }
30
+
31
+ before do
32
+ allow(Whisperer).to receive(:serializer).and_return(serializer)
33
+ allow(serializer).to receive(:serialize).and_return(serialized_data)
34
+ end
35
+
36
+ it 'gets the serializer' do
37
+ expect(Whisperer).to receive(:serializer).with(:json)
38
+
39
+ subject.process
40
+ end
41
+
42
+ it 'serializes the respose body' do
43
+ expect(serializer).to receive(:serialize).with(data_obj, {some: 'options'})
44
+
45
+ subject.process
46
+ end
47
+
48
+ it 'assigns the serialized data to the record' do
49
+ subject.process
50
+
51
+ expect(record.response.body.string).to eq(serialized_data)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Preprocessors do
4
+ describe '.process' do
5
+ it 'processes the container with A processor'
6
+ it 'processes the container with B processor'
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Headers do
4
+ describe '.to_hash' do
5
+ subject {
6
+ obj = described_class.new()
7
+
8
+ obj.attribute(:content_type, String)
9
+ obj.attributes = {
10
+ content_type: 'json'
11
+ }
12
+ obj
13
+ }
14
+
15
+ it 'returns a hash with correct keys' do
16
+ expect(subject.to_hash).to eq(
17
+ 'Content-Type' => 'json'
18
+ )
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Response do
4
+ describe '.headers' do
5
+ subject { described_class.new }
6
+
7
+ it 'has a content length field' do
8
+ expect(subject.headers).to respond_to(:content_length)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Record do
4
+ describe '#merge!' do
5
+ let(:record) {
6
+ r = Whisperer::Record.new(
7
+ request: {
8
+ uri: 'http://google.com',
9
+ },
10
+ response: {
11
+ body: {
12
+ encoding: 'UTF-8',
13
+ string: 'test'
14
+ }
15
+ },
16
+ recorded_at: 'test data'
17
+ )
18
+
19
+ r.request.headers.attribute(:content_length, Integer)
20
+ r.request.headers.attribute(:accept, String)
21
+
22
+ r.request.headers.content_length = 100
23
+ r.request.headers.accept = 'javascript'
24
+ r
25
+ }
26
+
27
+ let(:another_record) {
28
+ r = Whisperer::Record.new(
29
+ request: {
30
+ headers: {
31
+ content_length: 50
32
+ }
33
+ },
34
+ response: {
35
+ body: {
36
+ encoding: 'UTF-16'
37
+ }
38
+ }
39
+ )
40
+
41
+ r.request.headers.attribute(:content_length, Integer)
42
+
43
+ r.request.headers.content_length = 50
44
+ r
45
+ }
46
+
47
+ subject { another_record }
48
+
49
+ before do
50
+ subject.merge!(record)
51
+ end
52
+
53
+ it 'has a correct content length header for the request' do
54
+ expect(subject.request.headers.content_length).to eq(50)
55
+ end
56
+
57
+ it 'has an accept header for the request' do
58
+ expect(subject.request.headers.accept).to eq('javascript')
59
+ end
60
+
61
+ it 'has an url' do
62
+ expect(subject.request.uri).to eq('http://google.com')
63
+ end
64
+
65
+ it 'has a correct encoding for the body of the response' do
66
+ expect(subject.response.body.encoding).to eq('UTF-16')
67
+ end
68
+
69
+ it 'has a string for the body of the response' do
70
+ expect(subject.response.body.string).to eq('test')
71
+ end
72
+
73
+ it 'has a correct recorded_at value' do
74
+ expect(subject.recorded_at).to eq('test data')
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Serializers::Base do
4
+ let(:options) { {test: 1} }
5
+
6
+ subject { described_class.new(nil, options: options) }
7
+
8
+ describe '.new' do
9
+ it 'keeps given options' do
10
+ expect(subject.options).to eq(options)
11
+ end
12
+ end
13
+
14
+ describe '#serialize' do
15
+ it 'raises an error about implementation' do
16
+ expect{ subject.serialize }.to raise_error(NotImplementedError)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer::Serializers::JsonMultiple do
4
+ describe '#serialize' do
5
+ let(:attrs) {
6
+ {
7
+ first_name: 'John',
8
+ last_name: 'Snow'
9
+ }
10
+ }
11
+
12
+ let(:data) {
13
+ [
14
+ OpenStruct.new(attrs)
15
+ ]
16
+ }
17
+
18
+ subject { described_class.new(data) }
19
+
20
+ it 'returns json string with a serialized array' do
21
+ expect(subject.serialize).to eq('[{"first_name":"John","last_name":"Snow"}]')
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ class TestChildJson < Whisperer::Serializers::Json
4
+ protected
5
+ def post_prepare_data(data)
6
+ {test: data}
7
+ end
8
+ end
9
+
10
+ describe Whisperer::Serializers::Json do
11
+ describe '#serialize' do
12
+ let(:attrs) {
13
+ {
14
+ first_name: 'John',
15
+ last_name: 'Snow'
16
+ }
17
+ }
18
+
19
+ subject { described_class.new(OpenStruct.new(attrs)) }
20
+
21
+ it 'returns json string with serialized attributes' do
22
+ expect(subject.serialize).to eq('{"first_name":"John","last_name":"Snow"}')
23
+ end
24
+
25
+ context 'when the class is inherited' do
26
+ subject { TestChildJson.new(OpenStruct.new(attrs)) }
27
+
28
+ context 'when the child class alters the data structure' do
29
+ it 'returns the altered structure' do
30
+ expect(subject.serialize).to eq(
31
+ '{"test":{"first_name":"John","last_name":"Snow"}}'
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,189 @@
1
+ require 'spec_helper'
2
+
3
+ describe Whisperer do
4
+ after do
5
+ described_class.cassette_records.clear
6
+ end
7
+
8
+ describe '.define' do
9
+ let(:cassette_record) { instance_double('Whisperer::Record', merge!: true) }
10
+ let(:dsl) { instance_double('Whisperer::Dsl', container: cassette_record) }
11
+
12
+ before do
13
+ allow(Whisperer::Dsl).to receive(:build).and_return(dsl)
14
+ end
15
+
16
+ it 'builds the dsl object' do
17
+ expect(Whisperer::Dsl).to receive(:build)
18
+
19
+ described_class.define(:test) {}
20
+ end
21
+
22
+ it 'executes a given block over the dsl object' do
23
+ expect(dsl).to receive(:request)
24
+
25
+ described_class.define(:test) {
26
+ request
27
+ }
28
+ end
29
+
30
+ it 'stores the generated cassette record' do
31
+ described_class.define(:test) {}
32
+
33
+ expect(Whisperer.cassette_records[:test]).to eq(cassette_record)
34
+ end
35
+
36
+ context 'when a string as a name of the cassette record is given' do
37
+ it 'stores a cassette record with a symbol key' do
38
+ described_class.define('test') {}
39
+
40
+ expect(Whisperer.cassette_records[:test]).to eq(cassette_record)
41
+ end
42
+ end
43
+
44
+ context 'when a parent is defined for a cassette record' do
45
+ context 'when such parent exists' do
46
+ let(:orig_cassette_record) { double('original cassette record') }
47
+
48
+ before do
49
+ Whisperer.cassette_records[:some_parent] = orig_cassette_record
50
+ end
51
+
52
+ it 'merges the original record with the newly built' do
53
+ expect(cassette_record).to receive(:merge!).with(orig_cassette_record)
54
+
55
+ described_class.define('test', parent: :some_parent) {}
56
+ end
57
+ end
58
+
59
+ context 'when such parent does not exist' do
60
+ it 'raises an error' do
61
+ expect {
62
+ described_class.define('test', parent: :some_parent) {}
63
+ }.to raise_error(ArgumentError, 'Parent record "some_parent" is not declared.')
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '.defined_any?' do
70
+ context 'when there are defined cassette records' do
71
+ before do
72
+ described_class.cassette_records[:test] = true
73
+ end
74
+
75
+ it 'returns true' do
76
+ expect(Whisperer.defined_any?).to be_truthy
77
+ end
78
+ end
79
+
80
+ context 'when there are not defined cassette_records' do
81
+ it 'returns false' do
82
+ expect(Whisperer.defined_any?).to be_falsey
83
+ end
84
+ end
85
+ end
86
+
87
+ describe '.generate' do
88
+ context 'when the cassette record with the given name does not exist' do
89
+ it 'raises an error' do
90
+ expect { described_class.generate(:mytest) }.to raise_error(
91
+ Whisperer::NocassetteRecordError,
92
+ 'There is not cassette builder with "mytest" name.'
93
+ )
94
+ end
95
+ end
96
+
97
+ context 'when the cassette with the given name exists' do
98
+ shared_examples 'generator' do |name|
99
+ it 'generates the VCR cassette' do
100
+ expect(Whisperer::Generator).to receive(:generate).with(
101
+ cassette_record,
102
+ :test
103
+ )
104
+
105
+ described_class.generate(name)
106
+ end
107
+ end
108
+
109
+ let(:cassette_record) { double }
110
+
111
+ before do
112
+ described_class.cassette_records[:test] = cassette_record
113
+ end
114
+
115
+ context 'when the given name is a symbol' do
116
+ it_behaves_like 'generator', :test
117
+ end
118
+
119
+ context 'when the given name is a string' do
120
+ it_behaves_like 'generator', 'test'
121
+ end
122
+ end
123
+ end
124
+
125
+ describe '.generate_all' do
126
+ context 'when there are defined cassettes' do
127
+ let(:record1) { double('cassette record 1') }
128
+ let(:record2) { double('cassette record 2') }
129
+
130
+ before do
131
+ Whisperer::cassette_records[:record1] = record1
132
+ Whisperer::cassette_records[:record2] = record2
133
+
134
+ allow(Whisperer).to receive(:defined_any?).and_return(true)
135
+ allow(Whisperer).to receive(:generate)
136
+ end
137
+
138
+ it 'generates the VCR cassette based on record1' do
139
+ expect(Whisperer).to receive(:generate).with(:record1)
140
+
141
+ described_class.generate_all
142
+ end
143
+
144
+ it 'generates the VCR cassette based on record2' do
145
+ expect(Whisperer).to receive(:generate).with(:record2)
146
+
147
+ described_class.generate_all
148
+ end
149
+ end
150
+
151
+ context 'when there are not defined cassette records' do
152
+ before do
153
+ allow(Whisperer).to receive(:defined_any?).and_return(false)
154
+ end
155
+
156
+ it 'raises and error' do
157
+ expect { described_class.generate_all }.to raise_error(
158
+ Whisperer::NocassetteRecordError,
159
+ 'cassette builders are not found.'
160
+ )
161
+ end
162
+ end
163
+ end
164
+
165
+ describe '.serializer' do
166
+ context 'when there is not such serializer' do
167
+ it 'raises an error' do
168
+ expect { described_class.serializer(:mytest) }.to raise_error(
169
+ ArgumentError,
170
+ 'There is not serializer registered with "mytest" name'
171
+ )
172
+ end
173
+ end
174
+
175
+ context 'when there is such serializer' do
176
+ it 'returns the registered class' do
177
+ expect(described_class.serializer(:json)).to eq(Whisperer::Serializers::Json)
178
+ end
179
+ end
180
+ end
181
+
182
+ describe '.register_preprocessor' do
183
+ it 'registers preprocessor' do
184
+ expect(Whisperer::Preprocessors).to receive(:register).with('some name', 'some class')
185
+
186
+ Whisperer.register_preprocessor('some name', 'some class')
187
+ end
188
+ end
189
+ end