Wednesday, June 29, 2011

Ugly, But SPDY, Vows.js Hacks

‹prev | My Chain | next›

Up today, I continue my efforts to write vows.js tests for the SPDY push streams in node-spdy.

It took a bit of doing, but yesterday I was able to describe one part of SPDY server push:
➜  node-spdy git:(post-response-push) vows ./test/response-test.js --spec

♢ Pushing Additional Resources

A response with a push_stream
✓ should push data on write

✓ OK » 1 honored (0.003s)
That vow covers a "normal" server push—pushing resources into browser cache before SPDY responds with the requested resource. I have been experimenting with pushing resources after the response (e.g. secondary web pages that the user is likely to request).

I am not terribly happy with my implementation of post-response server push in node-spdy so far (which is part of the reason I am writing vows). For each Response, I am adding a post-response callback via a method named setAfterResponsePush(). Adapting the pre-response push vow, I can write the post-response vow as:
    'with a push_after_stream': {
topic: function (response) {
var callback = this.callback;
response.setAfterResponsePush(function(pusher) {callback(null, pusher)});
response._write();
},
'should push data on write': function (pusher) {
assert.equal(pusher, response);
}
}
With that, I have two honored vows:
➜  node-spdy git:(post-response-push) ✗ vows ./test/response-test.js --spec

♢ Pushing Additional Resources

A response with a push_stream
✓ should push data on write
A response with a push_after_stream
✓ should push data on write


✓ OK » 2 honored (0.004s)
My API for post-response push may change, but that should just require a change to the topic of my vows.

Since I am writing vows after the code (I know, I know), I need to verify that the test covers what I actually think is does. So I comment out my setAfterResponsePush() call:
      topic: function (response) {
var callback = this.callback;
// response.setAfterResponsePush(function(pusher) {callback(null, pusher)});
response._write();
}
Re-running my vows, I do get a failure:
➜  node-spdy git:(post-response-push) ✗ vows ./test/response-test.js --spec

♢ Pushing Additional Resources

A response with a push_stream
✓ should push data on write

✗ Errored » callback not fired
in A response with a push_after_stream
in Pushing Additional Resources
in test/response-test.js

✗ Errored » 1 honored ∙ 1 errored ∙ 1 dropped
Cool. So at least my test is covering what I think it is.

Last up today, I would like to verify that the the post-response push occurs... well, after the response.

I have no idea how to do something like that without resorting to bad hacks. So that's what I do. I create a global test variable named last_called to hold the name of the last called function. If the response is written by the connetion object, then the last_called will be 'connection.write':
    connection = {
zlib: spdy.createZLib(),
write: function() {last_called = 'connection.write';}
}
If the post-response callback is called last, the value of last_called will be 'setAfterResponsePush':
      topic: function (response) {
var callback = this.callback;
response.setAfterResponsePush(function(pusher) {
last_called = 'setAfterResponsePush';
callback(null, pusher);
});
response._write();
}
Wow, do I feel dirty about that, but with the following vow:
      'should push _after_ write': function() {
assert.equal(last_called, 'setAfterResponsePush');
}
It works:
➜  node-spdy git:(post-response-push) ✗ vows ./test/response-test.js --spec

♢ Pushing Additional Resources

A response with a push_stream
✓ should push data on write
A response with a push_after_stream
✓ should push data on write
✓ should push _after_ write

✓ OK » 3 honored (0.004s)
The problem with globals is, of course, that they are global. I have the feeling that it won't take long for this to come back to bite me, but I will defer that until tomorrow.

For now, I am satisfied that I have verified that the post-response push is tested and that the test confirms that the call comes after the response to the original request. If I can think of a better approach than setPostResponsePush I may pick this back up tomorrow. I may also put this on the back-burner and begin investigating SPDY alternatives. There is a gaping hole in the SPDY Book in need of filling.


Day #61

No comments:

Post a Comment