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
hiredis
Commits
9bb22da6
Commit
9bb22da6
authored
Jan 04, 2012
by
Pieter Noordhuis
Browse files
Writing commands and reading replies for new context
parent
a52925d5
Changes
4
Show whitespace changes
Inline
Side-by-side
context.c
View file @
9bb22da6
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
/* local */
#include "context.h"
#include "format.h"
#include "object.h"
static
void
redis__clear_address
(
redis_context
*
ctx
)
{
...
...
@@ -119,3 +122,155 @@ int redis_context_connect_gai(redis_context *ctx, const char *host, int port) {
return
REDIS_OK
;
}
int
redis_context_flush
(
redis_context
*
ctx
)
{
int
rv
;
int
drained
=
0
;
while
(
!
drained
)
{
rv
=
redis_handle_write_from_buffer
(
&
ctx
->
handle
,
&
drained
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
}
return
REDIS_OK
;
}
int
redis_context_read
(
redis_context
*
ctx
,
redis_protocol
**
reply
)
{
int
rv
;
redis_protocol
*
aux
=
NULL
;
rv
=
redis_handle_read_from_buffer
(
&
ctx
->
handle
,
&
aux
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
/* No error, no reply: make sure write buffers are flushed */
if
(
aux
==
NULL
)
{
rv
=
redis_context_flush
(
ctx
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
}
while
(
aux
==
NULL
)
{
rv
=
redis_handle_wait_readable
(
&
ctx
->
handle
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
rv
=
redis_handle_read_to_buffer
(
&
ctx
->
handle
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
rv
=
redis_handle_read_from_buffer
(
&
ctx
->
handle
,
&
aux
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
}
assert
(
aux
!=
NULL
);
*
reply
=
aux
;
return
REDIS_OK
;
}
int
redis_context_write_vcommand
(
redis_context
*
ctx
,
const
char
*
format
,
va_list
ap
)
{
char
*
buf
;
int
len
;
int
rv
;
len
=
redis_format_vcommand
(
&
buf
,
format
,
ap
);
if
(
len
<
0
)
{
errno
=
ENOMEM
;
return
REDIS_ESYS
;
}
/* Write command to output buffer in handle */
rv
=
redis_handle_write_to_buffer
(
&
ctx
->
handle
,
buf
,
len
);
free
(
buf
);
return
rv
;
}
int
redis_context_write_command
(
redis_context
*
ctx
,
const
char
*
format
,
...)
{
va_list
ap
;
int
rv
;
va_start
(
ap
,
format
);
rv
=
redis_context_write_vcommand
(
ctx
,
format
,
ap
);
va_end
(
ap
);
return
rv
;
}
int
redis_context_write_command_argv
(
redis_context
*
ctx
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
)
{
char
*
buf
;
int
len
;
int
rv
;
len
=
redis_format_command_argv
(
&
buf
,
argc
,
argv
,
argvlen
);
if
(
len
<
0
)
{
errno
=
ENOMEM
;
return
REDIS_ESYS
;
}
/* Write command to output buffer in handle */
rv
=
redis_handle_write_to_buffer
(
&
ctx
->
handle
,
buf
,
len
);
free
(
buf
);
return
rv
;
}
int
redis_context_call_vcommand
(
redis_context
*
ctx
,
redis_protocol
**
reply
,
const
char
*
format
,
va_list
ap
)
{
int
rv
;
rv
=
redis_context_write_vcommand
(
ctx
,
format
,
ap
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
return
redis_context_read
(
ctx
,
reply
);
}
int
redis_context_call_command
(
redis_context
*
ctx
,
redis_protocol
**
reply
,
const
char
*
format
,
...)
{
va_list
ap
;
int
rv
;
va_start
(
ap
,
format
);
rv
=
redis_context_call_vcommand
(
ctx
,
reply
,
format
,
ap
);
va_end
(
ap
);
return
rv
;
}
int
redis_context_call_command_argv
(
redis_context
*
ctx
,
redis_protocol
**
reply
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
)
{
int
rv
;
rv
=
redis_context_write_command_argv
(
ctx
,
argc
,
argv
,
argvlen
);
if
(
rv
!=
REDIS_OK
)
{
return
rv
;
}
return
redis_context_read
(
ctx
,
reply
);
}
context.h
View file @
9bb22da6
#ifndef _HIREDIS_CONTEXT_H
#define _HIREDIS_CONTEXT_H 1
#include <stdarg.h>
/* local */
#include "handle.h"
...
...
@@ -24,4 +26,32 @@ int redis_context_connect_in6(redis_context *, struct sockaddr_in6 addr);
int
redis_context_connect_un
(
redis_context
*
,
struct
sockaddr_un
addr
);
int
redis_context_connect_gai
(
redis_context
*
,
const
char
*
addr
,
int
port
);
int
redis_context_flush
(
redis_context
*
ctx
);
int
redis_context_read
(
redis_context
*
ctx
,
redis_protocol
**
reply
);
int
redis_context_write_vcommand
(
redis_context
*
ctx
,
const
char
*
format
,
va_list
ap
);
int
redis_context_write_command
(
redis_context
*
ctx
,
const
char
*
format
,
...);
int
redis_context_write_command_argv
(
redis_context
*
ctx
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
int
redis_context_call_vcommand
(
redis_context
*
ctx
,
redis_protocol
**
reply
,
const
char
*
format
,
va_list
ap
);
int
redis_context_call_command
(
redis_context
*
ctx
,
redis_protocol
**
reply
,
const
char
*
format
,
...);
int
redis_context_call_command_argv
(
redis_context
*
ctx
,
redis_protocol
**
reply
,
int
argc
,
const
char
**
argv
,
const
size_t
*
argvlen
);
#endif
test/test-context.c
View file @
9bb22da6
...
...
@@ -17,6 +17,7 @@
/* local */
#include "../context.h"
#include "../object.h"
#include "test-helper.h"
#define SETUP_CONNECT() \
...
...
@@ -165,6 +166,109 @@ TEST(connect_gai_success) {
redis_context_destroy
(
&
c
);
}
#define SETUP_CONNECTED() \
SETUP_CONNECT(); \
rv = redis_context_connect_gai(&c, "localhost", redis_port()); \
assert_equal_int(rv, REDIS_OK);
static
redis_object
*
read
(
redis_context
*
ctx
)
{
redis_protocol
*
reply
;
int
rv
;
rv
=
redis_context_read
(
ctx
,
&
reply
);
assert_equal_return
(
rv
,
REDIS_OK
);
return
(
redis_object
*
)
reply
->
data
;
}
static
void
compare_ok_status
(
redis_object
*
obj
)
{
assert_equal_int
(
obj
->
type
,
REDIS_STATUS
);
assert_equal_string
(
obj
->
str
,
"OK"
);
assert_equal_int
(
obj
->
len
,
2
);
}
static
void
compare_string
(
redis_object
*
obj
,
const
char
*
str
,
size_t
len
)
{
assert_equal_int
(
obj
->
type
,
REDIS_STRING
);
assert_equal_string
(
obj
->
str
,
str
);
assert_equal_int
(
obj
->
len
,
len
);
}
TEST
(
write_command
)
{
SETUP_CONNECTED
();
rv
=
redis_context_write_command
(
&
c
,
"set foo bar"
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_ok_status
(
read
(
&
c
));
/* Check that the command was executed as intended */
rv
=
redis_context_write_command
(
&
c
,
"get foo"
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_string
(
read
(
&
c
),
"bar"
,
3
);
redis_context_destroy
(
&
c
);
}
TEST
(
write_command_argv
)
{
SETUP_CONNECTED
();
int
argc1
=
3
;
const
char
*
argv1
[]
=
{
"set"
,
"foo"
,
"bar"
};
size_t
argvlen1
[]
=
{
3
,
3
,
3
};
rv
=
redis_context_write_command_argv
(
&
c
,
argc1
,
argv1
,
argvlen1
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_ok_status
(
read
(
&
c
));
/* Check that the command was executed as intended */
int
argc2
=
2
;
const
char
*
argv2
[]
=
{
"get"
,
argv1
[
1
]
};
size_t
argvlen2
[]
=
{
3
,
argvlen1
[
1
]
};
rv
=
redis_context_write_command_argv
(
&
c
,
argc2
,
argv2
,
argvlen2
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_string
(
read
(
&
c
),
argv1
[
2
],
argvlen1
[
2
]);
redis_context_destroy
(
&
c
);
}
TEST
(
call_command
)
{
SETUP_CONNECTED
();
redis_protocol
*
reply
;
rv
=
redis_context_call_command
(
&
c
,
&
reply
,
"set foo bar"
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_ok_status
(
reply
->
data
);
/* Check that the command was executed as intended */
rv
=
redis_context_call_command
(
&
c
,
&
reply
,
"get foo"
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_string
(
reply
->
data
,
"bar"
,
3
);
redis_context_destroy
(
&
c
);
}
TEST
(
call_command_argv
)
{
SETUP_CONNECTED
();
redis_protocol
*
reply
;
int
argc1
=
3
;
const
char
*
argv1
[]
=
{
"set"
,
"foo"
,
"bar"
};
size_t
argvlen1
[]
=
{
3
,
3
,
3
};
rv
=
redis_context_call_command_argv
(
&
c
,
&
reply
,
argc1
,
argv1
,
argvlen1
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_ok_status
(
reply
->
data
);
/* Check that the command was executed as intended */
int
argc2
=
2
;
const
char
*
argv2
[]
=
{
"get"
,
argv1
[
1
]
};
size_t
argvlen2
[]
=
{
3
,
argvlen1
[
1
]
};
rv
=
redis_context_call_command_argv
(
&
c
,
&
reply
,
argc2
,
argv2
,
argvlen2
);
assert_equal_int
(
rv
,
REDIS_OK
);
compare_string
(
reply
->
data
,
argv1
[
2
],
argvlen1
[
2
]);
redis_context_destroy
(
&
c
);
}
int
main
(
void
)
{
test_connect_in_refused
();
test_connect_in6_refused
();
...
...
@@ -174,4 +278,9 @@ int main(void) {
test_connect_gai_unknown_host
();
test_connect_gai_timeout
();
test_connect_gai_success
();
test_write_command
();
test_write_command_argv
();
test_call_command
();
test_call_command_argv
();
}
test/test-helper.h
View file @
9bb22da6
...
...
@@ -6,6 +6,15 @@
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>
#include <errno.h>
/* gai_strerror */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
/* local */
#include "../handle.h"
/******************************************************************************/
/* ASSERTS ********************************************************************/
...
...
@@ -48,6 +57,42 @@
} \
} while(0)
#define ERR_TO_STR_OFFSET 4
static
const
char
*
err_to_str
[]
=
{
[
REDIS_OK
+
ERR_TO_STR_OFFSET
]
=
"REDIS_OK"
,
[
REDIS_ESYS
+
ERR_TO_STR_OFFSET
]
=
"REDIS_ESYS"
,
[
REDIS_EGAI
+
ERR_TO_STR_OFFSET
]
=
"REDIS_EGAI"
,
[
REDIS_EPARSER
+
ERR_TO_STR_OFFSET
]
=
"REDIS_EPARSER"
,
[
REDIS_EEOF
+
ERR_TO_STR_OFFSET
]
=
"REDIS_EEOF"
};
static
void
assert_equal_return_failure
(
int
actual
,
int
expected
,
const
char
*
file
,
int
line
)
{
const
char
*
actualstr
=
err_to_str
[
actual
+
ERR_TO_STR_OFFSET
];
const
char
*
expectedstr
=
err_to_str
[
expected
+
ERR_TO_STR_OFFSET
];
char
reason
[
128
];
switch
(
actual
)
{
case
REDIS_ESYS
:
sprintf
(
reason
,
"%d:%s"
,
errno
,
strerror
(
errno
));
break
;
case
REDIS_EGAI
:
sprintf
(
reason
,
"%d:%s"
,
errno
,
gai_strerror
(
errno
));
break
;
}
fprintf
(
stderr
,
"%s:%d: "
,
file
,
line
);
fprintf
(
stderr
,
"%s != %s (%s)
\n
"
,
actualstr
,
expectedstr
,
reason
);
}
#define assert_equal_return(a, b) do { \
if ((a) != (b)) { \
assert_equal_return_failure( \
(a), (b), \
__FILE__, __LINE__); \
assert(0); \
} \
} while(0)
/******************************************************************************/
/* TEST DEFINITION ************************************************************/
/******************************************************************************/
...
...
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