|
1 var expect = require('chai').expect; |
|
2 var util = require('./util'); |
|
3 |
|
4 var framer = require('../lib/framer'); |
|
5 var Serializer = framer.Serializer; |
|
6 var Deserializer = framer.Deserializer; |
|
7 |
|
8 var frame_types = { |
|
9 DATA: ['data'], |
|
10 HEADERS: ['priority', 'data'], |
|
11 PRIORITY: ['priority'], |
|
12 RST_STREAM: ['error'], |
|
13 SETTINGS: ['settings'], |
|
14 PUSH_PROMISE: ['promised_stream', 'data'], |
|
15 PING: ['data'], |
|
16 GOAWAY: ['last_stream', 'error'], |
|
17 WINDOW_UPDATE: ['window_size'], |
|
18 CONTINUATION: ['data'] |
|
19 }; |
|
20 |
|
21 var test_frames = [{ |
|
22 frame: { |
|
23 type: 'DATA', |
|
24 flags: { END_STREAM: false, END_SEGMENT: false, RESERVED4: false, |
|
25 RESERVED8: false, PAD_LOW: false, PAD_HIGH: false }, |
|
26 stream: 10, |
|
27 |
|
28 data: new Buffer('12345678', 'hex') |
|
29 }, |
|
30 // length + type + flags + stream + content |
|
31 buffer: new Buffer('0004' + '00' + '00' + '0000000A' + '12345678', 'hex') |
|
32 |
|
33 }, { |
|
34 frame: { |
|
35 type: 'HEADERS', |
|
36 flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false, |
|
37 PRIORITY: false, PAD_LOW: false, PAD_HIGH: false }, |
|
38 stream: 15, |
|
39 |
|
40 data: new Buffer('12345678', 'hex') |
|
41 }, |
|
42 buffer: new Buffer('0004' + '01' + '00' + '0000000F' + '12345678', 'hex') |
|
43 |
|
44 }, { |
|
45 frame: { |
|
46 type: 'HEADERS', |
|
47 flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false, |
|
48 PRIORITY: true, PAD_LOW: false, PAD_HIGH: false }, |
|
49 stream: 15, |
|
50 |
|
51 priority: 3, |
|
52 data: new Buffer('12345678', 'hex') |
|
53 }, |
|
54 buffer: new Buffer('0008' + '01' + '08' + '0000000F' + '00000003' + '12345678', 'hex') |
|
55 |
|
56 }, { |
|
57 frame: { |
|
58 type: 'PRIORITY', |
|
59 flags: { }, |
|
60 stream: 10, |
|
61 |
|
62 priority: 3 |
|
63 }, |
|
64 buffer: new Buffer('0004' + '02' + '00' + '0000000A' + '00000003', 'hex') |
|
65 |
|
66 }, { |
|
67 frame: { |
|
68 type: 'RST_STREAM', |
|
69 flags: { }, |
|
70 stream: 10, |
|
71 |
|
72 error: 'INTERNAL_ERROR' |
|
73 }, |
|
74 buffer: new Buffer('0004' + '03' + '00' + '0000000A' + '00000002', 'hex') |
|
75 |
|
76 }, { |
|
77 frame: { |
|
78 type: 'SETTINGS', |
|
79 flags: { ACK: false }, |
|
80 stream: 10, |
|
81 |
|
82 settings: { |
|
83 SETTINGS_HEADER_TABLE_SIZE: 0x12345678, |
|
84 SETTINGS_ENABLE_PUSH: true, |
|
85 SETTINGS_MAX_CONCURRENT_STREAMS: 0x01234567, |
|
86 SETTINGS_INITIAL_WINDOW_SIZE: 0x89ABCDEF |
|
87 } |
|
88 }, |
|
89 buffer: new Buffer('0014' + '04' + '00' + '0000000A' + '01' + '12345678' + |
|
90 '02' + '00000001' + |
|
91 '03' + '01234567' + |
|
92 '04' + '89ABCDEF', 'hex') |
|
93 |
|
94 }, { |
|
95 frame: { |
|
96 type: 'PUSH_PROMISE', |
|
97 flags: { RESERVED1: false, RESERVED2: false, END_PUSH_PROMISE: false }, |
|
98 stream: 15, |
|
99 |
|
100 promised_stream: 3, |
|
101 data: new Buffer('12345678', 'hex') |
|
102 }, |
|
103 buffer: new Buffer('0008' + '05' + '00' + '0000000F' + '00000003' + '12345678', 'hex') |
|
104 |
|
105 }, { |
|
106 frame: { |
|
107 type: 'PING', |
|
108 flags: { ACK: false }, |
|
109 stream: 15, |
|
110 |
|
111 data: new Buffer('1234567887654321', 'hex') |
|
112 }, |
|
113 buffer: new Buffer('0008' + '06' + '00' + '0000000F' + '1234567887654321', 'hex') |
|
114 |
|
115 }, { |
|
116 frame: { |
|
117 type: 'GOAWAY', |
|
118 flags: { }, |
|
119 stream: 10, |
|
120 |
|
121 last_stream: 0x12345678, |
|
122 error: 'PROTOCOL_ERROR' |
|
123 }, |
|
124 buffer: new Buffer('0008' + '07' + '00' + '0000000A' + '12345678' + '00000001', 'hex') |
|
125 |
|
126 }, { |
|
127 frame: { |
|
128 type: 'WINDOW_UPDATE', |
|
129 flags: { }, |
|
130 stream: 10, |
|
131 |
|
132 window_size: 0x12345678 |
|
133 }, |
|
134 buffer: new Buffer('0004' + '08' + '00' + '0000000A' + '12345678', 'hex') |
|
135 }, { |
|
136 frame: { |
|
137 type: 'CONTINUATION', |
|
138 flags: { RESERVED1: false, RESERVED2: false, END_HEADERS: true, |
|
139 RESERVED8: false, PAD_LOW: false, PAD_HIGH: false }, |
|
140 stream: 10, |
|
141 |
|
142 data: new Buffer('12345678', 'hex') |
|
143 }, |
|
144 // length + type + flags + stream + content |
|
145 buffer: new Buffer('0004' + '09' + '04' + '0000000A' + '12345678', 'hex') |
|
146 }]; |
|
147 |
|
148 var deserializer_test_frames = test_frames.slice(0); |
|
149 var padded_test_frames = [{ |
|
150 frame: { |
|
151 type: 'DATA', |
|
152 flags: { END_STREAM: false, END_SEGMENT: false, RESERVED4: false, |
|
153 RESERVED8: false, PAD_LOW: true, PAD_HIGH: false }, |
|
154 stream: 10, |
|
155 data: new Buffer('12345678', 'hex') |
|
156 }, |
|
157 // length + type + flags + stream + pad_low control + content + padding |
|
158 buffer: new Buffer('000B' + '00' + '10' + '0000000A' + '06' + '12345678' + '000000000000', 'hex') |
|
159 |
|
160 }, { |
|
161 frame: { |
|
162 type: 'HEADERS', |
|
163 flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false, |
|
164 PRIORITY: false, PAD_LOW: true, PAD_HIGH: false }, |
|
165 stream: 15, |
|
166 |
|
167 data: new Buffer('12345678', 'hex') |
|
168 }, |
|
169 buffer: new Buffer('000B' + '01' + '10' + '0000000F' + '06' + '12345678' + '000000000000', 'hex') |
|
170 |
|
171 }, { |
|
172 frame: { |
|
173 type: 'HEADERS', |
|
174 flags: { END_STREAM: false, END_SEGMENT: false, END_HEADERS: false, |
|
175 PRIORITY: true, PAD_LOW: true, PAD_HIGH: false }, |
|
176 stream: 15, |
|
177 |
|
178 priority: 3, |
|
179 data: new Buffer('12345678', 'hex') |
|
180 }, |
|
181 buffer: new Buffer('000F' + '01' + '18' + '0000000F' + '06' + '00000003' + '12345678' + '000000000000', 'hex') |
|
182 |
|
183 }, { |
|
184 frame: { |
|
185 type: 'CONTINUATION', |
|
186 flags: { RESERVED1: false, RESERVED2: false, END_HEADERS: true, |
|
187 RESERVED8: false, PAD_LOW: true, PAD_HIGH: false }, |
|
188 stream: 10, |
|
189 |
|
190 data: new Buffer('12345678', 'hex') |
|
191 }, |
|
192 // length + type + flags + stream + content |
|
193 buffer: new Buffer('000B' + '09' + '14' + '0000000A' + '06' + '12345678' + '000000000000', 'hex') |
|
194 }]; |
|
195 for (var idx = 0; idx < padded_test_frames.length; idx++) { |
|
196 deserializer_test_frames.push(padded_test_frames[idx]); |
|
197 } |
|
198 |
|
199 |
|
200 describe('framer.js', function() { |
|
201 describe('Serializer', function() { |
|
202 describe('static method .commonHeader({ type, flags, stream }, buffer_array)', function() { |
|
203 it('should add the appropriate 8 byte header buffer in front of the others', function() { |
|
204 for (var i = 0; i < test_frames.length; i++) { |
|
205 var test = test_frames[i]; |
|
206 var buffers = [test.buffer.slice(8)]; |
|
207 var header_buffer = test.buffer.slice(0,8); |
|
208 Serializer.commonHeader(test.frame, buffers); |
|
209 expect(buffers[0]).to.deep.equal(header_buffer); |
|
210 } |
|
211 }); |
|
212 }); |
|
213 |
|
214 Object.keys(frame_types).forEach(function(type) { |
|
215 var tests = test_frames.filter(function(test) { return test.frame.type === type; }); |
|
216 var frame_shape = '{ ' + frame_types[type].join(', ') + ' }'; |
|
217 describe('static method .' + type + '(' + frame_shape + ', buffer_array)', function() { |
|
218 it('should push buffers to the array that make up a ' + type + ' type payload', function() { |
|
219 for (var i = 0; i < tests.length; i++) { |
|
220 var test = tests[i]; |
|
221 var buffers = []; |
|
222 Serializer[type](test.frame, buffers); |
|
223 expect(util.concat(buffers)).to.deep.equal(test.buffer.slice(8)); |
|
224 } |
|
225 }); |
|
226 }); |
|
227 }); |
|
228 |
|
229 describe('transform stream', function() { |
|
230 it('should transform frame objects to appropriate buffers', function() { |
|
231 var stream = new Serializer(util.log); |
|
232 |
|
233 for (var i = 0; i < test_frames.length; i++) { |
|
234 var test = test_frames[i]; |
|
235 stream.write(test.frame); |
|
236 var chunk, buffer = new Buffer(0); |
|
237 while (chunk = stream.read()) { |
|
238 buffer = util.concat([buffer, chunk]); |
|
239 } |
|
240 expect(buffer).to.be.deep.equal(test.buffer); |
|
241 } |
|
242 }); |
|
243 }); |
|
244 }); |
|
245 |
|
246 describe('Deserializer', function() { |
|
247 describe('static method .commonHeader(header_buffer, frame)', function() { |
|
248 it('should augment the frame object with these properties: { type, flags, stream })', function() { |
|
249 for (var i = 0; i < deserializer_test_frames.length; i++) { |
|
250 var test = deserializer_test_frames[i], frame = {}; |
|
251 Deserializer.commonHeader(test.buffer.slice(0,8), frame); |
|
252 expect(frame).to.deep.equal({ |
|
253 type: test.frame.type, |
|
254 flags: test.frame.flags, |
|
255 stream: test.frame.stream |
|
256 }); |
|
257 } |
|
258 }); |
|
259 }); |
|
260 |
|
261 Object.keys(frame_types).forEach(function(type) { |
|
262 var tests = deserializer_test_frames.filter(function(test) { return test.frame.type === type; }); |
|
263 var frame_shape = '{ ' + frame_types[type].join(', ') + ' }'; |
|
264 describe('static method .' + type + '(payload_buffer, frame)', function() { |
|
265 it('should augment the frame object with these properties: ' + frame_shape, function() { |
|
266 for (var i = 0; i < tests.length; i++) { |
|
267 var test = tests[i]; |
|
268 var frame = { |
|
269 type: test.frame.type, |
|
270 flags: test.frame.flags, |
|
271 stream: test.frame.stream |
|
272 }; |
|
273 Deserializer[type](test.buffer.slice(8), frame); |
|
274 expect(frame).to.deep.equal(test.frame); |
|
275 } |
|
276 }); |
|
277 }); |
|
278 }); |
|
279 |
|
280 describe('transform stream', function() { |
|
281 it('should transform buffers to appropriate frame object', function() { |
|
282 var stream = new Deserializer(util.log); |
|
283 |
|
284 var shuffled = util.shuffleBuffers(deserializer_test_frames.map(function(test) { return test.buffer; })); |
|
285 shuffled.forEach(stream.write.bind(stream)); |
|
286 |
|
287 for (var j = 0; j < deserializer_test_frames.length; j++) { |
|
288 expect(stream.read()).to.be.deep.equal(deserializer_test_frames[j].frame); |
|
289 } |
|
290 }); |
|
291 }); |
|
292 }); |
|
293 |
|
294 describe('bunyan formatter', function() { |
|
295 describe('`frame`', function() { |
|
296 var format = framer.serializers.frame; |
|
297 it('should assign a unique ID to each frame', function() { |
|
298 var frame1 = { type: 'DATA', data: new Buffer(10) }; |
|
299 var frame2 = { type: 'PRIORITY', priority: 1 }; |
|
300 expect(format(frame1).id).to.be.equal(format(frame1)); |
|
301 expect(format(frame2).id).to.be.equal(format(frame2)); |
|
302 expect(format(frame1)).to.not.be.equal(format(frame2)); |
|
303 }); |
|
304 }); |
|
305 }); |
|
306 }); |