mirror of https://github.com/tidwall/tile38.git
219 lines
4.8 KiB
Go
219 lines
4.8 KiB
Go
package tests
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gomodule/redigo/redis"
|
|
"github.com/tidwall/gjson"
|
|
)
|
|
|
|
func subTestFence(t *testing.T, mc *mockServer) {
|
|
runStep(t, mc, "basic", fence_basic_test)
|
|
runStep(t, mc, "detect inside,outside", fence_detect_inside_test)
|
|
}
|
|
|
|
type fenceReader struct {
|
|
conn net.Conn
|
|
rd *bufio.Reader
|
|
}
|
|
|
|
func (fr *fenceReader) receive() (string, error) {
|
|
if err := fr.conn.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
|
|
return "", err
|
|
}
|
|
line, err := fr.rd.ReadBytes('\n')
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(line) < 4 || line[0] != '$' || line[len(line)-2] != '\r' || line[len(line)-1] != '\n' {
|
|
return "", errors.New("invalid message")
|
|
}
|
|
n, err := strconv.ParseUint(string(line[1:len(line)-2]), 10, 64)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
buf := make([]byte, int(n)+2)
|
|
_, err = io.ReadFull(fr.rd, buf)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if buf[len(buf)-2] != '\r' || buf[len(buf)-1] != '\n' {
|
|
return "", errors.New("invalid message")
|
|
}
|
|
js := buf[:len(buf)-2]
|
|
var m interface{}
|
|
if err := json.Unmarshal(js, &m); err != nil {
|
|
return "", err
|
|
}
|
|
return string(js), nil
|
|
}
|
|
|
|
func (fr *fenceReader) receiveExpect(valex ...string) error {
|
|
s, err := fr.receive()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for i := 0; i < len(valex); i += 2 {
|
|
if gjson.Get(s, valex[i]).String() != valex[i+1] {
|
|
return fmt.Errorf("expected '%s'='%s', got '%s'", valex[i], valex[i+1], gjson.Get(s, valex[i]).String())
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func fence_basic_test(mc *mockServer) error {
|
|
conn, err := net.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
_, err = fmt.Fprintf(conn, "NEARBY mykey FENCE POINT 33 -115 5000\r\n")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
buf := make([]byte, 4096)
|
|
n, err := conn.Read(buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res := string(buf[:n])
|
|
if res != "+OK\r\n" {
|
|
return fmt.Errorf("expected OK, got '%v'", res)
|
|
}
|
|
rd := &fenceReader{conn, bufio.NewReader(conn)}
|
|
|
|
// send a point
|
|
c, err := redis.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer c.Close()
|
|
|
|
res, err = redis.String(c.Do("SET", "mykey", "myid1", "POINT", 33, -115))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res != "OK" {
|
|
return fmt.Errorf("expected OK, got '%v'", res)
|
|
}
|
|
|
|
// receive the message
|
|
if err := rd.receiveExpect("command", "set",
|
|
"detect", "enter",
|
|
"key", "mykey",
|
|
"id", "myid1",
|
|
"object.type", "Point",
|
|
"object.coordinates", "[-115,33]"); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := rd.receiveExpect("command", "set",
|
|
"detect", "inside",
|
|
"key", "mykey",
|
|
"id", "myid1",
|
|
"object.type", "Point",
|
|
"object.coordinates", "[-115,33]"); err != nil {
|
|
return err
|
|
}
|
|
|
|
res, err = redis.String(c.Do("SET", "mykey", "myid1", "POINT", 34, -115))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res != "OK" {
|
|
return fmt.Errorf("expected OK, got '%v'", res)
|
|
}
|
|
|
|
// receive the message
|
|
if err := rd.receiveExpect("command", "set",
|
|
"detect", "exit",
|
|
"key", "mykey",
|
|
"id", "myid1",
|
|
"object.type", "Point",
|
|
"object.coordinates", "[-115,34]"); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := rd.receiveExpect("command", "set",
|
|
"detect", "outside",
|
|
"key", "mykey",
|
|
"id", "myid1",
|
|
"object.type", "Point",
|
|
"object.coordinates", "[-115,34]"); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
func fence_detect_inside_test(mc *mockServer) error {
|
|
conn, err := net.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer conn.Close()
|
|
_, err = fmt.Fprintf(conn, "WITHIN users FENCE DETECT inside,outside POINTS BOUNDS 33.618824 -84.457973 33.654359 -84.399859\r\n")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
buf := make([]byte, 4096)
|
|
n, err := conn.Read(buf)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res := string(buf[:n])
|
|
if res != "+OK\r\n" {
|
|
return fmt.Errorf("expected OK, got '%v'", res)
|
|
}
|
|
rd := &fenceReader{conn, bufio.NewReader(conn)}
|
|
|
|
// send a point
|
|
c, err := redis.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer c.Close()
|
|
|
|
res, err = redis.String(c.Do("SET", "users", "200", "POINT", "33.642301", "-84.43118"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res != "OK" {
|
|
return fmt.Errorf("expected OK, got '%v'", res)
|
|
}
|
|
|
|
if err := rd.receiveExpect("command", "set",
|
|
"detect", "inside",
|
|
"key", "users",
|
|
"id", "200",
|
|
"point", `{"lat":33.642301,"lon":-84.43118}`); err != nil {
|
|
return err
|
|
}
|
|
|
|
res, err = redis.String(c.Do("SET", "users", "200", "POINT", "34.642301", "-84.43118"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if res != "OK" {
|
|
return fmt.Errorf("expected OK, got '%v'", res)
|
|
}
|
|
|
|
// receive the message
|
|
if err := rd.receiveExpect("command", "set",
|
|
"detect", "outside",
|
|
"key", "users",
|
|
"id", "200",
|
|
"point", `{"lat":34.642301,"lon":-84.43118}`); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|