もくもくしてるナニのメモ
完成目前、なのかどうか。とりあえず smtp な fakeweb 的ソリューションが無いみたいなので nodemailer な部分については別な手続きにして試験を作ってます。
# そのうち fakesmtp とかってのが出てくるのか作るのか
試験
メソドが無い、ってエラーが出てて ?? 状態だったんですが、vows って
$ vows test/*
で起動したら emacs のバックアップも処理対象にしちゃうんですねorz
あと、intercept してない URL にアクセスするコースを通過してるはずなんですが、何のお咎めも無かったなぁ。もしかして通ってないのかも。
掘削および改修
ええと、とりあえず fakeweb.js は http.request を書き換えてるのみ、だったので以下を追加。
var old_https_request = https.request; https.request = function(options, callback){ var rule = match_rule(options); if(rule){ var res = new events.EventEmitter(); res.headers = rule.headers || {'Content-Type': 'text/html'}; return {end: function(){ callback(res); res.emit('data', rule.body || ''); res.emit('end'); } }; } else { return old_https_request.call(http, options, callback); } };
動かしてみたら setEncoding というメソドが無い、とお叱りを受けました。とりあえず上記 res に何らかの属性を追加する必要があるんですがどうなのか。
顛末
なんとか動くようになったので情報を纏めておきます。
fakeweb で https な応答をする手続きが未定義
これは上で書いてますね。
FacebookClient の setEncoding 対策
FacebookClient の doRequest という手続きが戻す手続きの中で setEncoding 手続きを呼び出す記述があります。
var request = protocol.request(options, function(response){ response.setEncoding("utf8"); var body = [];
fakeweb の https.request 手続きにて空っぽの手続きをセットしてます。
var old_https_request = https.request; https.request = function(options, callback){ var rule = match_rule(options); if(rule){ var res = new events.EventEmitter(); res.setEncoding = function(encoding) {};
すげぇ無理矢理。
match_rule 手続き
ドキュメントには以下のようにせい、という記述があるんですが
var fakeweb = require('fakeweb'), http = require('http') http.register_intercept({ uri: '/foo', host: 'test.com', body: 'I'm the mocked-out body!' }) http.request({uri: "/foo", host: "test.com"}, function(response){ // ... })
FacebookClient 側の options の記述が以下になってます。
var options = { host: host, port: port, path: path, method: method || 'GET' };
これが前提になってくるのですが fakeweb の match_rule という手続きは以下な形で定義されておりまして
function match_rule(options){ var matched_rule; intercept_rules.forEach(function(rule){ var keys = Object.keys(rule), match = false; // TODO headers matching and regex support keys.forEach(function(key){ if(options[key]){ if(rule[key] instanceof RegExp){ match = rule[key].test(options[key]); } else { match = options[key] == rule[key]; } } }); if(match){ matched_rule = rule; } }); return matched_rule; }
マッチングかけたい key が uri と path ってなってて、そこがそもそもマッチしない、というアレ。しかも残念なことに全ての要素についてマッチングしてて、その上最後のマッチングの結果が戻る形になっております。
とりあえず
- register_intercept 手続きに渡す javascript オブジェクトは uri じゃなくて path という key にする
- path な値は RegExp オブジェクトにする
- path のみでマッチング
- マッチしたらその後のマッチングはスルー
ということにして以下な実装に変更してたりして。
function match_rule(options){ var matched_rule; intercept_rules.forEach(function(rule){ var keys = Object.keys(rule), match = false; keys.forEach( function(key){ if(key == 'path' && !match){ if(rule[key] instanceof RegExp){ match = rule[key].test(options[key]); } else { match = options[key] == rule[key]; } } });
オレオレ fakeweb ってことでリポジトリにも追加しとこ。とりあえず試験も全てパスしたので再度 commit/push も。
あとは本番で正常動作するか、がアレなんですが、試験用のアカウントもあるみたいなので、そっちで試験をする方向。