diff --git a/Readme.md b/Readme.md index 4eb694d..44d8825 100644 --- a/Readme.md +++ b/Readme.md @@ -234,10 +234,10 @@ Notes Known Issues --------------------------- 1. Auth bson message has reduntant value. -2. Could not inserting a null array, it always inserted as a document. -3. Gridfs_new api only create a meta info in file_col. +2. Gridfs_new api only create a meta info in file_col. -Example + +Basic Usage --------------------------- local mongo = require "resty.mongol" conn = mongo:new() @@ -252,7 +252,11 @@ Example r = col:find_one({name="dog"}) ngx.say(r["name"]) + + +See wiki for advanced examples + For Test Case -------------------- #####mongo config: diff --git a/lib/resty/mongol/ObjectId.lua b/lib/resty/mongol/ObjectId.lua new file mode 100755 index 0000000..5ee744d --- /dev/null +++ b/lib/resty/mongol/ObjectId.lua @@ -0,0 +1,104 @@ +local type = type +local require = require +local assert = assert +local setmetatable = setmetatable + +local string_byte = string.byte +local string_format = string.format +local table_insert = table.insert +local table_concat = table.concat +local os_time = os.time +local io_popen = io.popen + +local hasposix, posix = pcall(require , "posix") + +local ngx = ngx +local ngx_decode_base64 = ngx.decode_base64 +local ngx_encode_base64 = ngx.encode_base64 +local ngx_md5_bin = ngx.md5_bin + +module(...) + +local ll = require(_PACKAGE.."ll") +local num_to_le_uint = ll.num_to_le_uint +local num_to_be_uint = ll.num_to_be_uint +local be_uint_tonum = ll.be_uint_to_num + +local machineid +local function _get_os_machineid() + if hasposix then + machineid = posix.uname("%n") + else + machineid = assert(io_popen("uname -n")):read("*l") + end + machineid = ngx_md5_bin(machineid):sub(1, 3) + return machineid +end + +local pid +local function _get_os_pid() + pid = num_to_le_uint(ngx.var.pid, 2) + return pid +end + +local inc = 0 +local function _generate_id() + inc = inc + 1 + -- "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON" + return num_to_be_uint(os_time(), 4) .. (machineid or _get_os_machineid()) .. (pid or _get_os_pid()) .. num_to_be_uint(inc, 3) +end + +local function _new(cls, id) + if id then + if type(id) == 'string' then + local len = #id + if len == 12 then + elseif len == 16 then + id = ngx_decode_base64((id:gsub('!', '+'):gsub('_', '/'))) + else + return nil, 'expecting string is 12 or 16 length' + end + else + return nil, 'expecting id is string or nil' + end + end + local o = { id = id or _generate_id() } + setmetatable(o, cls) + return o +end + +setmetatable(_M, { __call = _new }) + +__index = _M + +__tostring = function(ob) + return ngx_encode_base64(ob.id):gsub('%+', '!'):gsub('/', '_') +end + +__tojson = __tostring + +__eq = function (a, b) + return a.id == b.id +end + +tostring = __tostring + +function get_ts(ob) + return be_uint_to_num(ob.id, 1, 4) +end + +function get_pid(ob) + return be_uint_to_num(ob.id, 8, 9) +end + +function get_hostname(ob) + local t = {} + for i = 5, 7 do + table_insert(t, string_format("%02x", string_byte(ob.id, i, i))) + end + return table_concat(t) +end + +function get_inc(ob) + return be_uint_to_num(ob.id, 10, 12) +end diff --git a/lib/resty/mongol/bson-lua/bson.lua b/lib/resty/mongol/bson-lua/bson.lua deleted file mode 100644 index d92e6d8..0000000 --- a/lib/resty/mongol/bson-lua/bson.lua +++ /dev/null @@ -1,220 +0,0 @@ --- --- Pure Lua (5.1) implementation of BSON --- --- --- Copyright (c) 2013, Todd Coram. All rights reserved. --- See LICENSE for details. --- - -local bson = {} - --- Helper functions - -local function toLSB(bytes,value) - local res = '' - local size = bytes - local str = "" - for j=1,size do - str = str .. string.char(value % 256) - value = math.floor(value / 256) - end - return str -end - -local function toLSB32(value) return toLSB(4,value) end -local function toLSB64(value) return toLSB(8,value) end - -local function fromLSB32(s) - return s:byte(1) + (s:byte(2)*256) + - (s:byte(3)*65536) + (s:byte(4)*16777216) -end - -local function fromLSB64(s) - return fromLSB32(s) + - (s:byte(5)*4294967296) + (s:byte(6)*1099511627776) + - (s:byte(7)*2.8147497671066e+14) + (s:byte(8)*7.2057594037928e+16) -end - - --- BSON generators --- - -function bson.to_bool(n,v) - local pre = "\008"..n.."\000" - if v then - return pre.."\001" - else - return pre.."\000" - end -end - -function bson.to_str(n,v) return "\002"..n.."\000"..toLSB32(#v+1)..v.."\000" end -function bson.to_int32(n,v) return "\016"..n.."\000"..toLSB32(v) end -function bson.to_int64(n,v) return "\018"..n.."\000"..toLSB64(v) end -function bson.to_x(n,v) return v(n) end - -function bson.utc_datetime(t) - local t = t or (os.time()*1000) - f = function (n) - return "\009"..n.."\000"..toLSB64(t) - end - return f -end - --- Binary subtypes -bson.B_GENERIC = "\000" -bson.B_FUNCTION = "\001" -bson.B_UUID = "\004" -bson.B_MD5 = "\005" -bson.B_USER_DEFINED = "\128" - -function bson.binary(v, subtype) - local subtype = subtype or bson.B_GENERIC - f = function (n) - return "\005"..n.."\000"..toLSB32(#v)..subtype..v - end - return f -end - -function bson.to_num(n,v) - if math.floor(v) ~= v then - return bson.to_double(n,v) - elseif v > 2147483647 or v < -2147483648 then - return bson.to_int64(n,v) - else - return bson.to_int32(n,v) - end -end - -function bson.to_doc(n,doc) - local d=bson.start() - local doctype = "\003" - for cnt,v in ipairs(doc) do - local t = type(v) - local o = lua_to_bson_tbl[t](tostring(cnt-1),v) - d = d..o - doctype = "\004" - end - -- do this only if we don't have an array (enumerated pairs) - if d == "" then - for nm,v in pairs(doc) do - local t = type(v) - local o = lua_to_bson_tbl[t](nm,v) - d = d..o - end - end - return doctype..n.."\000"..bson.finish(d) -end - - --- Mappings between lua and BSON. --- "function" is a special catchall for non-direct mappings. --- -lua_to_bson_tbl= { - boolean = bson.to_bool, - string = bson.to_str, - number = bson.to_num, - table = bson.to_doc, - ["function"] = bson.to_x -} - --- BSON document creation. --- -function bson.start() return "" end - -function bson.finish(doc) - doc = doc .. "\000" - return toLSB32(#doc+4)..doc -end - -function bson.encode(doc) - local d=bson.start() - for e,v in pairs(doc) do - local t = type(v) - local o = lua_to_bson_tbl[t](e,v) - d = d..o - end - return bson.finish(d) -end - - --- BSON parsers - -function bson.from_bool(s) - return s:byte(1) == 1, s:sub(2) -end - -function bson.from_int32(s) - return fromLSB32(s:sub(1,4)), s:sub(5) -end - -function bson.from_int64(s) - return fromLSB64(s:sub(1,8)), s:sub(9) -end - -function bson.from_utc_date_time(s) - return fromLSB64(s:sub(1,8)), s:sub(9) -end - -function bson.from_binary(s) - local len = fromLSB32(s:sub(1,4)) - s = s:sub(6) - local str = s:sub(1,len-1) - return str, s:sub(len+1) -end - - -function bson.from_str(s) - local len = fromLSB32(s:sub(1,4)) - s = s:sub(5) - local str = s:sub(1,len-1) - return str, s:sub(len+1) -end - - -function bson.decode_doc(doc,doctype) - local luatab = {} - local len = fromLSB32(doc:sub(1,4)) - doc=doc:sub(5) - repeat - local val - local etype = doc:byte(1) - if etype == 0 then doc=doc:sub(2) break end - local ename = doc:match("(%Z+)\000",2) - doc = doc:sub(#ename+3) - val,doc = bson_to_lua_tbl[etype](doc,etype) - if doctype == 4 then - table.insert(luatab,val) - else - luatab[ename] = val - end - until not doc - return luatab,doc -end - -bson_to_lua_tbl= { - [2] = bson.from_str, - [16] = bson.from_int32, - [18] = bson.from_int64, - [8] = bson.from_bool, - [3] = bson.decode_doc, - [4] = bson.decode_doc, - [5] = bson.from_binary, - [9] = bson.from_utc_date_time -} - -function bson.decode(doc) - a,d=bson.decode_doc(doc,nil) - return a,d -end - -function bson.decode_next_io(fd) - local slen = fd:read(4) - if not slen then return nil end - local len = fromLSB32(slen) - 4 - local doc = fd:read(len) - return bson.decode(slen..doc) -end - - -return bson diff --git a/lib/resty/mongol/bson.lua b/lib/resty/mongol/bson.lua index 68a5577..6e590a0 100755 --- a/lib/resty/mongol/bson.lua +++ b/lib/resty/mongol/bson.lua @@ -7,10 +7,13 @@ local type = type local tonumber , tostring = tonumber , tostring local t_insert = table.insert local t_concat = table.concat +local t_maxn = table.maxn local strformat = string.format local strmatch = string.match local strbyte = string.byte +local Array = Array + local ll = require ( mod_name .. ".ll" ) local le_uint_to_num = ll.le_uint_to_num local le_int_to_num = ll.le_int_to_num @@ -19,114 +22,176 @@ local num_to_le_int = ll.num_to_le_int local from_double = ll.from_double local to_double = ll.to_double -local getlib = require ( mod_name .. ".get" ) +local getlib = require(mod_name..".get") local read_terminated_string = getlib.read_terminated_string -local obid = require ( mod_name .. ".object_id" ) -local nbson = require ( mod_name .. ".bson-lua.bson" ) -local new_object_id = obid.new -local object_id_mt = obid.metatable +local ObjectId = require(mod_name..".ObjectId") local binary_mt = {} local utc_date = {} - -local function read_document ( get , numerical ) - local bytes = le_uint_to_num ( get ( 4 ) ) - - local ho , hk , hv = false , false , false - local t = { } - while true do - local op = get ( 1 ) - if op == "\0" then break end - - local e_name = read_terminated_string ( get ) - local v - if op == "\1" then -- Double - v = from_double ( get ( 8 ) ) - elseif op == "\2" then -- String - local len = le_uint_to_num ( get ( 4 ) ) - v = get ( len - 1 ) - assert ( get ( 1 ) == "\0" ) - elseif op == "\3" then -- Embedded document - v = read_document ( get , false ) - elseif op == "\4" then -- Array - v = read_document ( get , true ) - elseif op == "\5" then -- Binary - local len = le_uint_to_num ( get ( 4 ) ) - local subtype = get ( 1 ) - v = get ( len ) - elseif op == "\7" then -- ObjectId - v = new_object_id ( get ( 12 ) ) - elseif op == "\8" then -- false - local f = get ( 1 ) - if f == "\0" then - v = false - elseif f == "\1" then - v = true - else - error ( f:byte ( ) ) - end - elseif op == "\9" then -- UTC datetime milliseconds - v = le_uint_to_num ( get ( 8 ) , 1 , 8 ) - elseif op == "\10" then -- Null - v = nil - elseif op == "\16" then --int32 - v = le_int_to_num ( get ( 4 ) , 1 , 8 ) - elseif op == "\17" then --int64 - v = le_int_to_num(get(8), 1, 8) - elseif op == "\18" then --int64 - v = le_int_to_num(get(8), 1, 8) - else - error ( "Unknown BSON type: " .. strbyte ( op ) ) - end - - if numerical then - t [ tonumber ( e_name ) ] = v - else - t [ e_name ] = v - end - - -- Check for special universal map - if e_name == "_keys" then - hk = v - elseif e_name == "_vals" then - hv = v - else - ho = true - end - end - - if not ho and hk and hv then - t = { } - for i=1,#hk do - t [ hk [ i ] ] = hv [ i ] - end - end - - return t +local function read_document(get, numerical) + local bytes = le_uint_to_num(get(4)) + + local t = {} + while true do + local op = get(1) + if op == "\0" then break end + + local e_name = read_terminated_string(get) + local v + if op == "\1" then -- Double + v = from_double(get(8)) + elseif op == "\2" then -- String + local len = le_uint_to_num(get(4)) + v = get(len - 1) + assert(get(1) == "\0") + elseif op == "\3" then -- Embedded document + v = read_document(get, false) + elseif op == "\4" then -- Array + v = read_document(get, true) + if Array then + v = Array(v) + end + elseif op == "\5" then -- Binary + local len = le_uint_to_num(get(4)) + local subtype = get(1) + v = get(len) + elseif op == "\7" then -- ObjectId + v = ObjectId(get(12)) + elseif op == "\8" then -- false + local f = get(1) + if f == "\0" then + v = false + elseif f == "\1" then + v = true + else + error(f:byte()) + end + elseif op == "\9" then -- UTC datetime milliseconds + v = le_uint_to_num(get(8), 1, 8) + elseif op == "\10" then -- Null + v = nil + elseif op == "\16" then --int32 + v = le_int_to_num(get(4), 1, 8) + elseif op == "\17" then --int64 // timestamp + v = le_int_to_num(get(8), 1, 8) + elseif op == "\18" then --int64 + v = le_int_to_num(get(8), 1, 8) + else + error ( "Unknown BSON type: " .. strbyte(op)) + end + + if numerical then + t[tonumber(e_name) + 1] = v + else + t[e_name] = v + end + end + return t end local function get_utc_date(v) - return setmetatable({v = v}, utc_date) + return setmetatable({v = v}, utc_date) end local function get_bin_data(v) - return setmetatable({v = v, st = "\0"}, binary_mt) + return setmetatable({v = v, st = "\0"}, binary_mt) end -local function from_bson ( get ) - local t = read_document ( get , false ) - return t +local function from_bson(get) + return read_document(get, false) end local to_bson +local function pack(k, v) + local ot = type(v) + local mt = getmetatable(v) + + if ot == "number" then + if math.floor(v) ~= v then + return "\1" .. k .. "\0" .. to_double ( v ) + elseif v > 2147483647 or v < -2147483648 then -- 64bit + return "\18" .. k .. "\0" .. num_to_le_int ( v , 8 ) + else -- 32bit + return "\16" .. k .. "\0" .. num_to_le_int ( v , 4 ) + end + elseif ot == "nil" then + return "\10" .. k .. "\0" + elseif ot == "userdata" then + return "\10" .. k .. "\0" + elseif ot == "string" then + return "\2" .. k .. "\0" .. num_to_le_uint ( #v + 1 ) .. v .. "\0" + elseif ot == "boolean" then + if v == false then + return "\8" .. k .. "\0\0" + else + return "\8" .. k .. "\0\1" + end + elseif mt == ObjectId then + return "\7" .. k .. "\0" .. v.id + elseif mt == utc_date then + return "\9" .. k .. "\0" .. num_to_le_int(v.v, 8) + elseif mt == binary_mt then + return "\5" .. k .. "\0" .. num_to_le_uint(string.len(v.v)) .. + v.st .. v.v + elseif ot == "table" then + local doc , array = to_bson(v) + if array then + return "\4" .. k .. "\0" .. doc + else + return "\3" .. k .. "\0" .. doc + end + else + error ( "Failure converting " .. ot ..": " .. tostring ( v ) ) + end +end + function to_bson(ob) - return nbson.encode(ob) + -- Find out if ob if an array; or a table + local is_array = true + local max = 0 + if Array then + if getmetatable(ob) == Array then + max = t_maxn(ob) + else + is_array = false + end + else + for k, v in pairs(ob) do + local t_k = type(k) + if is_array then + if t_k == "number" and k >= 1 then + if k >= max then + max = k + end + else + is_array = false + end + end + if not is_array then break end + end + end + + local m + if is_array then + local r = {} + for i = 1, max do + r[i] = pack(i - 1, ob[i]) + end + m = t_concat(r, "", 1, max) + else + local r = {} + for k, v in pairs(ob) do + t_insert(r, pack(tostring(k), v)) + end + m = t_concat(r) + end + return num_to_le_uint(#m + 4 + 1 )..m.."\0", is_array end return { - from_bson = from_bson ; - to_bson = to_bson ; - get_bin_data = get_bin_data; - get_utc_date = get_utc_date; + from_bson = from_bson; + to_bson = to_bson; + get_bin_data = get_bin_data; + get_utc_date = get_utc_date; } diff --git a/lib/resty/mongol/colmt.lua b/lib/resty/mongol/colmt.lua index e09ba36..187485c 100755 --- a/lib/resty/mongol/colmt.lua +++ b/lib/resty/mongol/colmt.lua @@ -93,7 +93,7 @@ local function handle_reply ( conn , req_id , offset_i ) local r = { } for i = 1 , t.numberReturned do - r[i] = from_bson(get) + r[i] = from_bson(get) end return cursorid, r, t diff --git a/lib/resty/mongol/gridfs.lua b/lib/resty/mongol/gridfs.lua index ff8eb07..2725134 100644 --- a/lib/resty/mongol/gridfs.lua +++ b/lib/resty/mongol/gridfs.lua @@ -1,10 +1,10 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) +local mod_name = (...):match( "^(.*)%..-$" ) local md5 = require "resty.md5" local str = require "resty.string" -local bson = require ( mod_name .. ".bson" ) -local object_id = require ( mod_name .. ".object_id" ) -local gridfs_file= require ( mod_name .. ".gridfs_file" ) +local bson = require(mod_name..".bson") +local ObjectId = require(mod_name..".ObjectId") +local gridfs_file= require(mod_name..".gridfs_file") local gridfs_mt = { } local gridfs = { __index = gridfs_mt } @@ -57,7 +57,7 @@ end function gridfs_mt:new(meta) meta = meta or {} - meta._id = meta._id or object_id.new() + meta._id = meta._id or ObjectId() meta.chunkSize = meta.chunkSize or 256*1024 meta.filename = meta.filename or meta._id:tostring() @@ -81,7 +81,7 @@ end function gridfs_mt:insert(fh, meta, safe) meta = meta or {} meta.chunkSize = meta.chunkSize or 256*1024 - meta._id = meta._id or object_id.new() + meta._id = meta._id or ObjectId() meta.filename = meta.filename or meta._id:tostring() local n = 0 diff --git a/lib/resty/mongol/gridfs_file.lua b/lib/resty/mongol/gridfs_file.lua index 4a99e16..4e09ecd 100644 --- a/lib/resty/mongol/gridfs_file.lua +++ b/lib/resty/mongol/gridfs_file.lua @@ -1,8 +1,8 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) +local mod_name = (...):match( "^(.*)%..-$" ) local md5 = require "resty.md5" local str = require "resty.string" -local bson = require ( mod_name .. ".bson" ) +local bson = require(mod_name..".bson") local gridfs_file_mt = { } local gridfs_file = { __index = gridfs_file_mt } @@ -129,6 +129,8 @@ function gridfs_file_mt:write(buf, offset, size) r,err = self.file_col:update({_id = self.files_id},nv, 0, 0, true) if not r then return nil,"write failed: "..err end + + self.file_size = nf end nv["$set"] = {md5 = 0} diff --git a/lib/resty/mongol/ll.lua b/lib/resty/mongol/ll.lua index ec06645..49312c9 100644 --- a/lib/resty/mongol/ll.lua +++ b/lib/resty/mongol/ll.lua @@ -31,7 +31,6 @@ local num_to_le_uint = function ( n , bytes ) for i=1 , bytes do b [ i ] , n = n % 2^8 , floor ( n / 2^8 ) end - assert ( n == 0 ) return strchar ( unpack ( b ) ) end local num_to_le_int = function ( n , bytes ) @@ -57,7 +56,6 @@ local num_to_be_uint = function ( n , bytes ) for i=bytes , 1 , -1 do b [ i ] , n = n % 2^8 , floor ( n / 2^8 ) end - assert ( n == 0 ) return strchar ( unpack ( b ) ) end diff --git a/lib/resty/mongol/misc.lua b/lib/resty/mongol/misc.lua index e676843..812e9d5 100755 --- a/lib/resty/mongol/misc.lua +++ b/lib/resty/mongol/misc.lua @@ -1,12 +1,11 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) +local mod_name = (...):match("^(.*)%..-$") -local ll = require ( mod_name .. ".ll" ) +local ll = require(mod_name..".ll") local num_to_le_uint = ll.num_to_le_uint local num_to_le_int = ll.num_to_le_int local le_uint_to_num = ll.le_uint_to_num local le_bpeek = ll.le_bpeek - local getmetatable , setmetatable = getmetatable , setmetatable local pairs = pairs local next = next diff --git a/lib/resty/mongol/object_id.lua b/lib/resty/mongol/object_id.lua deleted file mode 100755 index fc3f2bb..0000000 --- a/lib/resty/mongol/object_id.lua +++ /dev/null @@ -1,83 +0,0 @@ -local mod_name = (...):match ( "^(.*)%..-$" ) - -local setmetatable = setmetatable -local strbyte = string.byte -local strformat = string.format -local t_insert = table.insert -local t_concat = table.concat - -local hasposix , posix = pcall ( require , "posix" ) - -local ll = require ( mod_name .. ".ll" ) -local num_to_le_uint = ll.num_to_le_uint -local num_to_be_uint = ll.num_to_be_uint - -local function _tostring(ob) - local t = {} - for i = 1 , 12 do - t_insert(t, strformat("%02x", strbyte(ob.id, i, i))) - end - return t_concat(t) -end - -local function _get_ts(ob) - return ll.be_uint_to_num(ob.id, 1, 4) -end - -local function _get_hostname(ob) - local t = {} - for i = 5, 7 do - t_insert(t, strformat("%02x", strbyte(ob.id, i, i))) - end - return t_concat(t) -end - -local function _get_pid(ob) - return ll.be_uint_to_num(ob.id, 8, 9) -end - -local function _get_inc(ob) - return ll.be_uint_to_num(ob.id, 10, 12) -end - -local object_id_mt = { - __tostring = _tostring; - __eq = function ( a , b ) return a.id == b.id end ; -} - -local machineid -if hasposix then - machineid = posix.uname("%n") -else - machineid = assert(io.popen("uname -n")):read("*l") -end -machineid = ngx.md5_bin(machineid):sub(1, 3) - -local pid = num_to_le_uint(ngx.var.pid, 2) - -local inc = 0 -local function generate_id ( ) - inc = inc + 1 - -- "A BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Note that the timestamp and counter fields must be stored big endian unlike the rest of BSON" - return num_to_be_uint ( os.time ( ) , 4 ) .. machineid .. pid .. num_to_be_uint ( inc , 3 ) -end - -local function new_object_id(str) - if str then - assert(#str == 12) - else - str = generate_id() - end - return setmetatable({id = str, - tostring = _tostring, - get_ts = _get_ts, - get_pid = _get_pid, - get_hostname = _get_hostname, - get_inc = _get_inc, - } , object_id_mt) -end - -return { - new = new_object_id ; - metatable = object_id_mt ; -} diff --git a/t/cluster.t b/t/cluster.t new file mode 100644 index 0000000..9415203 --- /dev/null +++ b/t/cluster.t @@ -0,0 +1,190 @@ +# vim:set ft= ts=4 sw=4 et: + +use Test::Nginx::Socket; +use Cwd qw(cwd); + +repeat_each(1); + +plan tests => repeat_each() * (3 * blocks()); + +my $pwd = cwd(); + +our $HttpConfig = qq{ + lua_package_path "$pwd/lib/?/init.lua;;"; +}; + +$ENV{TEST_NGINX_RESOLVER} = '8.8.8.8'; +$ENV{TEST_NGINX_MONGO_PORT} ||= 27017; + +no_long_string(); +#no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 2: db auth failed +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(1000) + + ok, err = conn:connect("10.6.2.51") + if not ok then + ngx.say("connect failed: "..err) + end + + local db = conn:new_db_handle("test") + local r,err = db:auth("admin", "pass") + if not r then ngx.say(err) + else + ngx.say(r) + end + '; + } +--- request +GET /t +--- response_body +auth fails +--- no_error_log +[error] + +=== TEST 5: is master +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(1000) + + ok, err = conn:connect("10.6.2.51") + if not ok then + ngx.say("connect failed: "..err) + end + + r, h = conn:ismaster() + if not r then + ngx.say("query master failed: "..h) + end + + ngx.say(r) + for i,v in pairs(h) do + ngx.say(v) + end + conn:close() + '; + } +--- request +GET /t +--- response_body_like +true +--- no_error_log +[error] + +=== TEST 6: is not master +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(1000) + + ok, err = conn:connect("10.6.2.51", 27018) + if not ok then + ngx.say("connect failed: "..err) + end + + r, h = conn:ismaster() + if r == nil then + ngx.say("query master failed: "..h) + end + + ngx.say(r) + for i,v in pairs(h) do + ngx.say(v) + end + conn:close() + '; + } +--- request +GET /t +--- response_body_like +false +--- no_error_log +[error] + +=== TEST 7: get primary +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(1000) + + ok, err = conn:connect("10.6.2.51", 27018) + if not ok then + ngx.say("connect failed: "..err) + end + + r, h = conn:ismaster() + if r == nil then + ngx.say("query master failed: "..h) + end + + if r then ngx.say("already master") return end + + newconn,err = conn:getprimary() + if not newconn then + ngx.say("get primary failed: "..err) + end + r, h = newconn:ismaster() + if not r then + ngx.say("get master failed") + end + + ngx.say("get primary") + conn:close() + '; + } +--- request +GET /t +--- response_body +get primary +--- no_error_log +[error] + +=== TEST 8: db auth +--- http_config eval: $::HttpConfig +--- config + lua_code_cache off; + location /t { + content_by_lua ' + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(1000) + + ok, err = conn:connect("10.6.2.51") + if not ok then + ngx.say("connect failed: "..err) + end + + local db = conn:new_db_handle("test") + local r,err = db:auth("admin", "admin") + if not r then ngx.say("auth failed") end + ngx.say(r) + '; + } +--- request +GET /t +--- response_body +1 +--- no_error_log +[error] + + diff --git a/t/cursor.t b/t/cursor.t index f86e92b..563a05a 100644 --- a/t/cursor.t +++ b/t/cursor.t @@ -86,9 +86,6 @@ GET /t 3 1 2 -3 -4 -5 --- no_error_log [error] @@ -258,3 +255,76 @@ sort failed: sort must be an array --- no_error_log [error] +=== TEST 4: cursor next over limit +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(10000) + local ok, err = conn:connect("10.6.2.51") + + if not ok then + ngx.say("connect failed: "..err) + end + + local db = conn:new_db_handle("test") + local r = db:auth("admin", "admin") + if not r then ngx.say("auth failed") end + local col = db:get_col("test") + + r, err = col:delete({}, nil, true) + if not r then ngx.say("delete failed: "..err) end + + local i, j + local t = {} + for i = 1,10 do + j = 100 - i + table.insert(t, {name="dog",n=i,m=j}) + end + r, err = col:insert(t, nil, true) + if not r then ngx.say("insert failed: "..err) end + + r = col:find({name="dog"}) + r:limit(3) + for i , v in r:pairs() do + ngx.say(v["n"]) + end + + k,v = r:next() + ngx.say(v) + + r = col:find({name="dog"}) + for i = 1, 10 do + k,v = r:next() + ngx.say(v["n"]) + end + + i,v = r:next() + ngx.say(v) + + conn:close() + '; + } +--- request +GET /t +--- response_body +1 +2 +3 +nil +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +nil +--- no_error_log +[error] + diff --git a/t/gridfs_write.t b/t/gridfs_write.t index c370016..6fef49f 100644 --- a/t/gridfs_write.t +++ b/t/gridfs_write.t @@ -5,7 +5,7 @@ use Cwd qw(cwd); repeat_each(1); -plan tests => repeat_each() * (4 * blocks()); +plan tests => repeat_each() * (4 * blocks()) - 1; my $pwd = cwd(); @@ -768,7 +768,6 @@ GET /t --- output_files >>> /tmp/testfile chop ABCDEFGHIJKLMNOPQRST ---- ONLY --- no_error_log [error] diff --git a/t/sanity.t b/t/sanity.t index 02b5ec3..b58c29a 100644 --- a/t/sanity.t +++ b/t/sanity.t @@ -62,41 +62,12 @@ __DATA__ --- request GET /t --- response_body -insert failed: unauthorized +insert failed: need to login 0 dog --- no_error_log [error] -=== TEST 2: db auth failed ---- http_config eval: $::HttpConfig ---- config - location /t { - content_by_lua ' - local mongo = require "resty.mongol" - conn = mongo:new() - conn:set_timeout(1000) - - ok, err = conn:connect("10.6.2.51") - if not ok then - ngx.say("connect failed: "..err) - end - - local db = conn:new_db_handle("test") - local r,err = db:auth("admin", "pass") - if not r then ngx.say(err) - else - ngx.say(r) - end - '; - } ---- request -GET /t ---- response_body -auth fails ---- no_error_log -[error] - === TEST 3: socket failed --- http_config eval: $::HttpConfig --- config @@ -154,140 +125,6 @@ GET /t --- no_error_log [error] -=== TEST 5: is master ---- http_config eval: $::HttpConfig ---- config - location /t { - content_by_lua ' - local mongo = require "resty.mongol" - conn = mongo:new() - conn:set_timeout(1000) - - ok, err = conn:connect("10.6.2.51") - if not ok then - ngx.say("connect failed: "..err) - end - - r, h = conn:ismaster() - if not r then - ngx.say("query master failed: "..h) - end - - ngx.say(r) - for i,v in pairs(h) do - ngx.say(v) - end - conn:close() - '; - } ---- request -GET /t ---- response_body_like -true ---- no_error_log -[error] - -=== TEST 6: is not master ---- http_config eval: $::HttpConfig ---- config - location /t { - content_by_lua ' - local mongo = require "resty.mongol" - conn = mongo:new() - conn:set_timeout(1000) - - ok, err = conn:connect("10.6.2.51", 27018) - if not ok then - ngx.say("connect failed: "..err) - end - - r, h = conn:ismaster() - if r == nil then - ngx.say("query master failed: "..h) - end - - ngx.say(r) - for i,v in pairs(h) do - ngx.say(v) - end - conn:close() - '; - } ---- request -GET /t ---- response_body_like -false ---- no_error_log -[error] - -=== TEST 7: get primary ---- http_config eval: $::HttpConfig ---- config - location /t { - content_by_lua ' - local mongo = require "resty.mongol" - conn = mongo:new() - conn:set_timeout(1000) - - ok, err = conn:connect("10.6.2.51", 27018) - if not ok then - ngx.say("connect failed: "..err) - end - - r, h = conn:ismaster() - if r == nil then - ngx.say("query master failed: "..h) - end - - if r then ngx.say("already master") return end - - newconn,err = conn:getprimary() - if not newconn then - ngx.say("get primary failed: "..err) - end - r, h = newconn:ismaster() - if not r then - ngx.say("get master failed") - end - - ngx.say("get primary") - conn:close() - '; - } ---- request -GET /t ---- response_body -get primary ---- no_error_log -[error] - -=== TEST 8: db auth ---- http_config eval: $::HttpConfig ---- config - lua_code_cache off; - location /t { - content_by_lua ' - local mongo = require "resty.mongol" - conn = mongo:new() - conn:set_timeout(1000) - - ok, err = conn:connect("10.6.2.51") - if not ok then - ngx.say("connect failed: "..err) - end - - local db = conn:new_db_handle("test") - local r,err = db:auth("admin", "admin") - if not r then ngx.say("auth failed") end - ngx.say(r) - '; - } ---- request -GET /t ---- response_body -1 ---- no_error_log -[error] === TEST 9: col count --- http_config eval: $::HttpConfig @@ -341,6 +178,7 @@ GET /t local db = conn:new_db_handle("test") local col = db:get_col("test") + r,err = col:update({name="dog"},{name="cat"}, nil, nil, true) if not r then ngx.say("update failed: "..err) end @@ -393,7 +231,7 @@ GET /t --- request GET /t --- response_body -update failed: unauthorized +update failed: need to login 1 cat 1 @@ -443,7 +281,7 @@ cat --- request GET /t --- response_body -10 +4 --- no_error_log [error] @@ -471,17 +309,17 @@ GET /t col = db:get_col("test") col:delete({name="puppy"}) - for i = 1, 3 do + for i = 1, 10 do col:insert({{name="puppy", n=i, m="foo"}}) end - r = col:find({name="puppy"}, {n=0}, 4) + r = col:find({name="puppy"}, {n=0}, 3) for i , v in r:pairs() do ngx.say(v["n"]) ngx.say(v["name"]) end - r = col:find({name="puppy"}, {n=1}, 4) + r = col:find({name="puppy"}, {n=1}, 3) for i , v in r:pairs() do ngx.say(v["n"]) ngx.say(v["name"]) @@ -677,7 +515,7 @@ not found --- request GET /t --- response_body -delete failed: unauthorized +delete failed: need to login 3 1 -1 @@ -962,3 +800,50 @@ GET /t --- no_error_log [error] +=== TEST 21: query by skip and retnum +--- http_config eval: $::HttpConfig +--- config + location /t { + content_by_lua ' + local mongo = require "resty.mongol" + conn = mongo:new() + conn:set_timeout(10000) + ok, err = conn:connect("10.6.2.51") + + if not ok then + ngx.say("connect failed: "..err) + end + + local db = conn:new_db_handle("test") + local col = db:get_col("test") + + r = db:auth("admin", "admin") + if not r then ngx.say("auth failed") end + + r, err = col:delete({}, nil, true) + if not r then ngx.say("delete failed: "..err) end + + local t = {a=1,b=2} + + for i = 1, 10 do + col:insert({{name="puppy"}}) + end + + sel = {name="puppy"} + id, results, t = col:query(sel,{_id=1},0,1) + ngx.say(#results) + + id, results, t = col:query(sel,{_id=1},5,5) + ngx.say(#results) + + conn:close() + '; + } +--- request +GET /t +--- response_body +1 +5 +--- no_error_log +[error] +