whisperer 0.0.1

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