3
3
namespace React \Tests \Socket ;
4
4
5
5
use React \Promise ;
6
+ use React \Promise \Deferred ;
6
7
use React \Socket \SecureConnector ;
7
8
8
9
class SecureConnectorTest extends TestCase
@@ -51,16 +52,33 @@ public function testConnectionToInvalidSchemeWillReject()
51
52
52
53
public function testCancelDuringTcpConnectionCancelsTcpConnection ()
53
54
{
54
- $ pending = new Promise \Promise (function () { }, function () { throw new \Exception (); });
55
+ $ pending = new Promise \Promise (function () { }, $ this ->expectCallableOnce ());
56
+ $ this ->tcp ->expects ($ this ->once ())->method ('connect ' )->with ('example.com:80 ' )->willReturn ($ pending );
57
+
58
+ $ promise = $ this ->connector ->connect ('example.com:80 ' );
59
+ $ promise ->cancel ();
60
+ }
61
+
62
+ /**
63
+ * @expectedException RuntimeException
64
+ * @expectedExceptionMessage Connection cancelled
65
+ */
66
+ public function testCancelDuringTcpConnectionCancelsTcpConnectionAndRejectsWithTcpRejection ()
67
+ {
68
+ $ pending = new Promise \Promise (function () { }, function () { throw new \RuntimeException ('Connection cancelled ' ); });
55
69
$ this ->tcp ->expects ($ this ->once ())->method ('connect ' )->with ($ this ->equalTo ('example.com:80 ' ))->will ($ this ->returnValue ($ pending ));
56
70
57
71
$ promise = $ this ->connector ->connect ('example.com:80 ' );
58
72
$ promise ->cancel ();
59
73
60
- $ promise -> then ( $ this ->expectCallableNever (), $ this -> expectCallableOnce () );
74
+ $ this ->throwRejection ( $ promise );
61
75
}
62
76
63
- public function testConnectionWillBeClosedAndRejectedIfConnectioIsNoStream ()
77
+ /**
78
+ * @expectedException UnexpectedValueException
79
+ * @expectedExceptionMessage Base connector does not use internal Connection class exposing stream resource
80
+ */
81
+ public function testConnectionWillBeClosedAndRejectedIfConnectionIsNoStream ()
64
82
{
65
83
$ connection = $ this ->getMockBuilder ('React\Socket\ConnectionInterface ' )->getMock ();
66
84
$ connection ->expects ($ this ->once ())->method ('close ' );
@@ -69,6 +87,133 @@ public function testConnectionWillBeClosedAndRejectedIfConnectioIsNoStream()
69
87
70
88
$ promise = $ this ->connector ->connect ('example.com:80 ' );
71
89
72
- $ promise ->then ($ this ->expectCallableNever (), $ this ->expectCallableOnce ());
90
+ $ this ->throwRejection ($ promise );
91
+ }
92
+
93
+ public function testStreamEncryptionWillBeEnabledAfterConnecting ()
94
+ {
95
+ $ connection = $ this ->getMockBuilder ('React\Socket\Connection ' )->disableOriginalConstructor ()->getMock ();
96
+
97
+ $ encryption = $ this ->getMockBuilder ('React\Socket\StreamEncryption ' )->disableOriginalConstructor ()->getMock ();
98
+ $ encryption ->expects ($ this ->once ())->method ('enable ' )->with ($ connection )->willReturn (new \React \Promise \Promise (function () { }));
99
+
100
+ $ ref = new \ReflectionProperty ($ this ->connector , 'streamEncryption ' );
101
+ $ ref ->setAccessible (true );
102
+ $ ref ->setValue ($ this ->connector , $ encryption );
103
+
104
+ $ pending = new Promise \Promise (function () { }, function () { throw new \RuntimeException ('Connection cancelled ' ); });
105
+ $ this ->tcp ->expects ($ this ->once ())->method ('connect ' )->with ($ this ->equalTo ('example.com:80 ' ))->willReturn (Promise \resolve ($ connection ));
106
+
107
+ $ promise = $ this ->connector ->connect ('example.com:80 ' );
108
+ }
109
+
110
+ public function testConnectionWillBeRejectedIfStreamEncryptionFailsAndClosesConnection ()
111
+ {
112
+ $ connection = $ this ->getMockBuilder ('React\Socket\Connection ' )->disableOriginalConstructor ()->getMock ();
113
+ $ connection ->expects ($ this ->once ())->method ('close ' );
114
+
115
+ $ encryption = $ this ->getMockBuilder ('React\Socket\StreamEncryption ' )->disableOriginalConstructor ()->getMock ();
116
+ $ encryption ->expects ($ this ->once ())->method ('enable ' )->willReturn (Promise \reject (new \RuntimeException ('TLS error ' , 123 )));
117
+
118
+ $ ref = new \ReflectionProperty ($ this ->connector , 'streamEncryption ' );
119
+ $ ref ->setAccessible (true );
120
+ $ ref ->setValue ($ this ->connector , $ encryption );
121
+
122
+ $ pending = new Promise \Promise (function () { }, function () { throw new \RuntimeException ('Connection cancelled ' ); });
123
+ $ this ->tcp ->expects ($ this ->once ())->method ('connect ' )->with ($ this ->equalTo ('example.com:80 ' ))->willReturn (Promise \resolve ($ connection ));
124
+
125
+ $ promise = $ this ->connector ->connect ('example.com:80 ' );
126
+
127
+ try {
128
+ $ this ->throwRejection ($ promise );
129
+ } catch (\RuntimeException $ e ) {
130
+ $ this ->assertEquals ('Connection to example.com:80 failed during TLS handshake: TLS error ' , $ e ->getMessage ());
131
+ $ this ->assertEquals (123 , $ e ->getCode ());
132
+ $ this ->assertNull ($ e ->getPrevious ());
133
+ }
134
+ }
135
+
136
+ /**
137
+ * @expectedException RuntimeException
138
+ * @expectedExceptionMessage Connection to example.com:80 cancelled during TLS handshake
139
+ */
140
+ public function testCancelDuringStreamEncryptionCancelsEncryptionAndClosesConnection ()
141
+ {
142
+ $ connection = $ this ->getMockBuilder ('React\Socket\Connection ' )->disableOriginalConstructor ()->getMock ();
143
+ $ connection ->expects ($ this ->once ())->method ('close ' );
144
+
145
+ $ pending = new Promise \Promise (function () { }, function () {
146
+ throw new \Exception ('Ignored ' );
147
+ });
148
+ $ encryption = $ this ->getMockBuilder ('React\Socket\StreamEncryption ' )->disableOriginalConstructor ()->getMock ();
149
+ $ encryption ->expects ($ this ->once ())->method ('enable ' )->willReturn ($ pending );
150
+
151
+ $ ref = new \ReflectionProperty ($ this ->connector , 'streamEncryption ' );
152
+ $ ref ->setAccessible (true );
153
+ $ ref ->setValue ($ this ->connector , $ encryption );
154
+
155
+ $ this ->tcp ->expects ($ this ->once ())->method ('connect ' )->with ($ this ->equalTo ('example.com:80 ' ))->willReturn (Promise \resolve ($ connection ));
156
+
157
+ $ promise = $ this ->connector ->connect ('example.com:80 ' );
158
+ $ promise ->cancel ();
159
+
160
+ $ this ->throwRejection ($ promise );
161
+ }
162
+
163
+ public function testRejectionDuringConnectionShouldNotCreateAnyGarbageReferences ()
164
+ {
165
+ if (class_exists ('React\Promise\When ' )) {
166
+ $ this ->markTestSkipped ('Not supported on legacy Promise v1 API ' );
167
+ }
168
+
169
+ gc_collect_cycles ();
170
+
171
+ $ tcp = new Deferred ();
172
+ $ this ->tcp ->expects ($ this ->once ())->method ('connect ' )->willReturn ($ tcp ->promise ());
173
+
174
+ $ promise = $ this ->connector ->connect ('example.com:80 ' );
175
+ $ tcp ->reject (new \RuntimeException ());
176
+ unset($ promise , $ tcp );
177
+
178
+ $ this ->assertEquals (0 , gc_collect_cycles ());
179
+ }
180
+
181
+ public function testRejectionDuringTlsHandshakeShouldNotCreateAnyGarbageReferences ()
182
+ {
183
+ if (class_exists ('React\Promise\When ' )) {
184
+ $ this ->markTestSkipped ('Not supported on legacy Promise v1 API ' );
185
+ }
186
+
187
+ gc_collect_cycles ();
188
+
189
+ $ connection = $ this ->getMockBuilder ('React\Socket\Connection ' )->disableOriginalConstructor ()->getMock ();
190
+
191
+ $ tcp = new Deferred ();
192
+ $ this ->tcp ->expects ($ this ->once ())->method ('connect ' )->willReturn ($ tcp ->promise ());
193
+
194
+ $ tls = new Deferred ();
195
+ $ encryption = $ this ->getMockBuilder ('React\Socket\StreamEncryption ' )->disableOriginalConstructor ()->getMock ();
196
+ $ encryption ->expects ($ this ->once ())->method ('enable ' )->willReturn ($ tls ->promise ());
197
+
198
+ $ ref = new \ReflectionProperty ($ this ->connector , 'streamEncryption ' );
199
+ $ ref ->setAccessible (true );
200
+ $ ref ->setValue ($ this ->connector , $ encryption );
201
+
202
+ $ promise = $ this ->connector ->connect ('example.com:80 ' );
203
+ $ tcp ->resolve ($ connection );
204
+ $ tls ->reject (new \RuntimeException ());
205
+ unset($ promise , $ tcp , $ tls );
206
+
207
+ $ this ->assertEquals (0 , gc_collect_cycles ());
208
+ }
209
+
210
+ private function throwRejection ($ promise )
211
+ {
212
+ $ ex = null ;
213
+ $ promise ->then (null , function ($ e ) use (&$ ex ) {
214
+ $ ex = $ e ;
215
+ });
216
+
217
+ throw $ ex ;
73
218
}
74
219
}
0 commit comments