I am about ready to pull back from my SPDY server push spike and implement for real in node-spdy. But it has been a while since I have done serious vows.js testing so this may take a bit.
Actually, it may not. When I run the existing test suite for node-spdy, I get:
➜ node-spdy git:(push-stream) vows test/spdy-basic-test.js --specThe test structure for this basic test is... interesting. Most of the topics and vows are setting test-local variables to be re-used later on in the test suite. For instance, the
♢ SPDY/basic test
spdy.createServer
✓ should return spdy.Server instance
Listening on this server instance
✓ should be successfull
Calling spdy.createZLib
✓ should return instance of spdy.ZLib
Creating new connection to this server
✓ should receive connect event
Creating parser and waiting for SYN_REPLY
✓ should end up w/ that frame
Sending control SYN_STREAM frame should be successfull and sending request body
✓ should emit data and end events on request
Creating parser and waiting for Data packet
✗ should end up w/ that frame
» expected 1,
got 0 (==) // spdy-basic-test.js:140
✓ should end up w/ that frame
When calling server.close
✓ all connections will be dropped
✗ Broken » 7 honored ∙ 1 broken (0.036s)
connection
variable is declared outside of the test suite:var spdy = require('../lib/spdy');And is assigned inside the "Creating new connection" topic:
var server,
connection,
//...
vows.describe('SPDY/basic test').addBatch({Later on there is a separate topic that pipes that connection directly into a node-spdy
'spdy.createServer': {
//...
}
}).addBatch({
'Listening on this server instance': {
//...
}
}).addBatch({
'Creating new connection to this server': {
topic: function() {
connection = require('tls').connect(PORT, 'localhost', options, this.callback);
},
'should receive connect event': function() {
}
},
'Calling spdy.createZLib': {
topic: function() {
return spdy.createZLib();
},
'should return instance of spdy.ZLib': function(_zlib) {
zlib = _zlib;
assert.instanceOf(zlib, spdy.ZLib);
}
}
}).addBatch({
//...
Parser
object://...The failure that I am seeing is occurring in one of the two sub-contexts for this parser:
'Creating parser': {
topic: function() {
var parser = spdy.createParser(zlib);
connection.pipe(parser);
return parser;
},
//...
//...It is in the second sub-context, the waiting for the Data packet context, in which I am experiencing problems. Specifically, I am getting a 1 for 0 error:
'Creating parser': {
//...
'and waiting for SYN_REPLY': {
//...
},
'and waiting for Data packet': {
//...
}
}
//...
Creating parser and waiting for Data packetThe value of
✗ should end up w/ that frame
» expected 1,
got 0 (==) // spdy-basic-test.js:137
1
is setting the expectation that there is a data FIN flag set on the first data frame received. But clearly that is not the case now.The key word in that last sentence is "now". The data frame being received is the server push frame. I am sending out a separate, empty data FIN frame for the server push, so the first data push frame is devoid of FIN flags, hence the error.
Hrm... I am not quite ready to abandon my spike, but hate to proceed with that test failing. Actually, this is probably a good time to break out a separate vows suite for server push itself. From a high level, I expect the test to be exactly the same as this one, except that there is no FIN on the data packet:
//...I save that into a separate
'should end up with the push frame': function(dframe) {
assert.ok(!dframe.headers.c);
assert.equal(dframe.headers.flags & spdy.enums.DATA_FLAG_FIN, 0);
}
//...
test/spdy-push-test.js
and run it to find:...Hunh? How could it fail in both suites? Ah, I see. It is getting called twice. The first time through it passes, but the second time through, it fails. I only want to call it once, so I create a closure in the topic to only call it a single time:
Creating parser and waiting for Data packet
✓ should end up with the push frame
✗ should end up with the push frame
» expected 0,
got 1 (==) // spdy-push-test.js:143
...
topic: function(parser) {With that, I have my passing suite:
var callback = this.callback;
var called = false;
parser.on('dframe', function(dframe) {
if (!called) {
callback(null, dframe);
}
called = true;
});
},
➜ node-spdy git:(push-stream) ✗ vows test/spdy-push-test.js --specI will pick back up there tomorrow trying to get both suites passing at the same time. If I can do that, I ought to have a fairly re-usable solution for SPDY server push. Of course, that is a big "if".
♢ SPDY/basic test
spdy.createServer
✓ should return spdy.Server instance
Listening on this server instance
✓ should be successfull
Calling spdy.createZLib
✓ should return instance of spdy.ZLib
Creating new connection to this server
✓ should receive connect event
Creating parser and waiting for SYN_REPLY
✓ should end up w/ that frame
Sending control SYN_STREAM frame should be successfull and sending request body
✓ should emit data and end events on request
Creating parser and waiting for Data packet
✓ should end up with the push frame
When calling server.close
✓ all connections will be dropped
✓ OK » 8 honored (0.033s)
Day #42
No comments:
Post a Comment