|
1 var expect = require('chai').expect; |
|
2 var util = require('./util'); |
|
3 |
|
4 var Connection = require('../lib/connection').Connection; |
|
5 |
|
6 var settings = { |
|
7 SETTINGS_MAX_CONCURRENT_STREAMS: 100, |
|
8 SETTINGS_INITIAL_WINDOW_SIZE: 100000 |
|
9 }; |
|
10 |
|
11 var MAX_PRIORITY = Math.pow(2, 31) - 1; |
|
12 var MAX_RANDOM_PRIORITY = 10; |
|
13 |
|
14 function randomPriority() { |
|
15 return Math.floor(Math.random() * (MAX_RANDOM_PRIORITY + 1)); |
|
16 } |
|
17 |
|
18 function expectPriorityOrder(priorities) { |
|
19 priorities.forEach(function(bucket, priority) { |
|
20 bucket.forEach(function(stream) { |
|
21 expect(stream._priority).to.be.equal(priority); |
|
22 }); |
|
23 }); |
|
24 } |
|
25 |
|
26 describe('connection.js', function() { |
|
27 describe('Connection class', function() { |
|
28 describe('method ._insert(stream)', function() { |
|
29 it('should insert the stream in _streamPriorities in a place determined by stream._priority', function() { |
|
30 var streams = []; |
|
31 var connection = Object.create(Connection.prototype, { _streamPriorities: { value: streams }}); |
|
32 var streamCount = 10; |
|
33 |
|
34 for (var i = 0; i < streamCount; i++) { |
|
35 var stream = { _priority: randomPriority() }; |
|
36 connection._insert(stream, stream._priority); |
|
37 expect(connection._streamPriorities[stream._priority]).to.include(stream); |
|
38 } |
|
39 |
|
40 expectPriorityOrder(connection._streamPriorities); |
|
41 }); |
|
42 }); |
|
43 describe('method ._reprioritize(stream)', function() { |
|
44 it('should eject and then insert the stream in _streamPriorities in a place determined by stream._priority', function() { |
|
45 var streams = []; |
|
46 var connection = Object.create(Connection.prototype, { _streamPriorities: { value: streams }}); |
|
47 var streamCount = 10; |
|
48 var oldPriority, newPriority, stream; |
|
49 |
|
50 for (var i = 0; i < streamCount; i++) { |
|
51 oldPriority = randomPriority(); |
|
52 while ((newPriority = randomPriority()) === oldPriority); |
|
53 stream = { _priority: oldPriority }; |
|
54 connection._insert(stream, oldPriority); |
|
55 connection._reprioritize(stream, newPriority); |
|
56 stream._priority = newPriority; |
|
57 |
|
58 expect(connection._streamPriorities[newPriority]).to.include(stream); |
|
59 expect(connection._streamPriorities[oldPriority] || []).to.not.include(stream); |
|
60 } |
|
61 |
|
62 expectPriorityOrder(streams); |
|
63 }); |
|
64 }); |
|
65 describe('invalid operation', function() { |
|
66 describe('unsolicited ping answer', function() { |
|
67 it('should be ignored', function() { |
|
68 var connection = new Connection(util.log, 1, settings); |
|
69 |
|
70 connection._receivePing({ |
|
71 stream: 0, |
|
72 type: 'PING', |
|
73 flags: { |
|
74 'PONG': true |
|
75 }, |
|
76 data: new Buffer(8) |
|
77 }); |
|
78 }); |
|
79 }); |
|
80 }); |
|
81 }); |
|
82 describe('test scenario', function() { |
|
83 var c, s; |
|
84 beforeEach(function() { |
|
85 c = new Connection(util.log.child({ role: 'client' }), 1, settings); |
|
86 s = new Connection(util.log.child({ role: 'client' }), 2, settings); |
|
87 c.pipe(s).pipe(c); |
|
88 }); |
|
89 |
|
90 describe('connection setup', function() { |
|
91 it('should work as expected', function(done) { |
|
92 setTimeout(function() { |
|
93 // If there are no exception until this, then we're done |
|
94 done(); |
|
95 }, 10); |
|
96 }); |
|
97 }); |
|
98 describe('sending/receiving a request', function() { |
|
99 it('should work as expected', function(done) { |
|
100 // Request and response data |
|
101 var request_headers = { |
|
102 ':method': 'GET', |
|
103 ':path': '/' |
|
104 }; |
|
105 var request_data = new Buffer(0); |
|
106 var response_headers = { |
|
107 ':status': '200' |
|
108 }; |
|
109 var response_data = new Buffer('12345678', 'hex'); |
|
110 |
|
111 // Setting up server |
|
112 s.on('stream', function(server_stream) { |
|
113 server_stream.on('headers', function(headers) { |
|
114 expect(headers).to.deep.equal(request_headers); |
|
115 server_stream.headers(response_headers); |
|
116 server_stream.end(response_data); |
|
117 }); |
|
118 }); |
|
119 |
|
120 // Sending request |
|
121 var client_stream = c.createStream(); |
|
122 client_stream.headers(request_headers); |
|
123 client_stream.end(request_data); |
|
124 |
|
125 // Waiting for answer |
|
126 done = util.callNTimes(2, done); |
|
127 client_stream.on('headers', function(headers) { |
|
128 expect(headers).to.deep.equal(response_headers); |
|
129 done(); |
|
130 }); |
|
131 client_stream.on('readable', function() { |
|
132 expect(client_stream.read()).to.deep.equal(response_data); |
|
133 done(); |
|
134 }); |
|
135 }); |
|
136 }); |
|
137 describe('server push', function() { |
|
138 it('should work as expected', function(done) { |
|
139 var request_headers = { ':method': 'get', ':path': '/' }; |
|
140 var response_headers = { ':status': '200' }; |
|
141 var push_request_headers = { ':method': 'get', ':path': '/x' }; |
|
142 var push_response_headers = { ':status': '200' }; |
|
143 var response_content = new Buffer(10); |
|
144 var push_content = new Buffer(10); |
|
145 |
|
146 done = util.callNTimes(5, done); |
|
147 |
|
148 s.on('stream', function(response) { |
|
149 response.headers(response_headers); |
|
150 |
|
151 var pushed = response.promise(push_request_headers); |
|
152 pushed.headers(push_response_headers); |
|
153 pushed.end(push_content); |
|
154 |
|
155 response.end(response_content); |
|
156 }); |
|
157 |
|
158 var request = c.createStream(); |
|
159 request.headers(request_headers); |
|
160 request.end(); |
|
161 request.on('headers', function(headers) { |
|
162 expect(headers).to.deep.equal(response_headers); |
|
163 done(); |
|
164 }); |
|
165 request.on('readable', function() { |
|
166 expect(request.read()).to.deep.equal(response_content); |
|
167 done(); |
|
168 }); |
|
169 request.on('promise', function(pushed, headers) { |
|
170 expect(headers).to.deep.equal(push_request_headers); |
|
171 pushed.on('headers', function(headers) { |
|
172 expect(headers).to.deep.equal(response_headers); |
|
173 done(); |
|
174 }); |
|
175 pushed.on('readable', function() { |
|
176 expect(pushed.read()).to.deep.equal(push_content); |
|
177 done(); |
|
178 }); |
|
179 pushed.on('end', function() { |
|
180 done(); |
|
181 }); |
|
182 }); |
|
183 }); |
|
184 }); |
|
185 describe('ping from client', function() { |
|
186 it('should work as expected', function(done) { |
|
187 c.ping(function() { |
|
188 done(); |
|
189 }); |
|
190 }); |
|
191 }); |
|
192 describe('ping from server', function() { |
|
193 it('should work as expected', function(done) { |
|
194 s.ping(function() { |
|
195 done(); |
|
196 }); |
|
197 }); |
|
198 }); |
|
199 describe('creating two streams and then using them in reverse order', function() { |
|
200 it('should not result in non-monotonous local ID ordering', function() { |
|
201 var s1 = c.createStream(); |
|
202 var s2 = c.createStream(); |
|
203 s2.headers({ ':method': 'get', ':path': '/' }); |
|
204 s1.headers({ ':method': 'get', ':path': '/' }); |
|
205 }); |
|
206 }); |
|
207 describe('creating two promises and then using them in reverse order', function() { |
|
208 it('should not result in non-monotonous local ID ordering', function(done) { |
|
209 s.on('stream', function(response) { |
|
210 response.headers({ ':status': '200' }); |
|
211 |
|
212 var p1 = s.createStream(); |
|
213 var p2 = s.createStream(); |
|
214 response.promise(p2, { ':method': 'get', ':path': '/p2' }); |
|
215 response.promise(p1, { ':method': 'get', ':path': '/p1' }); |
|
216 p2.headers({ ':status': '200' }); |
|
217 p1.headers({ ':status': '200' }); |
|
218 }); |
|
219 |
|
220 var request = c.createStream(); |
|
221 request.headers({ ':method': 'get', ':path': '/' }); |
|
222 |
|
223 done = util.callNTimes(2, done); |
|
224 request.on('promise', function() { |
|
225 done(); |
|
226 }); |
|
227 }); |
|
228 }); |
|
229 describe('closing the connection on one end', function() { |
|
230 it('should result in closed streams on both ends', function(done) { |
|
231 done = util.callNTimes(2, done); |
|
232 c.on('end', done); |
|
233 s.on('end', done); |
|
234 |
|
235 c.close(); |
|
236 }); |
|
237 }); |
|
238 }); |
|
239 }); |