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 }