----------------------------------------------------------------------------- -- Mock WSAPI handler for Unit testing -- -- Author: Norman Clarke -- Copyright (c) 2010 Kepler Project -- ----------------------------------------------------------------------------- local _M = {} local common = require "wsapi.common" local request = require "wsapi.request" -- Build a request that looks like something that would come from a real web -- browser. local function build_request(method, path, headers) local req = { GATEWAY_INTERFACE = "CGI/1.1", HTTP_ACCEPT = "application/xml,application/xhtml+xml,text/html;q=0.9," .. "text/plain;q=0.8,image/png,*/*;q=0.5", HTTP_ACCEPT_CHARSET = "ISO-8859-1,utf-8;q=0.7,*;q=0.3", HTTP_ACCEPT_ENCODING = "gzip,deflate,sdch", HTTP_ACCEPT_LANGUAGE = "en-US,en;q=0.8", HTTP_CACHE_CONTROL = "max-age=0", HTTP_CONNECTION = "keep-alive", HTTP_HOST = "127.0.0.1:80", HTTP_USER_AGENT = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X " .. "10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) " .. "Chrome/6.0.472.55", HTTP_VERSION = "HTTP/1.1", REMOTE_ADDR = "127.0.0.1", REMOTE_HOST = "localhost", SCRIPT_NAME = "wsapi_test", SERVER_NAME = "localhost", SERVER_PORT = "80", SERVER_PROTOCOL = "HTTP/1.1" } req.PATH_INFO = path req.REQUEST_METHOD = method:upper() req.METHOD = req.REQUEST_METHOD req.REQUEST_PATH = "/" if req.PATH_INFO == "" then req.PATH_INFO = "/" end for k, v in pairs(headers or {}) do req[k] = v end -- allow case-insensitive table key access setmetatable(req, {__index = function(t, k) return rawget(t, string.upper(k)) end}) return req end -- Override common's output handler to avoid writing headers -- in the reponse body. function common.send_output(out, status, headers, res_iter, write_method,res_line) common.send_content(out, res_iter, "write") end -- Mock IO objects local function make_io_object(content) local receiver = { buffer = { content }, bytes_read = 0 } function receiver:write(content) self.buffer[#self.buffer + 1] = content return true end function receiver:read(len) -- first read will turn the buffer into a string if type(self.buffer) == "table" then self.buffer = table.concat(self.buffer) end len = len or (#self.buffer - self.bytes_read) if self.bytes_read >= #self.buffer then return nil end local s = self.buffer:sub(self.bytes_read + 1, self.bytes_read + len) self.bytes_read = self.bytes_read + len if self.bytes_read > #self.buffer then self.bytes_read = #self.buffer end return s end function receiver:clear() self.buffer = {} self.bytes_read = 0 end function receiver:reset() self.bytes_read = 0 end return receiver end -- Build a GET request local function build_get(path, params, headers) local req = build_request("GET", path, headers) req.QUERY_STRING = request.methods.qs_encode(nil, params) req.REQUEST_URI = "http://" .. req.HTTP_HOST .. req.PATH_INFO .. req.QUERY_STRING return { env = req, input = make_io_object(), output = make_io_object(), error = make_io_object() } end local function build_post(path, params, headers) local req = build_request("POST", path, headers) req.REQUEST_URI = "http://" .. req.HTTP_HOST .. req.PATH_INFO local body if headers["Content-Type"] then body = params else body = request.methods.qs_encode(nil, params):gsub("^?", "") req.CONTENT_TYPE = "x-www-form-urlencoded" end -- if the path includes a query string, store it in the appropiate header local qs = path:match("?(.+)$") if qs then req.QUERY_STRING = qs end req.CONTENT_LENGTH = headers["Content-Length"] or #body return { env = req, input = make_io_object(body), output = make_io_object(), error = make_io_object() } end local function make_request(request_builder, app, path, params, headers) local wsapi_env = request_builder(path, params, headers) local response = {} response.code, response.headers = common.run(app, wsapi_env) response.body = wsapi_env.output:read() response.wsapi_errors = wsapi_env.error:read() return response, wsapi_env.env end local function get(self, path, params, headers) return make_request(build_get, self.app, path, params, headers) end local function post(self, path, params, headers) return make_request(build_post, self.app, path, params, headers) end --- Creates a WSAPI handler for testing. -- @param app The WSAPI application you want to test. function _M.make_handler(app) return { app = app, get = get, post = post } end return _M