resp协议实现和使用hiredis进行测试

This commit is contained in:
1iaan
2026-01-20 11:51:38 +00:00
parent bb2c4275cb
commit f031e107b5
15 changed files with 1010 additions and 498 deletions

215
test-redis/test.c Normal file
View File

@@ -0,0 +1,215 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <hiredis/hiredis.h>
static void die(redisContext *c, const char *msg) {
fprintf(stderr, "%s: %s\n", msg, c && c->err ? c->errstr : "unknown");
exit(1);
}
static void must_ok(redisReply *r, const char *what) {
if (!r) { fprintf(stderr, "%s: reply null\n", what); exit(1); }
if (!(r->type == REDIS_REPLY_STATUS && r->str && strcasecmp(r->str, "OK") == 0)) {
fprintf(stderr, "%s: expect +OK, got type=%d str=%s\n",
what, r->type, r->str ? r->str : "(null)");
freeReplyObject(r);
exit(1);
}
freeReplyObject(r);
}
static void must_int(redisReply *r, long long expect, const char *what) {
if (!r) { fprintf(stderr, "%s: reply null\n", what); exit(1); }
if (r->type != REDIS_REPLY_INTEGER || r->integer != expect) {
fprintf(stderr, "%s: expect :%lld, got type=%d int=%lld\n",
what, expect, r->type, (long long)r->integer);
freeReplyObject(r);
exit(1);
}
freeReplyObject(r);
}
static void must_bulk_eq(redisReply *r, const void *buf, size_t n, const char *what) {
if (!r) { fprintf(stderr, "%s: reply null\n", what); exit(1); }
if (r->type != REDIS_REPLY_STRING || r->len != n || memcmp(r->str, buf, n) != 0) {
fprintf(stderr, "%s: bulk mismatch. type=%d len=%zu\n", what, r->type, r->len);
freeReplyObject(r);
exit(1);
}
freeReplyObject(r);
}
static void must_nil(redisReply *r, const char *what) {
if (!r) { fprintf(stderr, "%s: reply null\n", what); exit(1); }
if (r->type != REDIS_REPLY_NIL) {
fprintf(stderr, "%s: expect nil, got type=%d\n", what, r->type);
freeReplyObject(r);
exit(1);
}
freeReplyObject(r);
}
void basic_command_test(redisContext *c){
/* ---------- 1) 基本命令测试 ---------- */
const char *k = "k1";
const char *v1 = "v1";
const char *v2 = "v2";
must_ok((redisReply*)redisCommand(c, "SET %b %b", k, strlen(k), v1, strlen(v1)), "SET");
must_bulk_eq((redisReply*)redisCommand(c, "GET %b", k, strlen(k)), v1, strlen(v1), "GET");
must_int((redisReply*)redisCommand(c, "EXIST %b", k, strlen(k)), 1, "EXIST=1");
must_ok((redisReply*)redisCommand(c, "MOD %b %b", k, strlen(k), v2, strlen(v2)), "MOD");
must_bulk_eq((redisReply*)redisCommand(c, "GET %b", k, strlen(k)), v2, strlen(v2), "GET after MOD");
must_int((redisReply*)redisCommand(c, "DEL %b", k, strlen(k)), 1, "DEL=1");
must_int((redisReply*)redisCommand(c, "EXIST %b", k, strlen(k)), 0, "EXIST=0");
must_nil((redisReply*)redisCommand(c, "GET %b", k, strlen(k)), "GET nil");
printf("[OK] basic SET/GET/MOD/DEL/EXIST\n");
}
void special_char_test(redisContext *c){
/* ---------- 2) 特殊字符/二进制测试 ---------- */
uint8_t key2[] = { 'b','i','n',':',0x00,'K','\r','\n',0xFF };
uint8_t val2[] = { 0x00,'A','\r','\n','B',0x00,0xFF };
must_ok((redisReply*)redisCommand(c, "SET %b %b", key2, sizeof(key2), val2, sizeof(val2)),
"SET binary");
must_bulk_eq((redisReply*)redisCommand(c, "GET %b", key2, sizeof(key2)),
val2, sizeof(val2), "GET binary");
(void)redisCommand(c, "DEL %b", key2, sizeof(key2)); /* 不强制检查返回 */
printf("[OK] binary/special chars\n");
}
void save(redisContext *c){
must_ok((redisReply*)redisCommand(c, "SAVE"), "SET binary");
printf("[OK] SAVE\n");
}
void pipline_set_test(redisContext *c, int start, const char *op){
/* ---------- 3) Pipeline 批处理测试 ---------- */
const int N = 1000;
/* 一次塞 N 个 SET */
int end = start + N;
for (int i = start; i < end; i++) {
char kk[64], vv[64];
int kn = snprintf(kk, sizeof(kk), "p:%d", i);
int vn = snprintf(vv, sizeof(vv), "v:%d", i);
if (redisAppendCommand( c, "%s %b %b",
op,
kk, (size_t)kn,
vv, (size_t)vn) != REDIS_OK) {
die(c, "redisAppendCommand SET failed");
}
}
/* 再一次性把 N 个回复读出来 */
for (int i = start; i < end; i++) {
redisReply *r = NULL;
if (redisGetReply(c, (void**)&r) != REDIS_OK || !r) die(c, "redisGetReply SET failed");
must_ok(r, "pipeline SET reply");
}
printf("[OK] SET pipeline batch %d\n", N);
}
void pipline_get_test(redisContext *c, int start, const char *op){
const int N = 1000;
/* pipeline GET + 校验 */
int end = start + N;
for (int i = start; i < end; i++) {
char kk[64];
int kn = snprintf(kk, sizeof(kk), "p:%d", i);
if (redisAppendCommand( c, "%s %b",
op,
kk, (size_t)kn) != REDIS_OK) {
die(c, "redisAppendCommand GET failed");
}
}
for (int i = start; i < end; i++) {
redisReply *r = NULL;
if (redisGetReply(c, (void**)&r) != REDIS_OK || !r) die(c, "redisGetReply GET failed");
char expect[64];
int en = snprintf(expect, sizeof(expect), "v:%d", i);
must_bulk_eq(r, expect, (size_t)en, "pipeline GET reply");
}
printf("[OK] GET pipeline batch %d\n", N);
}
void pipline_del_test(redisContext *c, int start, const char *op){
const int N = 1000;
/* cleanuppipeline DEL */
int end = start + N;
for (int i = start; i < end; i++) {
char kk[64];
int kn = snprintf(kk, sizeof(kk), "p:%d", i);
if (redisAppendCommand( c, "%s %b",
op,
kk, (size_t)kn) != REDIS_OK) {
die(c, "redisAppendCommand DEL failed");
}
}
for (int i = start; i < end; i++) {
redisReply *r = NULL;
if (redisGetReply(c, (void**)&r) != REDIS_OK || !r) die(c, "redisGetReply DEL failed");
freeReplyObject(r); /* DEL 返回 int这里不强制检查 */
}
printf("[OK] DEL pipeline batch %d\n", N);
}
int main(int argc, char **argv) {
if(argc < 4) {
printf("invalid input\n");
return -1;
}
const char *host = argv[1];
int port = atoi(argv[2]);
int mode = atoi(argv[3]);
redisContext *c = redisConnect(host, port);
if (!c || c->err) die(c, "connect failed");
printf("Connected to %s:%d\n", host, port);
if(mode == 0){
save(c);
}else if(mode == 1){
basic_command_test(c);
}else if(mode == 10){
pipline_set_test(c, 0, "SET");
}else if(mode == 11){
pipline_get_test(c, 0, "GET");
}else if(mode == 12){
pipline_del_test(c, 0, "DEL");
}else if(mode == 20){
pipline_set_test(c, 0, "RSET");
}else if(mode == 21){
pipline_get_test(c, 0, "RGET");
}else if(mode == 22){
pipline_del_test(c, 0, "RDEL");
}else if(mode == 30){
pipline_set_test(c, 0, "HSET");
}else if(mode == 31){
pipline_get_test(c, 0, "HGET");
}else if(mode == 32){
pipline_del_test(c, 0, "HDEL");
}
redisFree(c);
printf("ALL TESTS PASSED.\n");
return 0;
}