Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
04340e1f
Commit
04340e1f
authored
Aug 03, 2016
by
antirez
Browse files
Modules: initial draft for a testing module.
parent
7829e4ed
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/module.c
View file @
04340e1f
...
@@ -766,6 +766,10 @@ const char *RM_StringPtrLen(const RedisModuleString *str, size_t *len) {
...
@@ -766,6 +766,10 @@ const char *RM_StringPtrLen(const RedisModuleString *str, size_t *len) {
return
str
->
ptr
;
return
str
->
ptr
;
}
}
/* --------------------------------------------------------------------------
* Higher level string operations
* ------------------------------------------------------------------------- */
/* Convert the string into a long long integer, storing it at `*ll`.
/* Convert the string into a long long integer, storing it at `*ll`.
* Returns REDISMODULE_OK on success. If the string can't be parsed
* Returns REDISMODULE_OK on success. If the string can't be parsed
* as a valid, strict long long (no spaces before/after), REDISMODULE_ERR
* as a valid, strict long long (no spaces before/after), REDISMODULE_ERR
...
@@ -783,6 +787,13 @@ int RM_StringToDouble(const RedisModuleString *str, double *d) {
...
@@ -783,6 +787,13 @@ int RM_StringToDouble(const RedisModuleString *str, double *d) {
return
(
retval
==
C_OK
)
?
REDISMODULE_OK
:
REDISMODULE_ERR
;
return
(
retval
==
C_OK
)
?
REDISMODULE_OK
:
REDISMODULE_ERR
;
}
}
/* Compare two string objects, returning -1, 0 or 1 respectively if
* a < b, a == b, a > b. Strings are compared byte by byte as two
* binary blobs without any encoding care / collation attempt. */
int
RM_StringCompare
(
RedisModuleString
*
a
,
RedisModuleString
*
b
)
{
return
compareStringObjects
(
a
,
b
);
}
/* Return the (possibly modified in encoding) input 'str' object if
/* Return the (possibly modified in encoding) input 'str' object if
* the string is unshared, otherwise NULL is returned. */
* the string is unshared, otherwise NULL is returned. */
RedisModuleString
*
moduleAssertUnsharedString
(
RedisModuleString
*
str
)
{
RedisModuleString
*
moduleAssertUnsharedString
(
RedisModuleString
*
str
)
{
...
@@ -2940,100 +2951,9 @@ int moduleRegisterApi(const char *funcname, void *funcptr) {
...
@@ -2940,100 +2951,9 @@ int moduleRegisterApi(const char *funcname, void *funcptr) {
#define REGISTER_API(name) \
#define REGISTER_API(name) \
moduleRegisterApi("RedisModule_" #name, (void *)(unsigned long)RM_ ## name)
moduleRegisterApi("RedisModule_" #name, (void *)(unsigned long)RM_ ## name)
/* Register all the APIs we export. */
void
moduleRegisterCoreAPI
(
void
)
{
server
.
moduleapi
=
dictCreate
(
&
moduleAPIDictType
,
NULL
);
REGISTER_API
(
Alloc
);
REGISTER_API
(
Calloc
);
REGISTER_API
(
Realloc
);
REGISTER_API
(
Free
);
REGISTER_API
(
Strdup
);
REGISTER_API
(
CreateCommand
);
REGISTER_API
(
SetModuleAttribs
);
REGISTER_API
(
WrongArity
);
REGISTER_API
(
ReplyWithLongLong
);
REGISTER_API
(
ReplyWithError
);
REGISTER_API
(
ReplyWithSimpleString
);
REGISTER_API
(
ReplyWithArray
);
REGISTER_API
(
ReplySetArrayLength
);
REGISTER_API
(
ReplyWithString
);
REGISTER_API
(
ReplyWithStringBuffer
);
REGISTER_API
(
ReplyWithNull
);
REGISTER_API
(
ReplyWithCallReply
);
REGISTER_API
(
ReplyWithDouble
);
REGISTER_API
(
GetSelectedDb
);
REGISTER_API
(
SelectDb
);
REGISTER_API
(
OpenKey
);
REGISTER_API
(
CloseKey
);
REGISTER_API
(
KeyType
);
REGISTER_API
(
ValueLength
);
REGISTER_API
(
ListPush
);
REGISTER_API
(
ListPop
);
REGISTER_API
(
StringToLongLong
);
REGISTER_API
(
StringToDouble
);
REGISTER_API
(
Call
);
REGISTER_API
(
CallReplyProto
);
REGISTER_API
(
FreeCallReply
);
REGISTER_API
(
CallReplyInteger
);
REGISTER_API
(
CallReplyType
);
REGISTER_API
(
CallReplyLength
);
REGISTER_API
(
CallReplyArrayElement
);
REGISTER_API
(
CallReplyStringPtr
);
REGISTER_API
(
CreateStringFromCallReply
);
REGISTER_API
(
CreateString
);
REGISTER_API
(
CreateStringFromLongLong
);
REGISTER_API
(
CreateStringFromString
);
REGISTER_API
(
FreeString
);
REGISTER_API
(
StringPtrLen
);
REGISTER_API
(
AutoMemory
);
REGISTER_API
(
Replicate
);
REGISTER_API
(
ReplicateVerbatim
);
REGISTER_API
(
DeleteKey
);
REGISTER_API
(
StringSet
);
REGISTER_API
(
StringDMA
);
REGISTER_API
(
StringTruncate
);
REGISTER_API
(
SetExpire
);
REGISTER_API
(
GetExpire
);
REGISTER_API
(
ZsetAdd
);
REGISTER_API
(
ZsetIncrby
);
REGISTER_API
(
ZsetScore
);
REGISTER_API
(
ZsetRem
);
REGISTER_API
(
ZsetRangeStop
);
REGISTER_API
(
ZsetFirstInScoreRange
);
REGISTER_API
(
ZsetLastInScoreRange
);
REGISTER_API
(
ZsetFirstInLexRange
);
REGISTER_API
(
ZsetLastInLexRange
);
REGISTER_API
(
ZsetRangeCurrentElement
);
REGISTER_API
(
ZsetRangeNext
);
REGISTER_API
(
ZsetRangePrev
);
REGISTER_API
(
ZsetRangeEndReached
);
REGISTER_API
(
HashSet
);
REGISTER_API
(
HashGet
);
REGISTER_API
(
IsKeysPositionRequest
);
REGISTER_API
(
KeyAtPos
);
REGISTER_API
(
GetClientId
);
REGISTER_API
(
PoolAlloc
);
REGISTER_API
(
CreateDataType
);
REGISTER_API
(
ModuleTypeSetValue
);
REGISTER_API
(
ModuleTypeGetType
);
REGISTER_API
(
ModuleTypeGetValue
);
REGISTER_API
(
SaveUnsigned
);
REGISTER_API
(
LoadUnsigned
);
REGISTER_API
(
SaveSigned
);
REGISTER_API
(
LoadSigned
);
REGISTER_API
(
SaveString
);
REGISTER_API
(
SaveStringBuffer
);
REGISTER_API
(
LoadString
);
REGISTER_API
(
LoadStringBuffer
);
REGISTER_API
(
SaveDouble
);
REGISTER_API
(
LoadDouble
);
REGISTER_API
(
EmitAOF
);
REGISTER_API
(
Log
);
REGISTER_API
(
StringAppendBuffer
);
REGISTER_API
(
RetainString
);
}
/* Global initialization at Redis startup. */
/* Global initialization at Redis startup. */
void
moduleRegisterCoreAPI
(
void
);
void
moduleInitModulesSystem
(
void
)
{
void
moduleInitModulesSystem
(
void
)
{
server
.
loadmodule_queue
=
listCreate
();
server
.
loadmodule_queue
=
listCreate
();
modules
=
dictCreate
(
&
modulesDictType
,
NULL
);
modules
=
dictCreate
(
&
modulesDictType
,
NULL
);
...
@@ -3222,3 +3142,98 @@ void moduleCommand(client *c) {
...
@@ -3222,3 +3142,98 @@ void moduleCommand(client *c) {
addReply
(
c
,
shared
.
syntaxerr
);
addReply
(
c
,
shared
.
syntaxerr
);
}
}
}
}
/* Register all the APIs we export. Keep this function at the end of the
* file so that's easy to seek it to add new entries. */
void
moduleRegisterCoreAPI
(
void
)
{
server
.
moduleapi
=
dictCreate
(
&
moduleAPIDictType
,
NULL
);
REGISTER_API
(
Alloc
);
REGISTER_API
(
Calloc
);
REGISTER_API
(
Realloc
);
REGISTER_API
(
Free
);
REGISTER_API
(
Strdup
);
REGISTER_API
(
CreateCommand
);
REGISTER_API
(
SetModuleAttribs
);
REGISTER_API
(
WrongArity
);
REGISTER_API
(
ReplyWithLongLong
);
REGISTER_API
(
ReplyWithError
);
REGISTER_API
(
ReplyWithSimpleString
);
REGISTER_API
(
ReplyWithArray
);
REGISTER_API
(
ReplySetArrayLength
);
REGISTER_API
(
ReplyWithString
);
REGISTER_API
(
ReplyWithStringBuffer
);
REGISTER_API
(
ReplyWithNull
);
REGISTER_API
(
ReplyWithCallReply
);
REGISTER_API
(
ReplyWithDouble
);
REGISTER_API
(
GetSelectedDb
);
REGISTER_API
(
SelectDb
);
REGISTER_API
(
OpenKey
);
REGISTER_API
(
CloseKey
);
REGISTER_API
(
KeyType
);
REGISTER_API
(
ValueLength
);
REGISTER_API
(
ListPush
);
REGISTER_API
(
ListPop
);
REGISTER_API
(
StringToLongLong
);
REGISTER_API
(
StringToDouble
);
REGISTER_API
(
Call
);
REGISTER_API
(
CallReplyProto
);
REGISTER_API
(
FreeCallReply
);
REGISTER_API
(
CallReplyInteger
);
REGISTER_API
(
CallReplyType
);
REGISTER_API
(
CallReplyLength
);
REGISTER_API
(
CallReplyArrayElement
);
REGISTER_API
(
CallReplyStringPtr
);
REGISTER_API
(
CreateStringFromCallReply
);
REGISTER_API
(
CreateString
);
REGISTER_API
(
CreateStringFromLongLong
);
REGISTER_API
(
CreateStringFromString
);
REGISTER_API
(
FreeString
);
REGISTER_API
(
StringPtrLen
);
REGISTER_API
(
AutoMemory
);
REGISTER_API
(
Replicate
);
REGISTER_API
(
ReplicateVerbatim
);
REGISTER_API
(
DeleteKey
);
REGISTER_API
(
StringSet
);
REGISTER_API
(
StringDMA
);
REGISTER_API
(
StringTruncate
);
REGISTER_API
(
SetExpire
);
REGISTER_API
(
GetExpire
);
REGISTER_API
(
ZsetAdd
);
REGISTER_API
(
ZsetIncrby
);
REGISTER_API
(
ZsetScore
);
REGISTER_API
(
ZsetRem
);
REGISTER_API
(
ZsetRangeStop
);
REGISTER_API
(
ZsetFirstInScoreRange
);
REGISTER_API
(
ZsetLastInScoreRange
);
REGISTER_API
(
ZsetFirstInLexRange
);
REGISTER_API
(
ZsetLastInLexRange
);
REGISTER_API
(
ZsetRangeCurrentElement
);
REGISTER_API
(
ZsetRangeNext
);
REGISTER_API
(
ZsetRangePrev
);
REGISTER_API
(
ZsetRangeEndReached
);
REGISTER_API
(
HashSet
);
REGISTER_API
(
HashGet
);
REGISTER_API
(
IsKeysPositionRequest
);
REGISTER_API
(
KeyAtPos
);
REGISTER_API
(
GetClientId
);
REGISTER_API
(
PoolAlloc
);
REGISTER_API
(
CreateDataType
);
REGISTER_API
(
ModuleTypeSetValue
);
REGISTER_API
(
ModuleTypeGetType
);
REGISTER_API
(
ModuleTypeGetValue
);
REGISTER_API
(
SaveUnsigned
);
REGISTER_API
(
LoadUnsigned
);
REGISTER_API
(
SaveSigned
);
REGISTER_API
(
LoadSigned
);
REGISTER_API
(
SaveString
);
REGISTER_API
(
SaveStringBuffer
);
REGISTER_API
(
LoadString
);
REGISTER_API
(
LoadStringBuffer
);
REGISTER_API
(
SaveDouble
);
REGISTER_API
(
LoadDouble
);
REGISTER_API
(
EmitAOF
);
REGISTER_API
(
Log
);
REGISTER_API
(
StringAppendBuffer
);
REGISTER_API
(
RetainString
);
REGISTER_API
(
StringCompare
);
}
src/modules/testmodule.c
0 → 100644
View file @
04340e1f
/* Module designed to test the Redis modules subsystem.
*
* -----------------------------------------------------------------------------
*
* Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "../redismodule.h"
/* ------------------------------- Test units ------------------------------- */
/* TEST.STRING.APPEND -- Test appending to an existing string object. */
int
TestStringAppend
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
RedisModuleString
*
s
=
RedisModule_CreateString
(
ctx
,
"foo"
,
3
);
RedisModule_StringAppendBuffer
(
ctx
,
s
,
"bar"
,
3
);
RedisModule_ReplyWithString
(
ctx
,
s
);
RedisModule_FreeString
(
ctx
,
s
);
return
REDISMODULE_OK
;
}
/* TEST.STRING.APPEND.AM -- Test append with retain when auto memory is on. */
int
TestStringAppendAM
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
RedisModule_AutoMemory
(
ctx
);
RedisModuleString
*
s
=
RedisModule_CreateString
(
ctx
,
"foo"
,
3
);
RedisModule_RetainString
(
ctx
,
s
);
RedisModule_StringAppendBuffer
(
ctx
,
s
,
"bar"
,
3
);
RedisModule_ReplyWithString
(
ctx
,
s
);
RedisModule_FreeString
(
ctx
,
s
);
return
REDISMODULE_OK
;
}
/* ----------------------------- Test framework ----------------------------- */
/* Return 1 if the reply matches the specified string, otherwise log errors
* in the server log and return 0. */
int
TestAssertStringReply
(
RedisModuleCtx
*
ctx
,
RedisModuleCallReply
*
reply
,
char
*
str
,
size_t
len
)
{
RedisModuleString
*
mystr
,
*
expected
;
if
(
RedisModule_CallReplyType
(
reply
)
!=
REDISMODULE_REPLY_STRING
)
{
RedisModule_Log
(
ctx
,
"warning"
,
"Unexpected reply type %d"
,
RedisModule_CallReplyType
(
reply
));
return
0
;
}
mystr
=
RedisModule_CreateStringFromCallReply
(
reply
);
expected
=
RedisModule_CreateString
(
ctx
,
str
,
len
);
if
(
RedisModule_StringCompare
(
mystr
,
expected
)
!=
0
)
{
const
char
*
mystr_ptr
=
RedisModule_StringPtrLen
(
mystr
,
NULL
);
const
char
*
expected_ptr
=
RedisModule_StringPtrLen
(
expected
,
NULL
);
RedisModule_Log
(
ctx
,
"warning"
,
"Unexpected string reply '%s' (instead of '%s')"
,
mystr_ptr
,
expected_ptr
);
return
0
;
}
return
1
;
}
#define T(name,...) \
do { \
RedisModule_Log(ctx,"warning","Testing %s", name); \
reply = RedisModule_Call(ctx,name,__VA_ARGS__); \
} while (0);
/* TEST.IT -- Run all the tests. */
int
TestIt
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
RedisModule_AutoMemory
(
ctx
);
RedisModuleCallReply
*
reply
;
T
(
"test.string.append"
,
""
);
if
(
!
TestAssertStringReply
(
ctx
,
reply
,
"foobar"
,
6
))
goto
fail
;
T
(
"test.string.append.am"
,
""
);
if
(
!
TestAssertStringReply
(
ctx
,
reply
,
"foobar"
,
6
))
goto
fail
;
RedisModule_ReplyWithSimpleString
(
ctx
,
"ALL TESTS PASSED"
);
return
REDISMODULE_OK
;
fail:
RedisModule_ReplyWithSimpleString
(
ctx
,
"SOME TEST NOT PASSED! Check server logs"
);
return
REDISMODULE_OK
;
}
int
RedisModule_OnLoad
(
RedisModuleCtx
*
ctx
,
RedisModuleString
**
argv
,
int
argc
)
{
if
(
RedisModule_Init
(
ctx
,
"test"
,
1
,
REDISMODULE_APIVER_1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"test.string.append"
,
TestStringAppend
,
"write deny-oom"
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"test.string.append.am"
,
TestStringAppendAM
,
"write deny-oom"
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
if
(
RedisModule_CreateCommand
(
ctx
,
"test.it"
,
TestIt
,
"readonly"
,
1
,
1
,
1
)
==
REDISMODULE_ERR
)
return
REDISMODULE_ERR
;
return
REDISMODULE_OK
;
}
src/redismodule.h
View file @
04340e1f
...
@@ -186,6 +186,7 @@ double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
...
@@ -186,6 +186,7 @@ double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io);
void
REDISMODULE_API_FUNC
(
RedisModule_Log
)(
RedisModuleCtx
*
ctx
,
const
char
*
level
,
const
char
*
fmt
,
...);
void
REDISMODULE_API_FUNC
(
RedisModule_Log
)(
RedisModuleCtx
*
ctx
,
const
char
*
level
,
const
char
*
fmt
,
...);
int
REDISMODULE_API_FUNC
(
RedisModule_StringAppendBuffer
)(
RedisModuleCtx
*
ctx
,
RedisModuleString
*
str
,
const
char
*
buf
,
size_t
len
);
int
REDISMODULE_API_FUNC
(
RedisModule_StringAppendBuffer
)(
RedisModuleCtx
*
ctx
,
RedisModuleString
*
str
,
const
char
*
buf
,
size_t
len
);
void
REDISMODULE_API_FUNC
(
RedisModule_RetainString
)(
RedisModuleCtx
*
ctx
,
RedisModuleString
*
str
);
void
REDISMODULE_API_FUNC
(
RedisModule_RetainString
)(
RedisModuleCtx
*
ctx
,
RedisModuleString
*
str
);
int
REDISMODULE_API_FUNC
(
RedisModule_StringCompare
)(
RedisModuleString
*
a
,
RedisModuleString
*
b
);
/* This is included inline inside each Redis module. */
/* This is included inline inside each Redis module. */
static
int
RedisModule_Init
(
RedisModuleCtx
*
ctx
,
const
char
*
name
,
int
ver
,
int
apiver
)
__attribute__
((
unused
));
static
int
RedisModule_Init
(
RedisModuleCtx
*
ctx
,
const
char
*
name
,
int
ver
,
int
apiver
)
__attribute__
((
unused
));
...
@@ -281,6 +282,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
...
@@ -281,6 +282,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API
(
Log
);
REDISMODULE_GET_API
(
Log
);
REDISMODULE_GET_API
(
StringAppendBuffer
);
REDISMODULE_GET_API
(
StringAppendBuffer
);
REDISMODULE_GET_API
(
RetainString
);
REDISMODULE_GET_API
(
RetainString
);
REDISMODULE_GET_API
(
StringCompare
);
RedisModule_SetModuleAttribs
(
ctx
,
name
,
ver
,
apiver
);
RedisModule_SetModuleAttribs
(
ctx
,
name
,
ver
,
apiver
);
return
REDISMODULE_OK
;
return
REDISMODULE_OK
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment