func MemcachedServerProcessSpecs(c gospec.Context) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) c.Specify("[MemcachedServerProcess] Starts a new Memcached-Server", func() { server, err := StartMemcachedServer(&logger) defer server.Close() c.Expect(err, gospec.Equals, nil) c.Expect(server, gospec.Satisfies, server != nil) c.Expect(server.logger, gospec.Equals, &logger) c.Expect(server.port, gospec.Satisfies, server.port >= 1024) c.Expect(server.cmd, gospec.Satisfies, nil != server.cmd) c.Expect(server.connection, gospec.Satisfies, nil == server.connection) }) c.Specify("[MemcachedServerProcess] Creates a connection to a Memcached-Server", func() { server, err := StartMemcachedServer(&logger) defer server.Close() c.Expect(err, gospec.Equals, nil) c.Expect(server, gospec.Satisfies, server != nil) connection := server.Connection() c.Expect(connection, gospec.Satisfies, nil != connection) c.Expect(server.connection, gospec.Equals, connection) err = connection.Open() c.Expect(err, gospec.Equals, nil) c.Expect(connection.IsOpen(), gospec.Equals, true) }) }
// // Benchmark Bit Operation A & !B on 10x keys // func Benchmark_BitOp_ComplementSet_BatchCommands(b *testing.B) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() keys_all := [][]string{make([]string, 10), make([]string, 10)} keys_bob := [][]string{make([]string, 10), make([]string, 10)} keys_not_bob := [][]string{make([]string, 10), make([]string, 10)} keys_gary := [][]string{make([]string, 10), make([]string, 10)} keys_not_gary := [][]string{make([]string, 10), make([]string, 10)} for i := 0; i < 10; i++ { for j := 0; j <= 1; j++ { keys_all[j][i] = fmt.Sprintf("ALL:%d:%d", j, i) keys_bob[j][i] = fmt.Sprintf("BOB:%d:%d", j, i) keys_not_bob[j][i] = fmt.Sprintf("Not-BOB:%d:%d", j, i) keys_gary[j][i] = fmt.Sprintf("GARY:%d:%d", j, i) keys_not_gary[j][i] = fmt.Sprintf("Not-GARY:%d:%d", j, i) } } for i := 0; i < 1024; i++ { for j := 0; j < 10; j++ { for k := 0; k <= 1; k++ { server.Connection().Cmd("SETBIT", keys_all[k][j], i, true) server.Connection().Cmd("SETBIT", keys_bob[k][j], i, i%2 == 0) server.Connection().Cmd("SETBIT", keys_not_bob[k][j], i, i%2 == 1) server.Connection().Cmd("SETBIT", keys_gary[k][j], i, i%4 == 0) server.Connection().Cmd("SETBIT", keys_not_gary[k][j], i, i%4 == 0) } } } cmds := RedisBatchCommands{ MakeRedisBatchCommandBitopAnd("ALL:0", keys_all[0]...), MakeRedisBatchCommandBitopAnd("ALL:1", keys_all[1]...), MakeRedisBatchCommandBitopAnd("BOB:0", keys_bob[0]...), MakeRedisBatchCommandBitopAnd("BOB:1", keys_bob[1]...), MakeRedisBatchCommandBitopAnd("Not-BOB:0", keys_not_bob[0]...), MakeRedisBatchCommandBitopAnd("Not-BOB:1", keys_not_bob[1]...), MakeRedisBatchCommandBitopAnd("GARY:0", keys_gary[0]...), MakeRedisBatchCommandBitopAnd("GARY:1", keys_gary[1]...), MakeRedisBatchCommandBitopAnd("Not-GARY:0", keys_not_gary[0]...), MakeRedisBatchCommandBitopOr("Not-GARY:1", keys_not_gary[1]...), MakeRedisBatchCommandBitopNot("Not-GARY:1", "Not-GARY:1"), MakeRedisBatchCommandBitopAnd("Complement", "Not-GARY:1", "ALL:0", "ALL:1", "BOB:0", "BOB:1", "Not-BOB:0", "Not-BOB:1", "GARY:0", "GARY:1", "Not-GARY:0"), } for _, key := range []string{"Complement", "Not-GARY:1", "ALL:0", "ALL:1", "BOB:0", "BOB:1", "Not-BOB:0", "Not-BOB:1", "GARY:0", "GARY:1", "Not-GARY:0"} { cmds = append(cmds, MakeRedisBatchCommandBitCount(key)) } cmds = append(cmds, MakeRedisBatchCommandGet("Complement")) b.ResetTimer() for i := 0; i < b.N; i++ { cmds.ExecuteBatch(server.Connection()) } }
func Benchmark_Del_CacheMiss_RedisConnection(b *testing.B) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() b.ResetTimer() for i := 0; i < b.N; i++ { server.Connection().Cmd("DEL", "BOB", "Hello", "World", "GARY", "THE", "SNAIL") } }
func Benchmark_Set_RedisConnection(b *testing.B) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() b.ResetTimer() for i := 0; i < b.N; i++ { server.Connection().Cmd("SET", "BOB", "Hello") } }
func Benchmark_MemcachedConnection_Set(b *testing.B) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartMemcachedServer(&logger) if nil != err { panic(err) } defer server.Close() b.ResetTimer() for i := 0; i < b.N; i++ { server.Connection().Set(&memcached.Item{Key: "BOB", Value: []byte("Hello")}) } }
func Benchmark_Bit_Get_RedisConnection(b *testing.B) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() for i := 0; i < 1024; i++ { server.Connection().Cmd("SETBIT", "ALL", i, true) } b.ResetTimer() for i := 0; i < b.N; i++ { server.Connection().Cmd("GET", "ALL") } }
func Benchmark_BitOp_Not_RedisConnection(b *testing.B) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() for i := 0; i < 1024; i++ { server.Connection().Cmd("SETBIT", "ALL", i, true) server.Connection().Cmd("SETBIT", "BOB", i, i%2 == 0) server.Connection().Cmd("SETBIT", "Not-BOB", i, i%2 == 1) server.Connection().Cmd("SETBIT", "GARY", i, i%4 == 0) } b.ResetTimer() for i := 0; i < b.N; i++ { server.Connection().Cmd("BITOP", "NOT", "ALL", "BOB", "Not-BOB", "GARY", "Cache-Miss") } }
// Pre-format the commands as a single string, and compare the results to above func Benchmark_BitOp_ComplementSet_RedisConnection(b *testing.B) { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() keys_all := [][]string{make([]string, 10), make([]string, 10)} keys_bob := [][]string{make([]string, 10), make([]string, 10)} keys_not_bob := [][]string{make([]string, 10), make([]string, 10)} keys_gary := [][]string{make([]string, 10), make([]string, 10)} keys_not_gary := [][]string{make([]string, 10), make([]string, 10)} for i := 0; i < 10; i++ { for j := 0; j <= 1; j++ { keys_all[j][i] = fmt.Sprintf("ALL:%d:%d", j, i) keys_bob[j][i] = fmt.Sprintf("BOB:%d:%d", j, i) keys_not_bob[j][i] = fmt.Sprintf("Not-BOB:%d:%d", j, i) keys_gary[j][i] = fmt.Sprintf("GARY:%d:%d", j, i) keys_not_gary[j][i] = fmt.Sprintf("Not-GARY:%d:%d", j, i) } } for i := 0; i < 1024; i++ { for j := 0; j < 10; j++ { for k := 0; k <= 1; k++ { server.Connection().Cmd("SETBIT", keys_all[k][j], i, true) server.Connection().Cmd("SETBIT", keys_bob[k][j], i, i%2 == 0) server.Connection().Cmd("SETBIT", keys_not_bob[k][j], i, i%2 == 1) server.Connection().Cmd("SETBIT", keys_gary[k][j], i, i%4 == 0) server.Connection().Cmd("SETBIT", keys_not_gary[k][j], i, i%4 == 0) } } } b.ResetTimer() for i := 0; i < b.N; i++ { server.Connection().Cmd("BITOP AND ALL:0 %s", keys_all[0]) server.Connection().Cmd("BITOP AND ALL:1 %s", keys_all[1]) server.Connection().Cmd("BITOP AND BOB:0 %s", keys_bob[0]) server.Connection().Cmd("BITOP AND BOB:1 %s", keys_bob[1]) server.Connection().Cmd("BITOP AND Not-BOB:0 %s", keys_not_bob[0]) server.Connection().Cmd("BITOP AND Not-BOB:1 %s", keys_not_bob[1]) server.Connection().Cmd("BITOP AND GARY:0 %s", keys_gary[0]) server.Connection().Cmd("BITOP AND GARY:1 %s", keys_gary[1]) server.Connection().Cmd("BITOP AND Not-GARY:0 %s", keys_not_gary[0]) server.Connection().Cmd("BITOP AND Not-GARY:0 %s", keys_not_gary[0]) server.Connection().Cmd("BITOP OR Not-GARY:1 %s", keys_not_gary[1]) server.Connection().Cmd("BITOP", "NOT", "Not-GARY:1", "Not-GARY:1") server.Connection().Cmd("BITOP", "AND", "Complement", "Not-GARY:1", "ALL:0", "ALL:1", "BOB:0", "BOB:1", "Not-BOB:0", "Not-BOB:1", "GARY:0", "GARY:1", "Not-GARY:0") server.Connection().Cmd("BITCOUNT", "Complement") server.Connection().Cmd("BITCOUNT", "Not-GARY:1") server.Connection().Cmd("BITCOUNT", "ALL:0") server.Connection().Cmd("BITCOUNT", "ALL:1") server.Connection().Cmd("BITCOUNT", "BOB:0") server.Connection().Cmd("BITCOUNT", "BOB:1") server.Connection().Cmd("BITCOUNT", "Not-BOB:0") server.Connection().Cmd("BITCOUNT", "Not-BOB:1") server.Connection().Cmd("BITCOUNT", "GARY:0") server.Connection().Cmd("BITCOUNT", "GARY:1") server.Connection().Cmd("BITCOUNT", "Not-GARY:0") server.Connection().Cmd("GET", "Complement") } }
// Helpers func ReplyToSpecs(c gospec.Context) { c.Specify("[ReplyToBool] returns boolean or error", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Cache Miss reply := server.Connection().Cmd("EXISTS", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err := ReplyToBool(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Equals, false) // Cache Hit server.Connection().Cmd("SET", "Bob", "George") reply = server.Connection().Cmd("EXISTS", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err = ReplyToBool(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Equals, true) // Parsing Error reply = server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) value, value_err = ReplyToBool(reply) c.Expect(value_err, gospec.Satisfies, nil != value_err) c.Expect(value, gospec.Equals, false) }) c.Specify("[ReplyToInt64Ptr] returns *int64 or error", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Cache Miss reply := server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.NilReply) value, value_err := ReplyToInt64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil == value) // Cache Hit --> String server.Connection().Cmd("SET", "Bob", "123") reply = server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToInt64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(value, gospec.Satisfies, int64(123) == *value) // Cache Hit --> Integer reply = server.Connection().Cmd("INCRBY", "Bob", 1000) c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err = ReplyToInt64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, int64(1123)) // Cache Hit --> Integer reply = server.Connection().Cmd("DECRBY", "Bob", 1000) c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err = ReplyToInt64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, int64(123)) // Cache Hit --> Integer reply = server.Connection().Cmd("INCR", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err = ReplyToInt64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, int64(124)) // Cache Hit --> Integer reply = server.Connection().Cmd("DECR", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err = ReplyToInt64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, int64(123)) // Parsing Error reply = server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) value, value_err = ReplyToInt64Ptr(reply) c.Expect(value_err, gospec.Satisfies, nil != value_err) c.Expect(value, gospec.Satisfies, nil == value) }) c.Specify("[ReplyToInt64Ptrs] returns []*int64 or error", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Invalid Reply Type // Cache Miss reply := server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) value, value_err := ReplyToInt64Ptrs(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, 1 == len(value)) c.Expect(value[0], gospec.Satisfies, nil == value[0]) // Cache Hit --> String server.Connection().Cmd("SET", "Bob", "123") reply = server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) c.Expect(len(reply.Elems), gospec.Equals, 1) c.Expect(reply.Elems[0].Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToInt64Ptrs(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, 1 == len(value)) c.Expect(value[0], gospec.Satisfies, nil != value[0]) c.Expect(value[0], gospec.Satisfies, int64(123) == *value[0]) // Parsing Error reply = server.Connection().Cmd("GET", "Missing") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.NilReply) value, value_err = ReplyToInt64Ptrs(reply) c.Expect(value_err, gospec.Satisfies, strings.HasPrefix(value_err.Error(), "Reply type is not MultiReply, ")) c.Expect(value, gospec.Satisfies, 0 == len(value)) // Parsing Error reply = server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToInt64Ptrs(reply) c.Expect(value_err, gospec.Satisfies, strings.HasPrefix(value_err.Error(), "Reply type is not MultiReply, ")) c.Expect(value, gospec.Satisfies, 0 == len(value)) }) c.Specify("[ReplyToFloat64Ptr] returns *float64 or error", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Cache Miss reply := server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.NilReply) value, value_err := ReplyToFloat64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil == value) // Cache Hit --> String server.Connection().Cmd("SET", "Bob", "123.456") reply = server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToFloat64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(value, gospec.Satisfies, float64(123.456) == *value) // Cache Hit --> Float reply = server.Connection().Cmd("INCRBYFLOAT", "Bob", 1000.0) c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToFloat64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, float64(1123.456)) // Cache Hit --> Integer server.Connection().Cmd("SET", "Bob", 123) reply = server.Connection().Cmd("INCR", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err = ReplyToFloat64Ptr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, float64(123+1)) // Parsing Error reply = server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) value, value_err = ReplyToFloat64Ptr(reply) c.Expect(value_err, gospec.Satisfies, nil != value_err) c.Expect(value, gospec.Satisfies, nil == value) }) c.Specify("[ReplyToFloat64Ptrs] returns []*float64 or error", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Invalid Reply Type // Cache Miss reply := server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) value, value_err := ReplyToFloat64Ptrs(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, 1 == len(value)) c.Expect(value[0], gospec.Satisfies, nil == value[0]) // Cache Hit --> String server.Connection().Cmd("SET", "Bob", "123.456") reply = server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) c.Expect(len(reply.Elems), gospec.Equals, 1) c.Expect(reply.Elems[0].Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToFloat64Ptrs(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, 1 == len(value)) c.Expect(value[0], gospec.Satisfies, nil != value[0]) c.Expect(value[0], gospec.Satisfies, float64(123.456) == *value[0]) // Parsing Error reply = server.Connection().Cmd("GET", "Missing") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.NilReply) value, value_err = ReplyToFloat64Ptrs(reply) c.Expect(value_err, gospec.Satisfies, strings.HasPrefix(value_err.Error(), "Reply type is not MultiReply, ")) c.Expect(value, gospec.Satisfies, 0 == len(value)) // Parsing Error reply = server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToFloat64Ptrs(reply) c.Expect(value_err, gospec.Satisfies, strings.HasPrefix(value_err.Error(), "Reply type is not MultiReply, ")) c.Expect(value, gospec.Satisfies, 0 == len(value)) }) c.Specify("[ReplyToStringPtr] returns *string or error", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Cache Miss reply := server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.NilReply) value, value_err := ReplyToStringPtr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil == value) // Cache Hit --> String server.Connection().Cmd("SET", "Bob", "123.456") reply = server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToStringPtr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(value, gospec.Satisfies, string("123.456") == *value) // Cache Hit --> Float reply = server.Connection().Cmd("INCRBYFLOAT", "Bob", 1000.0) c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToStringPtr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, string("1123.45599999999999996")) // Cache Hit --> Integer server.Connection().Cmd("SET", "Bob", 123) reply = server.Connection().Cmd("INCR", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.IntegerReply) value, value_err = ReplyToStringPtr(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, nil != value) c.Expect(*value, gospec.Equals, string("124")) // Parsing Error reply = server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) value, value_err = ReplyToStringPtr(reply) c.Expect(value_err, gospec.Satisfies, nil != value_err) c.Expect(value, gospec.Satisfies, nil == value) }) c.Specify("[ReplyToStringPtrs] returns []*string or error", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Invalid Reply Type // Cache Miss reply := server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) value, value_err := ReplyToStringPtrs(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, 1 == len(value)) c.Expect(value[0], gospec.Satisfies, nil == value[0]) // Cache Hit --> String server.Connection().Cmd("SET", "Bob", "123.456") reply = server.Connection().Cmd("MGET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.MultiReply) c.Expect(len(reply.Elems), gospec.Equals, 1) c.Expect(reply.Elems[0].Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToStringPtrs(reply) c.Expect(value_err, gospec.Equals, nil) c.Expect(value, gospec.Satisfies, 1 == len(value)) c.Expect(value[0], gospec.Satisfies, nil != value[0]) c.Expect(value[0], gospec.Satisfies, string("123.456") == *value[0]) // Parsing Error reply = server.Connection().Cmd("GET", "Missing") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.NilReply) value, value_err = ReplyToStringPtrs(reply) c.Expect(value_err, gospec.Satisfies, strings.HasPrefix(value_err.Error(), "Reply type is not MultiReply, ")) c.Expect(value, gospec.Satisfies, 0 == len(value)) // Parsing Error reply = server.Connection().Cmd("GET", "Bob") c.Expect(reply.Err, gospec.Equals, nil) c.Expect(reply, gospec.Satisfies, nil != reply) c.Expect(reply.Type, gospec.Equals, redis.BulkReply) value, value_err = ReplyToStringPtrs(reply) c.Expect(value_err, gospec.Satisfies, strings.HasPrefix(value_err.Error(), "Reply type is not MultiReply, ")) c.Expect(value, gospec.Satisfies, 0 == len(value)) }) }
// Helpers func MemcachedConnectionSpecs(c gospec.Context) { var memcached_connection_logger = log4go.NewDefaultLogger(log4go.CRITICAL) c.Specify("[MemcachedConnection] New connection is not open", func() { connection := MemcachedConnection{Url: "127.0.0.1:11290", Logger: &memcached_connection_logger} defer connection.Close() // Should be opposite of each other: c.Expect(connection.IsOpen(), gospec.Equals, false) c.Expect(connection.IsClosed(), gospec.Equals, true) }) c.Specify("[MemcachedConnection] Opening connection to Invalid Host/Port has errors", func() { connection := MemcachedConnection{Url: "127.0.0.1:11291", Logger: &memcached_connection_logger} defer connection.Close() c.Expect(nil != connection.Open(), gospec.Equals, true) c.Expect(connection.IsClosed(), gospec.Equals, true) }) c.Specify("[MemcachedConnection] Opening connection to Valid Host/Port has no errors", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartMemcachedServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().Open(), gospec.Equals, nil) c.Expect(server.Connection().IsOpen(), gospec.Equals, true) c.Expect(server.Connection().IsClosed(), gospec.Equals, false) }) c.Specify("[MemcachedConnection] Ping (-->Set-->Delete) (re-)opens the connection automatically", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartMemcachedServer(&logger) if nil != err { panic(err) } defer server.Close() // Starts off closed ... c.Expect(server.Connection().IsClosed(), gospec.Equals, true) // Ping the server // Should now be open c.Expect(server.Connection().Ping(), gospec.Equals, nil) c.Expect(server.Connection().IsOpen(), gospec.Equals, true) // Close the connection err = server.Connection().Close() c.Expect(err, gospec.Equals, nil) c.Expect(server.Connection().IsClosed(), gospec.Equals, true) // Ping the server again // Should now be open again c.Expect(server.Connection().Ping(), gospec.Equals, nil) c.Expect(server.Connection().IsOpen(), gospec.Equals, true) }) c.Specify("[MemcachedConnection] Clone+Ping (-->Set-->Delete) (re-)opens the connection automatically", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartMemcachedServer(&logger) if nil != err { panic(err) } defer server.Close() // Starts off closed ... c.Expect(server.Connection().IsClosed(), gospec.Equals, true) // Ping the server // Should now be open c.Expect(server.Connection().Ping(), gospec.Equals, nil) c.Expect(server.Connection().IsOpen(), gospec.Equals, true) // Clone the connection clone := server.Connection().Clone() defer clone.Close() // Close the connection c.Expect(err, gospec.Equals, nil) c.Expect(clone.IsClosed(), gospec.Equals, true) // Ping the server again // Should now be open again c.Expect(clone.Ping(), gospec.Equals, nil) c.Expect(clone.IsOpen(), gospec.Equals, true) }) c.Specify("[MemcachedConnection][Get] Returns Cache Miss", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartMemcachedServer(&logger) if nil != err { panic(err) } defer server.Close() item, err := server.Connection().Get("BOB") c.Expect(err, gospec.Equals, memcached.ErrCacheMiss) c.Expect(item, gospec.Satisfies, nil == item) }) c.Specify("[MemcachedConnection][Set+Get] Returns Value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartMemcachedServer(&logger) if nil != err { panic(err) } defer server.Close() item_input := &memcached.Item{Key: "BOB", Value: []byte("Hello")} c.Expect(server.Connection().Set(item_input), gospec.Equals, nil) item_output, err := server.Connection().Get("BOB") c.Expect(err, gospec.Equals, nil) c.Expect(item_output.Key, gospec.Equals, item_input.Key) c.Expect(string(item_output.Value), gospec.Equals, string(item_input.Value)) }) c.Specify("[MemcachedConnection][SetStr+GetStr] Returns Value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartMemcachedServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().SetStr("BOB", "Hello", 0), gospec.Equals, nil) ptr, err := server.Connection().GetStr("BOB") c.Expect(err, gospec.Equals, nil) c.Expect(ptr, gospec.Satisfies, nil != ptr) c.Expect(*ptr, gospec.Equals, "Hello") }) }
// Helpers func StopWatchSpecs(c gospec.Context) { c.Specify("[StopWatch] Makes StopWatch", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) value := MakeStopWatch(c, &logger, "Make") c.Expect(value, gospec.Satisfies, nil != value) c.Expect(value.Logger, gospec.Equals, &logger) c.Expect(value.Connection, gospec.Equals, c) c.Expect(value.Tags[0], gospec.Equals, "Make") c.Expect(value.Time, gospec.Satisfies, value.Time.IsZero()) c.Expect(value.Duration, gospec.Equals, time.Duration(0)) }) c.Specify("[StopWatch] Starts StopWatch", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) value := MakeStopWatch(c, &logger, "Make") c.Expect(value, gospec.Satisfies, nil != value) c.Expect(value.Logger, gospec.Equals, &logger) c.Expect(value.Connection, gospec.Equals, c) c.Expect(value.Tags[0], gospec.Equals, "Make") c.Expect(value.Time, gospec.Satisfies, value.Time.IsZero()) c.Expect(value.Duration, gospec.Equals, time.Duration(0)) value.Start() c.Expect(value.Time, gospec.Satisfies, !value.Time.IsZero()) c.Expect(value.Duration, gospec.Equals, time.Duration(0)) time.Sleep(time.Duration(1) * time.Microsecond) }) c.Specify("[StopWatch] Stops StopWatch", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) value := MakeStopWatch(c, &logger, "Make") c.Expect(value, gospec.Satisfies, nil != value) c.Expect(value.Logger, gospec.Equals, &logger) c.Expect(value.Connection, gospec.Equals, c) c.Expect(value.Tags[0], gospec.Equals, "Make") c.Expect(value.Time, gospec.Satisfies, value.Time.IsZero()) c.Expect(value.Duration, gospec.Equals, time.Duration(0)) // Don't error out or panic if the stop watch was not started! value.Stop() c.Expect(value.Time, gospec.Satisfies, value.Time.IsZero()) c.Expect(value.Duration, gospec.Equals, time.Duration(0)) // Start the stop watch value.Start() c.Expect(value.Time, gospec.Satisfies, !value.Time.IsZero()) c.Expect(value.Duration, gospec.Equals, time.Duration(0)) // Sleep, then stop the stop watch time.Sleep(time.Duration(2) * time.Microsecond) value.Stop() c.Expect(value.Time, gospec.Satisfies, !value.Time.IsZero()) c.Expect(value.Duration, gospec.Satisfies, value.Duration > 0) c.Expect(value.Duration.Nanoseconds(), gospec.Satisfies, value.Duration.Nanoseconds() >= 2*1000) }) c.Specify("[StopWatch] Logs StopWatch", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) value := MakeStopWatch(c, &logger, "Make") c.Expect(value, gospec.Satisfies, nil != value) c.Expect(value.Logger, gospec.Equals, &logger) c.Expect(value.Connection, gospec.Equals, c) c.Expect(value.Tags[0], gospec.Equals, "Make") c.Expect(value.Time, gospec.Satisfies, value.Time.IsZero()) c.Expect(value.Duration, gospec.Equals, time.Duration(0)) // Start the stop watch value.Start() c.Expect(value.Time, gospec.Satisfies, !value.Time.IsZero()) // Sleep, then stop the stop watch time.Sleep(time.Duration(2) * time.Microsecond) value.Stop() // Execute the logger value.LogDuration() }) }
// Helpers func MemcachedPoolSpecs(c gospec.Context) { var memcached_pool_logger = log4go.NewDefaultLogger(log4go.CRITICAL) c.Specify("[MemcachedConnectionPool] New Pool is not open", func() { pool := MemcachedConnectionPool{Mode: AGRESSIVE, Size: 0, Urls: []string{}, Logger: memcached_pool_logger} defer pool.Close() c.Expect(pool.IsOpen(), gospec.Equals, false) c.Expect(pool.IsClosed(), gospec.Equals, true) c.Expect(pool.IsOpen(), gospec.Satisfies, pool.IsOpen() != pool.IsClosed()) c.Expect(pool.Len(), gospec.Equals, -1) }) c.Specify("[MemcachedConnectionPool] Opening a Pool with Undefined Mode has errors", func() { pool := MemcachedConnectionPool{Mode: 0, Size: 0, Urls: []string{}, Logger: memcached_pool_logger} defer pool.Close() // Should have an error err := pool.Open() c.Expect(err, gospec.Satisfies, err != nil) // Should be closed c.Expect(pool.IsClosed(), gospec.Equals, true) c.Expect(pool.Len(), gospec.Equals, -1) }) c.Specify("[MemcachedConnectionPool] Size=0 pool is Empty", func() { pool := MemcachedConnectionPool{Mode: AGRESSIVE, Size: 0, Urls: []string{}, Logger: memcached_pool_logger} defer pool.Close() // Shouldn't have any errors err := pool.Open() c.Expect(err, gospec.Equals, nil) // Should be open c.Expect(pool.IsOpen(), gospec.Equals, true) c.Expect(pool.IsClosed(), gospec.Equals, false) // Should be empty c.Expect(pool.Len(), gospec.Equals, 0) }) c.Specify("[MemcachedConnectionPool] Pop from empty pool returns error", func() { pool := MemcachedConnectionPool{Mode: AGRESSIVE, Size: 0, Urls: []string{}, Logger: memcached_pool_logger} defer pool.Close() // Shouldn't have any errors err := pool.Open() c.Expect(err, gospec.Equals, nil) // Should be open c.Expect(pool.IsOpen(), gospec.Equals, true) c.Expect(pool.IsClosed(), gospec.Equals, false) // Should be empty c.Expect(pool.Len(), gospec.Equals, 0) var connection *MemcachedConnection connection, err = pool.Pop() c.Expect(err, gospec.Equals, ErrNoConnectionsAvailable) c.Expect(connection, gospec.Satisfies, nil == connection) }) c.Specify("[MemcachedConnectionPool] Opening connection to Invalid Host/Port has errors", func() { pool := MemcachedConnectionPool{Mode: AGRESSIVE, Size: 1, Urls: []string{"127.0.0.1:11391"}, Logger: memcached_pool_logger} defer pool.Close() // Should have an error err := pool.Open() c.Expect(err, gospec.Satisfies, err != nil) // Should be closed c.Expect(pool.IsClosed(), gospec.Equals, true) c.Expect(pool.Len(), gospec.Equals, -1) }) c.Specify("[MemcachedConnectionPool] Opening connection to Valid Host/Port has no errors", func() { server, err := StartMemcachedServer(&memcached_pool_logger) if nil != err { panic(err) } defer server.Close() pool := MemcachedConnectionPool{Mode: AGRESSIVE, Size: 1, Urls: []string{server.Url()}, Logger: memcached_pool_logger} defer pool.Close() c.Expect(pool.Open(), gospec.Equals, nil) c.Expect(pool.IsOpen(), gospec.Equals, true) c.Expect(pool.IsClosed(), gospec.Equals, false) c.Expect(pool.IsClosed(), gospec.Satisfies, pool.IsOpen() != pool.IsClosed()) }) c.Specify("[MemcachedConnectionPool] 10x AGRESSIVE Pool Pops 10x open connections", func() { server, err := StartMemcachedServer(&memcached_pool_logger) if nil != err { panic(err) } defer server.Close() pool := MemcachedConnectionPool{Mode: AGRESSIVE, Size: 10, Urls: []string{server.Url()}, Logger: memcached_pool_logger} defer pool.Close() c.Expect(pool.Open(), gospec.Equals, nil) c.Expect(pool.IsOpen(), gospec.Equals, true) // Has 10x connections for count := 10; count > 0; count-- { // Count decrements when the connection is pop'd c.Expect(pool.Len(), gospec.Equals, count) connection, err := pool.Pop() c.Expect(pool.Len(), gospec.Equals, count-1) // Expecting an open connection c.Expect(err, gospec.Equals, nil) c.Expect(connection, gospec.Satisfies, connection != nil) c.Expect(connection.IsOpen(), gospec.Equals, true) } }) c.Specify("[MemcachedConnectionPool] 10x LAZY Pool Pops 10x closed connections", func() { server, err := StartMemcachedServer(&memcached_pool_logger) if nil != err { panic(err) } defer server.Close() pool := MemcachedConnectionPool{Mode: LAZY, Size: 10, Urls: []string{server.Url()}, Logger: memcached_pool_logger} defer pool.Close() c.Expect(pool.Open(), gospec.Equals, nil) c.Expect(pool.IsOpen(), gospec.Equals, true) // Has 10x connections for count := 10; count > 0; count-- { // Count decrements when the connection is pop'd c.Expect(pool.Len(), gospec.Equals, count) connection, err := pool.Pop() c.Expect(pool.Len(), gospec.Equals, count-1) // Expecting an open connection c.Expect(err, gospec.Equals, nil) c.Expect(connection, gospec.Satisfies, connection != nil) c.Expect(connection.IsClosed(), gospec.Equals, true) } }) }
func RedisBatchQueueWorkerSpecs(c gospec.Context) { c.Specify("[RedisBatchQueueWorker][Make]", func() { ptr, err := makeRedisBatchQueueWorker(nil, nil, 0, nil) c.Expect(err, gospec.Satisfies, nil != err) c.Expect(err.Error(), gospec.Equals, "[redisBatchQueueWorker][Make] Nil logger!") c.Expect(ptr, gospec.Satisfies, nil == ptr) logger := &log4go.Logger{} ptr, err = makeRedisBatchQueueWorker(logger, nil, 0, nil) c.Expect(err, gospec.Satisfies, nil != err) c.Expect(err.Error(), gospec.Equals, "[redisBatchQueueWorker][Make] Nil redis connection!") c.Expect(ptr, gospec.Satisfies, nil == ptr) connection := &RedisConnection{} ptr, err = makeRedisBatchQueueWorker(logger, connection, 0, nil) c.Expect(err, gospec.Satisfies, nil != err) c.Expect(err.Error(), gospec.Equals, "[redisBatchQueueWorker][Make] Nil queue!") c.Expect(ptr, gospec.Satisfies, nil == ptr) queue := make(chan *RedisBatchCommand) defer close(queue) ptr, err = makeRedisBatchQueueWorker(logger, connection, 0, queue) c.Expect(err, gospec.Satisfies, nil != err) c.Expect(err.Error(), gospec.Equals, "[redisBatchQueueWorker][Make] BatchSize must be greater than 0!") c.Expect(ptr, gospec.Satisfies, nil == ptr) batch_size := uint(1) ptr, err = makeRedisBatchQueueWorker(logger, connection, batch_size, queue) c.Expect(err, gospec.Satisfies, nil == err) c.Expect(ptr, gospec.Satisfies, nil != ptr) }) c.Specify("[RedisBatchQueueWorker][runCommands]", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() queue := make(chan *RedisBatchCommand) defer close(queue) worker, worker_err := makeRedisBatchQueueWorker(&logger, server.Connection(), 1, queue) c.Expect(worker_err, gospec.Equals, nil) c.Expect(worker, gospec.Satisfies, nil != worker) cmds := []*RedisBatchCommand{ MakeRedisBatchCommandSet("A", []byte("Bob")), MakeRedisBatchCommandSet("B", []byte("Gary")), } worker.runCommands(cmds) strs, strs_err := RedisDsl{server.Connection()}.MGET_STRINGS("A", "B") c.Expect(strs_err, gospec.Equals, nil) c.Expect(strs, gospec.Satisfies, 2 == len(strs)) c.Expect(*strs[0], gospec.Equals, "Bob") c.Expect(*strs[1], gospec.Equals, "Gary") }) c.Specify("[RedisBatchQueueWorker][mustPopCommand]", func() { prev := runtime.GOMAXPROCS(2) defer runtime.GOMAXPROCS(prev) logger := &log4go.Logger{} connection := &RedisConnection{} batch_size := uint(1) queue := make(chan *RedisBatchCommand, 2) defer close(queue) ptr, err := makeRedisBatchQueueWorker(logger, connection, batch_size, queue) c.Expect(err, gospec.Satisfies, nil == err) c.Expect(ptr, gospec.Satisfies, nil != ptr) counter := make(chan int, 2) defer close(counter) // Pop the command go func() { fmt.Println("Waiting for command ...") cmd, ok := ptr.mustPopCommand() fmt.Println("Got command:", cmd, ok) counter <- 1 fmt.Println("Forwarded command:", cmd, ok) }() time.Sleep(time.Millisecond) fmt.Println("Queue sizes:", len(queue), len(counter)) c.Expect(len(counter), gospec.Equals, 0) queue <- &RedisBatchCommand{} fmt.Println("Queue sizes:", len(queue), len(counter)) time.Sleep(10 * time.Millisecond) fmt.Println("Queue sizes:", len(queue), len(counter)) c.Expect(len(counter), gospec.Equals, 1) <-counter fmt.Println("Queue sizes:", len(queue), len(counter)) }) c.Specify("[RedisBatchQueueWorker][mayPopCommand]", func() { prev := runtime.GOMAXPROCS(2) defer runtime.GOMAXPROCS(prev) logger := &log4go.Logger{} connection := &RedisConnection{} batch_size := uint(1) queue := make(chan *RedisBatchCommand, 2) defer close(queue) ptr, err := makeRedisBatchQueueWorker(logger, connection, batch_size, queue) c.Expect(err, gospec.Satisfies, nil == err) c.Expect(ptr, gospec.Satisfies, nil != ptr) cmd, ok := ptr.mayPopCommand() c.Expect(cmd, gospec.Satisfies, nil == cmd) c.Expect(ok, gospec.Equals, true) c.Expect(len(queue), gospec.Equals, 0) queue <- &RedisBatchCommand{} c.Expect(len(queue), gospec.Equals, 1) cmd, ok = ptr.mayPopCommand() c.Expect(cmd, gospec.Satisfies, nil != cmd) c.Expect(ok, gospec.Equals, true) c.Expect(len(queue), gospec.Equals, 0) }) c.Specify("[RedisBatchQueueWorker][popCommands]", func() { prev := runtime.GOMAXPROCS(2) defer runtime.GOMAXPROCS(prev) logger := &log4go.Logger{} connection := &RedisConnection{} batch_size := uint(10) queue := make(chan *RedisBatchCommand, int(batch_size*3)) defer close(queue) ptr, err := makeRedisBatchQueueWorker(logger, connection, batch_size, queue) c.Expect(err, gospec.Satisfies, nil == err) c.Expect(ptr, gospec.Satisfies, nil != ptr) counter := make(chan int, 2) defer close(counter) // Pop the commands pop := func() { cmds, _ := ptr.popCommands() counter <- len(cmds) } c.Expect(len(queue), gospec.Equals, 0) c.Expect(len(counter), gospec.Equals, 0) queue <- &RedisBatchCommand{} c.Expect(len(queue), gospec.Equals, 1) c.Expect(len(counter), gospec.Equals, 0) go pop() time.Sleep(time.Millisecond) c.Expect(len(queue), gospec.Equals, 0) c.Expect(len(counter), gospec.Equals, 1) count, ok := <-counter c.Expect(count, gospec.Equals, 1) c.Expect(ok, gospec.Equals, true) for i := 0; i < 15; i++ { queue <- &RedisBatchCommand{} } c.Expect(len(queue), gospec.Equals, 15) c.Expect(len(counter), gospec.Equals, 0) // Pops 1x batch_size commands go pop() time.Sleep(time.Millisecond) c.Expect(len(queue), gospec.Equals, 5) c.Expect(len(counter), gospec.Equals, 1) // Counts the correct number of commands count, ok = <-counter c.Expect(count, gospec.Equals, 10) c.Expect(ok, gospec.Equals, true) // Pops 1/2x batch_size commands go pop() time.Sleep(time.Millisecond) c.Expect(len(queue), gospec.Equals, 0) c.Expect(len(counter), gospec.Equals, 1) // Pop a partial batch: count, ok = <-counter c.Expect(count, gospec.Equals, 5) c.Expect(ok, gospec.Equals, true) }) c.Specify("[RedisBatchQueueWorker][Run]", func() { prev := runtime.GOMAXPROCS(2) defer runtime.GOMAXPROCS(prev) logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() batch_size := uint(10) queue := make(chan *RedisBatchCommand, int(batch_size*3)) // defer close(queue) ptr, err := makeRedisBatchQueueWorker(&logger, server.Connection(), batch_size, queue) c.Expect(err, gospec.Satisfies, nil == err) c.Expect(ptr, gospec.Satisfies, nil != ptr) // Runs the task until the queue is closed go ptr.Run() queue <- MakeRedisBatchCommandHashIncrementBy("Hash", "Field A", 1) queue <- MakeRedisBatchCommandHashIncrementBy("Hash", "Field B", 10) queue <- MakeRedisBatchCommandHashIncrementBy("Hash", "Field C", 100) time.Sleep(50 * time.Millisecond) ints, ints_err := RedisDsl{server.Connection()}.HASH_MGET_INT64S("Hash", "Field A", "Field B", "Field C") c.Expect(ints_err, gospec.Equals, nil) c.Expect(len(ints), gospec.Equals, 3) c.Expect(*ints[0], gospec.Equals, int64(1)) c.Expect(*ints[1], gospec.Equals, int64(10)) c.Expect(*ints[2], gospec.Equals, int64(100)) queue <- MakeRedisBatchCommandHashDelete("Hash", "Field A", "Field B", "Field C") time.Sleep(time.Millisecond) close(queue) time.Sleep(50 * time.Millisecond) ints, ints_err = RedisDsl{server.Connection()}.HASH_MGET_INT64S("Hash", "Field A", "Field B", "Field C") c.Expect(ints_err, gospec.Equals, nil) c.Expect(len(ints), gospec.Equals, 3) c.Expect(ints[0], gospec.Satisfies, nil == ints[0]) c.Expect(ints[1], gospec.Satisfies, nil == ints[1]) c.Expect(ints[2], gospec.Satisfies, nil == ints[2]) }) }
// Helpers func RedisPoolSpecs(c gospec.Context) { var redis_pool_logger = log4go.NewDefaultLogger(log4go.CRITICAL) c.Specify("[RedisConnectionPool] New Pool is not open", func() { pool := RedisConnectionPool{Mode: AGRESSIVE, Size: 0, Urls: []string{}, Logger: redis_pool_logger} defer pool.Close() c.Expect(pool.IsOpen(), gospec.Equals, false) c.Expect(pool.IsClosed(), gospec.Equals, true) c.Expect(pool.IsOpen(), gospec.Satisfies, pool.IsOpen() != pool.IsClosed()) c.Expect(pool.Len(), gospec.Equals, -1) }) c.Specify("[RedisConnectionPool] Opening a Pool with Undefined Mode has errors", func() { pool := RedisConnectionPool{Mode: 0, Size: 0, Urls: []string{}, Logger: redis_pool_logger} defer pool.Close() // Should have an error err := pool.Open() c.Expect(err, gospec.Satisfies, err != nil) // Should be closed c.Expect(pool.IsClosed(), gospec.Equals, true) c.Expect(pool.Len(), gospec.Equals, -1) }) c.Specify("[RedisConnectionPool] Size=0 pool is Empty", func() { pool := RedisConnectionPool{Mode: AGRESSIVE, Size: 0, Urls: []string{}, Logger: redis_pool_logger} defer pool.Close() // Shouldn't have any errors err := pool.Open() c.Expect(err, gospec.Equals, nil) // Should be open c.Expect(pool.IsOpen(), gospec.Equals, true) c.Expect(pool.IsClosed(), gospec.Equals, false) // Should be empty c.Expect(pool.Len(), gospec.Equals, 0) }) c.Specify("[RedisConnectionPool] Pop from empty pool returns error", func() { pool := RedisConnectionPool{Mode: AGRESSIVE, Size: 0, Urls: []string{}, Logger: redis_pool_logger} defer pool.Close() // Shouldn't have any errors err := pool.Open() c.Expect(err, gospec.Equals, nil) // Should be open c.Expect(pool.IsOpen(), gospec.Equals, true) c.Expect(pool.IsClosed(), gospec.Equals, false) // Should be empty c.Expect(pool.Len(), gospec.Equals, 0) var connection *RedisConnection connection, err = pool.Pop() c.Expect(err, gospec.Equals, ErrNoConnectionsAvailable) c.Expect(connection, gospec.Satisfies, nil == connection) }) c.Specify("[RedisConnectionPool] Opening connection to Invalid Host/Port has errors", func() { pool := RedisConnectionPool{Mode: AGRESSIVE, Size: 1, Urls: []string{"127.0.0.1:6991"}, Logger: redis_pool_logger} defer pool.Close() // Should have an error err := pool.Open() c.Expect(err, gospec.Satisfies, err != nil) // Should be closed c.Expect(pool.IsClosed(), gospec.Equals, true) c.Expect(pool.Len(), gospec.Equals, -1) }) c.Specify("[RedisConnectionPool] Opening connection to Valid Host/Port has no errors", func() { pool := RedisConnectionPool{Mode: AGRESSIVE, Size: 1, Urls: []string{"127.0.0.1:6992"}, Logger: redis_pool_logger} defer pool.Close() // Start the server ... cmd := exec.Command("redis-server", "--port", "6992") err := cmd.Start() c.Expect(err, gospec.Equals, nil) if err != nil { // Abort on errors return } time.Sleep(time.Duration(1) * time.Second) defer cmd.Wait() defer cmd.Process.Kill() err = pool.Open() c.Expect(err, gospec.Equals, nil) c.Expect(pool.IsOpen(), gospec.Equals, true) c.Expect(pool.IsClosed(), gospec.Equals, false) c.Expect(pool.IsClosed(), gospec.Satisfies, pool.IsOpen() != pool.IsClosed()) }) c.Specify("[RedisConnectionPool] 10x AGRESSIVE Pool Pops 10x open connections", func() { pool := RedisConnectionPool{Mode: AGRESSIVE, Size: 10, Urls: []string{"127.0.0.1:6993"}, Logger: redis_pool_logger} defer pool.Close() // Start the server ... cmd := exec.Command("redis-server", "--port", "6993") err := cmd.Start() c.Expect(err, gospec.Equals, nil) if err != nil { // Abort on errors return } time.Sleep(time.Duration(1) * time.Second) defer cmd.Wait() defer cmd.Process.Kill() err = pool.Open() c.Expect(err, gospec.Equals, nil) c.Expect(pool.IsOpen(), gospec.Equals, true) // Has 10x connections var connection *RedisConnection for count := 10; count > 0; count-- { // Count decrements when the connection is pop'd c.Expect(pool.Len(), gospec.Equals, count) connection, err = pool.Pop() c.Expect(pool.Len(), gospec.Equals, count-1) // Expecting an open connection c.Expect(err, gospec.Equals, nil) c.Expect(connection, gospec.Satisfies, connection != nil) c.Expect(connection.IsOpen(), gospec.Equals, true) } }) c.Specify("[RedisConnectionPool] 10x LAZY Pool Pops 10x closed connections", func() { pool := RedisConnectionPool{Mode: LAZY, Size: 10, Urls: []string{"127.0.0.1:6994"}, Logger: redis_pool_logger} defer pool.Close() // Start the server ... cmd := exec.Command("redis-server", "--port", "6994") err := cmd.Start() c.Expect(err, gospec.Equals, nil) if err != nil { // Abort on errors return } time.Sleep(time.Duration(1) * time.Second) defer cmd.Wait() defer cmd.Process.Kill() err = pool.Open() c.Expect(err, gospec.Equals, nil) c.Expect(pool.IsOpen(), gospec.Equals, true) // Has 10x connections var connection *RedisConnection for count := 10; count > 0; count-- { // Count decrements when the connection is pop'd c.Expect(pool.Len(), gospec.Equals, count) connection, err = pool.Pop() c.Expect(pool.Len(), gospec.Equals, count-1) // Expecting an open connection c.Expect(err, gospec.Equals, nil) c.Expect(connection, gospec.Satisfies, connection != nil) c.Expect(connection.IsClosed(), gospec.Equals, true) } }) }
// Helpers func RedisBatchCommandsSpecs(c gospec.Context) { c.Specify("[RedisBatchCommands] PING Test", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommand("PING") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) str, _ := commands[0].Reply().Str() c.Expect(commands[0].Reply(), gospec.Satisfies, str == "PONG") }) c.Specify("[RedisBatchCommands] Value Exists", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SET", "Bob", "123") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 2) commands[0] = MakeRedisBatchCommandExists("Bob") commands[1] = MakeRedisBatchCommandExists("George") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 1) ok, _ = commands[1].Reply().Int() c.Expect(commands[1].Reply(), gospec.Satisfies, ok == 0) }) c.Specify("[RedisBatchCommands] Expire value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) commands := RedisBatchCommands{ // Expects -2 MakeRedisBatchCommandGetExpiresIn("Bob"), // Expects OK MakeRedisBatchCommandSet("Bob", []byte("123")), // Expects -1 MakeRedisBatchCommandGetExpiresIn("Bob"), // Expects OK MakeRedisBatchCommandExpireIn("Bob", time.Duration(1)*time.Second), // Expects ~1s MakeRedisBatchCommandGetExpiresIn("Bob"), // Clear the TTL MakeRedisBatchCommandPersist("Bob"), // Expects -1 MakeRedisBatchCommandGetExpiresIn("Bob"), // Set the TTL again, and use a Sleep below to test the expiration MakeRedisBatchCommandExpireIn("Bob", time.Duration(1)*time.Second), } err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Expects -2, or -1 for older redis's ttl, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ttl == -2 || ttl == -1) // Expects OK ok, _ := commands[1].Reply().Bool() c.Expect(commands[1].Reply(), gospec.Satisfies, ok) // Expects -1 ttl, _ = commands[2].Reply().Int() c.Expect(commands[2].Reply(), gospec.Satisfies, ttl == -1) // Expects OK ok, _ = commands[3].Reply().Bool() c.Expect(commands[3].Reply(), gospec.Satisfies, ok) // Expects ~1s ttl, _ = commands[4].Reply().Int() c.Expect(commands[4].Reply(), gospec.Satisfies, ttl == 1) // Expects 1, for TTL removed ttl, _ = commands[5].Reply().Int() c.Expect(commands[5].Reply(), gospec.Satisfies, ttl == 1) ttl, _ = commands[6].Reply().Int() c.Expect(commands[6].Reply(), gospec.Satisfies, ttl == -1) // Sleep for 1.5 seconds time.Sleep(time.Duration(1500) * time.Millisecond) // Value has expired! reply := server.Connection().Cmd("GET", "Bob") c.Expect(reply, gospec.Satisfies, reply.Type == redis.NilReply) }) c.Specify("[RedisBatchCommands] Delete values", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SET", "Bob", "123") server.Connection().Cmd("SET", "Gary", "456") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandDelete("Bob", "Gary", "George") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Deleted 2 keys: count, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, count == 2) }) c.Specify("[RedisBatchCommands] Mget values", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SET", "Bob", "123") server.Connection().Cmd("SET", "Gary", "456") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandMget("Bob", "Gary", "George") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Cache Hit on 2x; Cache Miss on 1x bytes_array, _ := commands[0].Reply().ListBytes() c.Expect(commands[0].Reply(), gospec.Satisfies, len(bytes_array) == 3) c.Expect(commands[0].Reply(), gospec.Satisfies, string(bytes_array[0]) == "123") c.Expect(commands[0].Reply(), gospec.Satisfies, string(bytes_array[1]) == "456") c.Expect(commands[0].Reply(), gospec.Satisfies, len(bytes_array[2]) == 0) }) c.Specify("[RedisBatchCommands] Get values", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SET", "Bob", "123") server.Connection().Cmd("SET", "Gary", "456") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 3) commands[0] = MakeRedisBatchCommandGet("Bob") commands[1] = MakeRedisBatchCommandGet("Gary") commands[2] = MakeRedisBatchCommandGet("George") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Cache Hit on 2x; Cache Miss on 1x str, _ := commands[0].Reply().Str() c.Expect(commands[0].Reply(), gospec.Satisfies, str == "123") str, _ = commands[1].Reply().Str() c.Expect(commands[1].Reply(), gospec.Satisfies, str == "456") str, _ = commands[2].Reply().Str() c.Expect(commands[2].Reply(), gospec.Satisfies, str == "") }) c.Specify("[RedisBatchCommands] Set value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandSet("Bob", []byte("123")) err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Str() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == "OK") }) c.Specify("[RedisBatchCommands] IncrementBy value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandIncrementBy("Bob", 123) err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Returns the new value ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 123) }) c.Specify("[RedisBatchCommands] IncrementByFloat value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandIncrementByFloat("Bob", 123.456) err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Returns the new value ok, _ := commands[0].Reply().Float64() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 123.456) }) c.Specify("[RedisBatchCommands] Hash Value Exists", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("HSET", "Bob", "123", "") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 2) commands[0] = MakeRedisBatchCommandHashExists("Bob", "123") commands[1] = MakeRedisBatchCommandHashExists("Bob", "George") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 1) ok, _ = commands[1].Reply().Int() c.Expect(commands[1].Reply(), gospec.Satisfies, ok == 0) }) c.Specify("[RedisBatchCommands] Hash Delete values", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("HSET", "Bob", "A", "123") str, _ := server.Connection().Cmd("HGET", "Bob", "A").Str() c.Expect(str, gospec.Equals, "123") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandHashDelete("Bob", "A") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Deleted 1 keys: count, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, count == 1) }) c.Specify("[RedisBatchCommands] Hash Mget values", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("HSET", "A", "Bob", "123") server.Connection().Cmd("HSET", "A", "Gary", "456") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandHashMget("A", "Bob", "Gary", "George") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Cache Hit on 2x; Cache Miss on 1x bytes_array, _ := commands[0].Reply().ListBytes() c.Expect(commands[0].Reply(), gospec.Satisfies, len(bytes_array) == 3) c.Expect(commands[0].Reply(), gospec.Satisfies, string(bytes_array[0]) == "123") c.Expect(commands[0].Reply(), gospec.Satisfies, string(bytes_array[1]) == "456") c.Expect(commands[0].Reply(), gospec.Satisfies, len(bytes_array[2]) == 0) }) c.Specify("[RedisBatchCommands] Hash Get values", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("HSET", "Bob", "A", "123") server.Connection().Cmd("HSET", "Gary", "A", "456") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 3) commands[0] = MakeRedisBatchCommandHashGet("Bob", "A") commands[1] = MakeRedisBatchCommandHashGet("Gary", "A") commands[2] = MakeRedisBatchCommandHashGet("George", "A") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Cache Hit on 2x; Cache Miss on 1x str, _ := commands[0].Reply().Str() c.Expect(commands[0].Reply(), gospec.Satisfies, str == "123") str, _ = commands[1].Reply().Str() c.Expect(commands[1].Reply(), gospec.Satisfies, str == "456") str, _ = commands[2].Reply().Str() c.Expect(commands[2].Reply(), gospec.Satisfies, str == "") }) c.Specify("[RedisBatchCommands] Hash Set value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandHashSet("Bob", "A", []byte("123")) err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 1) }) c.Specify("[RedisBatchCommands] Hash IncrementBy value", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandHashIncrementBy("Bob", "A", 123) err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) // Returns the new hash value ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 123) }) c.Specify("[MakeRedisBatchCommand][Bitop][And] Makes command", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SETBIT", "Bob", "123", "1") server.Connection().Cmd("SETBIT", "Gary", "456", "1") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandBitopAnd("DEST", "Bob", "Gary") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 58) }) c.Specify("[MakeRedisBatchCommand][Bitop][Or] Makes command", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SETBIT", "Bob", "123", "1") server.Connection().Cmd("SETBIT", "Gary", "456", "1") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandBitopOr("DEST", "Bob", "Gary") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 58) }) c.Specify("[MakeRedisBatchCommand][Bitop][Not] Makes command", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SETBIT", "Bob", "123", "1") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandBitopNot("DEST", "Bob") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 16) }) c.Specify("[MakeRedisBatchCommand][BitCount] Makes command", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SETBIT", "Bob", "123", "1") server.Connection().Cmd("SETBIT", "Bob", "456", "1") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandBitCount("Bob") err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 2) }) c.Specify("[MakeRedisBatchCommand][BitCount] Makes command", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) server.Connection().Cmd("SETBIT", "Bob", "123", "1") var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 2) commands[0] = MakeRedisBatchCommandGetBit("Bob", 123) commands[1] = MakeRedisBatchCommandGetBit("Bob", 456) err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 1) ok, _ = commands[1].Reply().Int() c.Expect(commands[1].Reply(), gospec.Satisfies, ok == 0) }) c.Specify("[MakeRedisBatchCommand][SetBit] Makes command", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().IsClosed(), gospec.Equals, true) var commands RedisBatchCommands commands = make([]*RedisBatchCommand, 1) commands[0] = MakeRedisBatchCommandSetBit("Bob", 123, true) err = commands.ExecuteBatch(server.Connection()) c.Expect(err, gospec.Equals, nil) ok, _ := commands[0].Reply().Int() c.Expect(commands[0].Reply(), gospec.Satisfies, ok == 0) }) }
// Helpers func RedisConnectionSpecs(c gospec.Context) { var redis_connection_logger = log4go.NewDefaultLogger(log4go.CRITICAL) c.Specify("[RedisConnection] Clone a connection", func() { connection := &RedisConnection{Url: "127.0.0.1:6990", Id: "Bob", Logger: &redis_connection_logger} defer connection.Close() c.Expect(connection.IsOpen(), gospec.Equals, false) connection2 := connection.Clone() defer connection2.Close() c.Expect(connection2.IsOpen(), gospec.Equals, false) // Should be differient pointers c.Expect(connection2, gospec.Satisfies, connection != connection2) }) c.Specify("[RedisConnection] New connection is not open", func() { connection := RedisConnection{Url: "127.0.0.1:6990", Logger: &redis_connection_logger} defer connection.Close() open := connection.IsOpen() closed := connection.IsClosed() // Should be opposite of each other: c.Expect(open, gospec.Equals, false) c.Expect(closed, gospec.Equals, true) c.Expect(closed, gospec.Satisfies, open != closed) }) c.Specify("[RedisConnection] Opening connection to Invalid Host/Port has errors", func() { connection := RedisConnection{Url: "127.0.0.1:6991", Logger: &redis_connection_logger} defer connection.Close() // The server is not running ... // This should return an error err := connection.Open() c.Expect(err, gospec.Satisfies, err != nil) closed := connection.IsClosed() c.Expect(closed, gospec.Equals, true) }) c.Specify("[RedisConnection] Opening connection to Valid Host/Port has no errors", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() c.Expect(server.Connection().Open(), gospec.Equals, nil) c.Expect(server.Connection().IsOpen(), gospec.Equals, true) c.Expect(server.Connection().IsClosed(), gospec.Equals, false) }) c.Specify("[RedisConnection][KeysExist] Checks if keys exists", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, server_err := StartRedisServer(&logger) if nil != server_err { panic(server_err) } defer server.Close() keys := []string{"Key", "Bob", "George", "Alex", "Applause"} for _, key := range keys { server.Connection().Cmd("SET", key, "123") } oks, err := server.Connection().KeysExist(keys...) c.Expect(err, gospec.Equals, nil) c.Expect(len(oks), gospec.Equals, len(keys)) for _, ok := range oks { c.Expect(ok, gospec.Equals, true) } // Cache Miss server.Connection().Cmd("DEL", keys) oks, err = server.Connection().KeysExist(keys...) c.Expect(err, gospec.Equals, nil) c.Expect(len(oks), gospec.Equals, len(keys)) for _, ok := range oks { c.Expect(ok, gospec.Equals, false) } }) c.Specify("[RedisConnection][HashFieldsExist] Checks if keys exists", func() { logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, server_err := StartRedisServer(&logger) if nil != server_err { panic(server_err) } defer server.Close() fields := []string{"Key", "Bob", "George", "Alex", "Applause"} for _, field := range fields { server.Connection().Cmd("HSET", "Hash Name", field, "123") } oks, err := server.Connection().HashFieldsExist("Hash Name", fields...) c.Expect(err, gospec.Equals, nil) c.Expect(len(oks), gospec.Equals, len(fields)) for _, ok := range oks { c.Expect(ok, gospec.Equals, true) } // Cache Miss server.Connection().Cmd("HDEL", "Hash Name", fields) oks, err = server.Connection().HashFieldsExist("Hash Name", fields...) c.Expect(err, gospec.Equals, nil) c.Expect(len(oks), gospec.Equals, len(fields)) for _, ok := range oks { c.Expect(ok, gospec.Equals, false) } // Cache Miss oks, err = server.Connection().HashFieldsExist("Hash Missing", fields...) c.Expect(err, gospec.Equals, nil) c.Expect(len(oks), gospec.Equals, len(fields)) for _, ok := range oks { c.Expect(ok, gospec.Equals, false) } }) c.Specify("[RedisConnection] Ping (-->Cmd-->Append+GetReply) (re-)opens the connection automatically", func() { logger := log4go.NewDefaultLogger(log4go.INFO) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() // Starts off closed ... c.Expect(server.Connection().IsClosed(), gospec.Equals, true) // Ping the server // Should now be open c.Expect(server.Connection().Ping(), gospec.Equals, nil) c.Expect(server.Connection().IsOpen(), gospec.Equals, true) c.Expect(server.Connection().IsClosed(), gospec.Equals, false) // Close the connection c.Expect(server.Connection().Close(), gospec.Equals, nil) c.Expect(server.Connection().IsClosed(), gospec.Equals, true) // Ping the server again // Should now be open again c.Expect(server.Connection().Ping(), gospec.Equals, nil) c.Expect(server.Connection().IsOpen(), gospec.Equals, true) c.Expect(server.Connection().IsClosed(), gospec.Equals, false) }) }
func RedisBatchQueueSpecs(c gospec.Context) { c.Specify("[RedisBatchQueue][Cap]", func() { ptr := &RedisBatchQueue{ queue: nil, } c.Expect(ptr.Cap(), gospec.Equals, -1) ptr.queue = make(chan *RedisBatchCommand, 10) defer close(ptr.queue) c.Expect(ptr.Cap(), gospec.Equals, 10) }) c.Specify("[RedisBatchQueue][Len]", func() { ptr := &RedisBatchQueue{ queue: nil, } c.Expect(ptr.Len(), gospec.Equals, -1) ptr.queue = make(chan *RedisBatchCommand, 10) defer close(ptr.queue) c.Expect(ptr.Len(), gospec.Equals, 0) ptr.queue <- &RedisBatchCommand{} c.Expect(ptr.Len(), gospec.Equals, 1) }) c.Specify("[RedisBatchQueue][String]", func() { ptr := &RedisBatchQueue{ QueueSize: 10, WorkersSize: 1, WorkersBatchSize: 5, queue: make(chan *RedisBatchCommand, 10), } defer close(ptr.queue) c.Expect(ptr.String(), gospec.Equals, "RedisBatchQueue { Connection=<nil>, QueueSize=10, WorkersSize=1, WorkersBatchSize=5, Queue.Cap=10, Queue.Len=0 }") }) c.Specify("[RedisBatchQueue][Open]", func() { ptr := &RedisBatchQueue{} defer ptr.Close() err := ptr.Open() c.Expect(err, gospec.Satisfies, nil != err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][Open] Nil Logger!") ptr.Logger = &log4go.Logger{} ptr.queue = make(chan *RedisBatchCommand, 10) err = ptr.Open() c.Expect(err, gospec.Satisfies, nil != err) c.Expect(ptr.queue, gospec.Satisfies, nil != ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][Open] Queue is already open!") close(ptr.queue) ptr.queue = nil err = ptr.Open() c.Expect(err, gospec.Satisfies, nil != err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][Open] Nil redis connection!") ptr.Connection = &RedisConnection{} err = ptr.Open() c.Expect(err, gospec.Satisfies, nil != err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][Open] QueueSize[0] must be > 0!") ptr.QueueSize = 10 err = ptr.Open() c.Expect(err, gospec.Satisfies, nil != err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][Open] WorkersSize[0] must be > 0!") ptr.WorkersSize = 20 err = ptr.Open() c.Expect(err, gospec.Satisfies, nil != err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][Open] WorkersBatchSize[0] must be > 0!") ptr.WorkersBatchSize = 5 err = ptr.Open() c.Expect(err, gospec.Satisfies, nil != err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][Open] QueueSize[10] must be > WorkersSize[20]!") ptr.WorkersSize = 10 err = ptr.Open() c.Expect(err, gospec.Equals, nil) c.Expect(ptr.queue, gospec.Satisfies, nil != ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 < len(ptr.workers)) }) c.Specify("[RedisBatchQueue][Close]", func() { ptr := &RedisBatchQueue{} err := ptr.Close() c.Expect(err, gospec.Satisfies, nil == err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) ptr.queue = make(chan *RedisBatchCommand, 10) ptr.workers = []*redisBatchQueueWorker{nil, nil, nil, nil, nil} err = ptr.Close() c.Expect(err, gospec.Satisfies, nil == err) c.Expect(ptr.queue, gospec.Satisfies, nil == ptr.queue) c.Expect(ptr.workers, gospec.Satisfies, 0 == len(ptr.workers)) }) c.Specify("[RedisBatchQueue][RunAsync]", func() { prev := runtime.GOMAXPROCS(2) defer runtime.GOMAXPROCS(prev) logger := log4go.NewDefaultLogger(log4go.CRITICAL) server, err := StartRedisServer(&logger) if nil != err { panic(err) } defer server.Close() ptr := &RedisBatchQueue{ Logger: &logger, Connection: server.Connection(), QueueSize: 10, WorkersSize: 5, WorkersBatchSize: 2, } err = ptr.RunAsync(nil) c.Expect(err, gospec.Satisfies, nil != err) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][RunAsync] Queue is closed!") err = ptr.Open() c.Expect(err, gospec.Satisfies, nil == err) err = ptr.RunAsync(nil) c.Expect(err, gospec.Satisfies, nil != err) c.Expect(err.Error(), gospec.Equals, "[RedisBatchQueue][RunAsync][0] Nil RedisBatchCommand!") err = ptr.RunAsync( MakeRedisBatchCommandHashIncrementBy("Hash", "Field A", 1), MakeRedisBatchCommandHashIncrementBy("Hash", "Field B", 10), MakeRedisBatchCommandHashIncrementBy("Hash", "Field C", 100), ) c.Expect(err, gospec.Satisfies, nil == err) time.Sleep(50 * time.Millisecond) ints, ints_err := RedisDsl{server.Connection()}.HASH_MGET_INT64S("Hash", "Field A", "Field B", "Field C") c.Expect(ints_err, gospec.Equals, nil) c.Expect(len(ints), gospec.Equals, 3) c.Expect(*ints[0], gospec.Equals, int64(1)) c.Expect(*ints[1], gospec.Equals, int64(10)) c.Expect(*ints[2], gospec.Equals, int64(100)) err = ptr.RunAsync( MakeRedisBatchCommandHashDelete("Hash", "Field A", "Field B", "Field C"), ) c.Expect(err, gospec.Satisfies, nil == err) time.Sleep(time.Millisecond) ptr.Close() time.Sleep(50 * time.Millisecond) ints, ints_err = RedisDsl{server.Connection()}.HASH_MGET_INT64S("Hash", "Field A", "Field B", "Field C") c.Expect(ints_err, gospec.Equals, nil) c.Expect(len(ints), gospec.Equals, 3) c.Expect(ints[0], gospec.Satisfies, nil == ints[0]) c.Expect(ints[1], gospec.Satisfies, nil == ints[1]) c.Expect(ints[2], gospec.Satisfies, nil == ints[2]) }) }