tcr 0.2.1 → 0.2.2
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 +4 -4
- data/lib/tcr.rb +2 -2
- data/lib/tcr/recordable_tcp_socket.rb +15 -7
- data/lib/tcr/version.rb +1 -1
- data/spec/tcr_spec.rb +106 -74
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c3b335b522930e2cda40cc99bacc68109e13189
|
4
|
+
data.tar.gz: 25d3fe32caf69278fc4753763e1c1ba84640a5c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee2afda4d4a575fee8d988d12a56b1bfe27f30dac317776232fddc019499addec91348d8c3545fbf0cccdfef0c3153b5016f66a21e8767d9e7b345fe1f7f59f9
|
7
|
+
data.tar.gz: 7cc411a8feb6d80c3ee2b4541141d90e0d47845853474a69255a6b0773b683d1b2e417dc7539013adb059c5d5abc94464b4825a2e3948b2ebd212747886dfc98
|
data/lib/tcr.rb
CHANGED
@@ -88,11 +88,11 @@ class Socket
|
|
88
88
|
class << self
|
89
89
|
alias_method :real_tcp, :tcp
|
90
90
|
|
91
|
-
def tcp(host, port, socket_opts)
|
91
|
+
def tcp(host, port, *socket_opts)
|
92
92
|
if TCR.configuration.hook_tcp_ports.include?(port)
|
93
93
|
TCR::RecordableTCPSocket.new(host, port, TCR.cassette)
|
94
94
|
else
|
95
|
-
real_tcp(host, port, socket_opts)
|
95
|
+
real_tcp(host, port, *socket_opts)
|
96
96
|
end
|
97
97
|
end
|
98
98
|
end
|
@@ -5,22 +5,26 @@ require 'thread'
|
|
5
5
|
|
6
6
|
module TCR
|
7
7
|
class RecordableTCPSocket
|
8
|
-
attr_reader :live, :socket
|
9
|
-
attr_accessor :recording
|
8
|
+
attr_reader :live, :socket, :recording
|
10
9
|
|
11
10
|
def initialize(address, port, cassette)
|
12
11
|
raise TCR::NoCassetteError.new unless TCR.cassette
|
13
12
|
|
14
13
|
@read_lock = Queue.new
|
14
|
+
@recording = cassette.next_session
|
15
|
+
@live = cassette.recording?
|
15
16
|
|
16
|
-
if
|
17
|
-
|
18
|
-
|
17
|
+
if live
|
18
|
+
begin
|
19
|
+
@socket = TCPSocket.real_open(address, port)
|
20
|
+
rescue => e
|
21
|
+
recording << ["error", Marshal.dump(e)]
|
22
|
+
raise
|
23
|
+
end
|
19
24
|
else
|
20
|
-
@live = false
|
21
25
|
@closed = false
|
26
|
+
check_recording_for_errors
|
22
27
|
end
|
23
|
-
@recording = cassette.next_session
|
24
28
|
end
|
25
29
|
|
26
30
|
def read(bytes)
|
@@ -75,6 +79,10 @@ module TCR
|
|
75
79
|
|
76
80
|
private
|
77
81
|
|
82
|
+
def check_recording_for_errors
|
83
|
+
raise Marshal.load(recording.first.last) if recording.first.first == "error"
|
84
|
+
end
|
85
|
+
|
78
86
|
def _intercept_socket
|
79
87
|
if @socket
|
80
88
|
@socket = yield @socket
|
data/lib/tcr/version.rb
CHANGED
data/spec/tcr_spec.rb
CHANGED
@@ -25,54 +25,91 @@ RSpec.describe TCR do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
describe ".configuration" do
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
it "has a default cassette location configured" do
|
29
|
+
TCR.configuration.cassette_library_dir.should == "fixtures/tcr_cassettes"
|
30
|
+
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
it "has an empty list of hook ports by default" do
|
33
|
+
TCR.configuration.hook_tcp_ports.should == []
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
it "defaults to erroring on read/write mismatch access" do
|
37
|
+
TCR.configuration.block_for_reads.should be_falsey
|
38
|
+
end
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
it "defaults to hit all to false" do
|
41
|
+
TCR.configuration.hit_all.should be_falsey
|
42
|
+
end
|
43
|
+
end
|
44
44
|
|
45
45
|
describe ".configure" do
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
context "with cassette_library_dir option" do
|
47
|
+
it "configures cassette location" do
|
48
|
+
expect {
|
49
|
+
TCR.configure { |c| c.cassette_library_dir = "some/dir" }
|
50
|
+
}.to change{ TCR.configuration.cassette_library_dir }.from("fixtures/tcr_cassettes").to("some/dir")
|
51
|
+
end
|
50
52
|
end
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
context "with hook_tcp_ports option" do
|
55
|
+
it "configures tcp ports to hook" do
|
56
|
+
expect {
|
57
|
+
TCR.configure { |c| c.hook_tcp_ports = [2525] }
|
58
|
+
}.to change{ TCR.configuration.hook_tcp_ports }.from([]).to([2525])
|
59
|
+
end
|
56
60
|
end
|
57
61
|
|
58
|
-
|
59
|
-
|
62
|
+
context "with block_for_reads option" do
|
63
|
+
before(:each) {
|
64
|
+
TCR.configure { |c|
|
65
|
+
c.hook_tcp_ports = [9999]
|
66
|
+
c.cassette_library_dir = '.'
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
it "configures allowing a blocking read mode" do
|
71
|
+
expect {
|
72
|
+
TCR.configure { |c| c.block_for_reads = true }
|
73
|
+
}.to change{ TCR.configuration.block_for_reads }.from(false).to(true)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "blocks read thread until data is available instead of raising mismatch error" do
|
60
77
|
TCR.configure { |c| c.block_for_reads = true }
|
61
|
-
|
62
|
-
end
|
78
|
+
reads = Queue.new
|
63
79
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
80
|
+
TCR.use_cassette("spec/fixtures/block_for_reads") do
|
81
|
+
sock = TCPSocket.open("google.com", 9999)
|
82
|
+
|
83
|
+
t = Thread.new do
|
84
|
+
reads << sock.gets
|
85
|
+
end
|
86
|
+
|
87
|
+
expect(reads.size).to eq(0)
|
88
|
+
sock.print("hello\n")
|
89
|
+
t.value
|
90
|
+
expect(reads.size).to eq(1)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "when disabled" do
|
95
|
+
it "raises mismatch error" do
|
96
|
+
TCR.use_cassette("spec/fixtures/block_for_reads") do
|
97
|
+
sock = TCPSocket.open("google.com", 9999)
|
98
|
+
expect {
|
99
|
+
Timeout::timeout(1) { sock.gets }
|
100
|
+
}.to raise_error(TCR::DirectionMismatchError)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
68
104
|
end
|
69
|
-
end
|
70
105
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
106
|
+
context "with hit_all option" do
|
107
|
+
it "configures to check if all sessions were hit" do
|
108
|
+
expect {
|
109
|
+
TCR.configure { |c| c.hit_all = true }
|
110
|
+
}.to change{ TCR.configuration.hit_all }.from(false).to(true)
|
111
|
+
end
|
112
|
+
end
|
76
113
|
end
|
77
114
|
|
78
115
|
describe ".turned_off" do
|
@@ -98,44 +135,6 @@ RSpec.describe TCR do
|
|
98
135
|
end
|
99
136
|
end
|
100
137
|
|
101
|
-
describe "block_for_reads" do
|
102
|
-
before(:each) {
|
103
|
-
TCR.configure { |c|
|
104
|
-
c.hook_tcp_ports = [9999]
|
105
|
-
c.cassette_library_dir = '.'
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
it "blocks read thread until data is available instead of raising mismatch error" do
|
110
|
-
TCR.configure { |c| c.block_for_reads = true }
|
111
|
-
reads = Queue.new
|
112
|
-
|
113
|
-
TCR.use_cassette("spec/fixtures/block_for_reads") do
|
114
|
-
sock = TCPSocket.open("google.com", 9999)
|
115
|
-
|
116
|
-
t = Thread.new do
|
117
|
-
reads << sock.gets
|
118
|
-
end
|
119
|
-
|
120
|
-
expect(reads.size).to eq(0)
|
121
|
-
sock.print("hello\n")
|
122
|
-
t.value
|
123
|
-
expect(reads.size).to eq(1)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
context "when disabled" do
|
128
|
-
it "raises mismatch error" do
|
129
|
-
TCR.use_cassette("spec/fixtures/block_for_reads") do
|
130
|
-
sock = TCPSocket.open("google.com", 9999)
|
131
|
-
expect {
|
132
|
-
Timeout::timeout(1) { sock.gets }
|
133
|
-
}.to raise_error(TCR::DirectionMismatchError)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
138
|
describe ".use_cassette" do
|
140
139
|
before(:each) {
|
141
140
|
TCR.configure { |c|
|
@@ -144,6 +143,13 @@ RSpec.describe TCR do
|
|
144
143
|
}
|
145
144
|
}
|
146
145
|
|
146
|
+
it "MUST be used when connecting to hooked ports (or else raises an error)" do
|
147
|
+
TCR.configure { |c| c.hook_tcp_ports = [2525] }
|
148
|
+
expect {
|
149
|
+
tcp_socket = TCPSocket.open("smtp.mandrillapp.com", 2525)
|
150
|
+
}.to raise_error(TCR::NoCassetteError)
|
151
|
+
end
|
152
|
+
|
147
153
|
it "requires a block to call" do
|
148
154
|
expect {
|
149
155
|
TCR.use_cassette("test")
|
@@ -433,6 +439,32 @@ RSpec.describe TCR do
|
|
433
439
|
end
|
434
440
|
end
|
435
441
|
|
442
|
+
context "when TCPSocket.open raises an error during recording" do
|
443
|
+
before do
|
444
|
+
TCR.configure { |c|
|
445
|
+
c.format = "yaml" # JSON borks on binary strings
|
446
|
+
c.hook_tcp_ports = [143]
|
447
|
+
c.cassette_library_dir = "."
|
448
|
+
}
|
449
|
+
|
450
|
+
# record cassette
|
451
|
+
TCR.use_cassette("test") do
|
452
|
+
expect { Net::IMAP.new(nil) }.to raise_error(SystemCallError)
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
it "records error to cassette" do
|
457
|
+
expect(File.exist?('test.yaml')).to be(true)
|
458
|
+
expect(File.read('test.yaml')).not_to be_empty
|
459
|
+
end
|
460
|
+
|
461
|
+
it "re-raises the error during replay" do
|
462
|
+
TCR.use_cassette("test") do
|
463
|
+
expect { Net::IMAP.new(nil) }.to raise_error(SystemCallError)
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
436
468
|
it "replaces sockets created with Socket.tcp" do
|
437
469
|
TCR.configure { |c|
|
438
470
|
c.hook_tcp_ports = [23]
|
@@ -440,7 +472,7 @@ RSpec.describe TCR do
|
|
440
472
|
}
|
441
473
|
|
442
474
|
TCR.use_cassette("test") do
|
443
|
-
sock = Socket.tcp("towel.blinkenlights.nl", 23
|
475
|
+
sock = Socket.tcp("towel.blinkenlights.nl", 23)
|
444
476
|
expect(sock).to be_a(TCR::RecordableTCPSocket)
|
445
477
|
end
|
446
478
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tcr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Forman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|