2019-01-10 21:28:29 +03:00
|
|
|
package tests
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2020-03-22 21:54:56 +03:00
|
|
|
"sync"
|
|
|
|
"time"
|
2019-01-10 21:28:29 +03:00
|
|
|
|
|
|
|
"github.com/gomodule/redigo/redis"
|
|
|
|
"github.com/tidwall/pretty"
|
|
|
|
"github.com/tidwall/sjson"
|
|
|
|
)
|
|
|
|
|
|
|
|
func fence_roaming_webhook_test(mc *mockServer) error {
|
|
|
|
car1, car2, expected := roamingTestData()
|
|
|
|
finalErr := make(chan error)
|
|
|
|
|
|
|
|
// Create a connection for subscribing to geofence notifications
|
|
|
|
sc, err := redis.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer sc.Close()
|
|
|
|
|
|
|
|
actual := []string{}
|
|
|
|
// Create the test http server that will capture all messages
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if err := func() error {
|
|
|
|
// Read the request body
|
|
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the new message doesn't match whats expected an error
|
|
|
|
// should be returned
|
|
|
|
actual = append(actual, cleanMessage(body))
|
|
|
|
pos := len(actual) - 1
|
|
|
|
if len(expected) < pos+1 {
|
|
|
|
return fmt.Errorf("More messages than expected were received : '%s'", actual[pos])
|
|
|
|
}
|
|
|
|
if actual[pos] != expected[pos] {
|
|
|
|
return fmt.Errorf("Expected '%s' but got '%s'", expected[pos],
|
|
|
|
actual[pos])
|
|
|
|
}
|
|
|
|
if len(actual) == len(expected) {
|
|
|
|
finalErr <- nil
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}(); err != nil {
|
|
|
|
finalErr <- err
|
|
|
|
}
|
|
|
|
fmt.Fprintln(w, "OK!")
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
_, err = sc.Do("SETHOOK", "carshook", ts.URL, "NEARBY", "cars", "FENCE", "ROAM", "cars", "*", 1000)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the base connection for setting up points and geofences
|
|
|
|
bc, err := redis.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer bc.Close()
|
|
|
|
|
|
|
|
// Fire all car movement commands on the base client
|
|
|
|
for i := range car1 {
|
|
|
|
if _, err := bc.Do("SET", "cars", "car1", "POINT", car1[i][1],
|
|
|
|
car1[i][0]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err := bc.Do("SET", "cars", "car2", "POINT", car2[i][1],
|
|
|
|
car2[i][0]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return <-finalErr
|
|
|
|
}
|
|
|
|
|
2020-03-22 21:54:56 +03:00
|
|
|
func goMultiFunc(mc *mockServer, fns ...func() error) error {
|
|
|
|
errs := make([]error, len(fns))
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(len(fns))
|
|
|
|
for i := 0; i < len(fns); i++ {
|
|
|
|
go func(i int) {
|
|
|
|
defer wg.Done()
|
|
|
|
errs[i] = fns[i]()
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
var ferrs []error
|
|
|
|
for i := 0; i < len(errs); i++ {
|
|
|
|
if errs[i] != nil {
|
|
|
|
ferrs = append(ferrs, errs[i])
|
2019-01-10 21:28:29 +03:00
|
|
|
}
|
2020-03-22 21:54:56 +03:00
|
|
|
}
|
|
|
|
if len(ferrs) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if len(ferrs) == 1 {
|
|
|
|
return ferrs[0]
|
|
|
|
}
|
|
|
|
return fmt.Errorf("%v", ferrs)
|
|
|
|
}
|
2019-01-10 21:28:29 +03:00
|
|
|
|
2020-03-22 21:54:56 +03:00
|
|
|
func fence_roaming_live_test(mc *mockServer) error {
|
|
|
|
car1, car2, expected := roamingTestData()
|
|
|
|
var liveReady sync.WaitGroup
|
|
|
|
liveReady.Add(1)
|
|
|
|
return goMultiFunc(mc,
|
|
|
|
func() error {
|
|
|
|
sc, err := redis.DialTimeout("tcp", fmt.Sprintf(":%d", mc.port),
|
|
|
|
0, time.Second*5, time.Second*5)
|
|
|
|
if err != nil {
|
|
|
|
liveReady.Done()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer sc.Close()
|
|
|
|
// Set up a live geofence stream
|
|
|
|
reply, err := redis.String(
|
|
|
|
sc.Do("NEARBY", "cars", "FENCE", "ROAM", "cars", "*", 1000),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
liveReady.Done()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if reply != "OK" {
|
|
|
|
liveReady.Done()
|
|
|
|
return fmt.Errorf("expected 'OK', got '%v'", reply)
|
|
|
|
}
|
|
|
|
liveReady.Done()
|
|
|
|
for i := 0; i < len(expected); i++ {
|
|
|
|
reply, err := redis.String(sc.Receive())
|
2019-01-10 21:28:29 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-22 21:54:56 +03:00
|
|
|
reply = cleanMessage([]byte(reply))
|
|
|
|
if reply != expected[i] {
|
|
|
|
return fmt.Errorf("Expected '%s' but got '%s'",
|
|
|
|
expected[i], reply)
|
2019-01-10 21:28:29 +03:00
|
|
|
}
|
2020-03-22 21:54:56 +03:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
func() error {
|
|
|
|
liveReady.Wait()
|
|
|
|
bc, err := redis.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer bc.Close()
|
2019-01-10 21:28:29 +03:00
|
|
|
|
2020-03-22 21:54:56 +03:00
|
|
|
// Fire all car movement commands on the base client
|
|
|
|
for i := range car1 {
|
|
|
|
|
|
|
|
if _, err := bc.Do("SET", "cars", "car1", "POINT", car1[i][1],
|
|
|
|
car1[i][0]); err != nil {
|
|
|
|
return err
|
2019-01-10 21:28:29 +03:00
|
|
|
}
|
2020-03-22 21:54:56 +03:00
|
|
|
if _, err := bc.Do("SET", "cars", "car2", "POINT", car2[i][1],
|
|
|
|
car2[i][0]); err != nil {
|
|
|
|
return err
|
2019-01-10 21:28:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 21:54:56 +03:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
)
|
2019-01-10 21:28:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func fence_roaming_channel_test(mc *mockServer) error {
|
|
|
|
car1, car2, expected := roamingTestData()
|
|
|
|
finalErr := make(chan error)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
// Create a connection for subscribing to geofence notifications
|
|
|
|
sc, err := redis.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
|
|
if err != nil {
|
|
|
|
finalErr <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer sc.Close()
|
|
|
|
|
|
|
|
if _, err := sc.Do("SETCHAN", "carschan", "NEARBY", "cars", "FENCE", "ROAM", "cars", "*", 1000); err != nil {
|
|
|
|
finalErr <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Subscribe the subscription client to the * pattern
|
|
|
|
psc := redis.PubSubConn{Conn: sc}
|
|
|
|
if err := psc.PSubscribe("carschan"); err != nil {
|
|
|
|
finalErr <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
actual := []string{}
|
|
|
|
for sc.Err() == nil {
|
|
|
|
if err := func() error {
|
|
|
|
var body []byte
|
|
|
|
switch v := psc.Receive().(type) {
|
|
|
|
case redis.Message:
|
|
|
|
body = v.Data
|
|
|
|
case error:
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(body) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the new message doesn't match whats expected an error
|
|
|
|
// should be returned
|
|
|
|
actual = append(actual, cleanMessage(body))
|
|
|
|
pos := len(actual) - 1
|
|
|
|
if len(expected) < pos+1 {
|
|
|
|
return fmt.Errorf("More messages than expected were received : '%s'", actual[pos])
|
|
|
|
}
|
|
|
|
if actual[pos] != expected[pos] {
|
|
|
|
return fmt.Errorf("Expected '%s' but got '%s'", expected[pos],
|
|
|
|
actual[pos])
|
|
|
|
}
|
|
|
|
if len(actual) == len(expected) {
|
|
|
|
finalErr <- nil
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}(); err != nil {
|
|
|
|
finalErr <- err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Create the base connection for setting up points and geofences
|
|
|
|
bc, err := redis.Dial("tcp", fmt.Sprintf(":%d", mc.port))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer bc.Close()
|
|
|
|
|
|
|
|
// Fire all car movement commands on the base client
|
|
|
|
for i := range car1 {
|
|
|
|
if _, err := bc.Do("SET", "cars", "car1", "POINT", car1[i][1],
|
|
|
|
car1[i][0]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err := bc.Do("SET", "cars", "car2", "POINT", car2[i][1],
|
|
|
|
car2[i][0]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return <-finalErr
|
|
|
|
}
|
|
|
|
|
|
|
|
func cleanMessage(body []byte) string {
|
|
|
|
// Remove fields that are non-deterministic or use case specific
|
|
|
|
msg, _ := sjson.Delete(string(body), "group")
|
|
|
|
msg, _ = sjson.Delete(msg, "time")
|
|
|
|
msg, _ = sjson.Delete(msg, "hook")
|
|
|
|
msg = string(pretty.Ugly([]byte(msg)))
|
|
|
|
return msg
|
|
|
|
}
|
|
|
|
|
|
|
|
func roamingTestData() (car1 [][]float64, car2 [][]float64, output []string) {
|
|
|
|
car1 = [][]float64{
|
|
|
|
{-111.93669319152832, 33.414750027566235},
|
|
|
|
{-111.93051338195801, 33.414750027566235},
|
|
|
|
{-111.92416191101074, 33.414750027566235},
|
|
|
|
{-111.91789627075195, 33.414750027566235},
|
|
|
|
{-111.9111156463623, 33.414750027566235},
|
|
|
|
{-111.90510749816895, 33.414750027566235},
|
|
|
|
{-111.89746856689453, 33.414750027566235},
|
|
|
|
}
|
|
|
|
car2 = [][]float64{
|
|
|
|
{-111.89746856689453, 33.414750027566235},
|
|
|
|
{-111.90519332885742, 33.414750027566235},
|
|
|
|
{-111.91154479980467, 33.414750027566235},
|
|
|
|
{-111.91781044006346, 33.414750027566235},
|
|
|
|
{-111.92416191101074, 33.414750027566235},
|
|
|
|
{-111.93059921264648, 33.414750027566235},
|
|
|
|
{-111.93660736083984, 33.414750027566235},
|
|
|
|
}
|
|
|
|
output = []string{
|
|
|
|
`{"command":"set","detect":"roam","key":"cars","id":"car1","object":{"type":"Point","coordinates":[-111.91789627075195,33.414750027566235]},"nearby":{"key":"cars","id":"car2","object":{"type":"Point","coordinates":[-111.91154479980467,33.414750027566235]},"meters":589.512}}`,
|
|
|
|
`{"command":"set","detect":"roam","key":"cars","id":"car2","object":{"type":"Point","coordinates":[-111.91781044006346,33.414750027566235]},"nearby":{"key":"cars","id":"car1","object":{"type":"Point","coordinates":[-111.91789627075195,33.414750027566235]},"meters":7.966}}`,
|
|
|
|
`{"command":"set","detect":"roam","key":"cars","id":"car1","object":{"type":"Point","coordinates":[-111.9111156463623,33.414750027566235]},"nearby":{"key":"cars","id":"car2","object":{"type":"Point","coordinates":[-111.91781044006346,33.414750027566235]},"meters":621.377}}`,
|
|
|
|
`{"command":"set","detect":"roam","key":"cars","id":"car2","object":{"type":"Point","coordinates":[-111.92416191101074,33.414750027566235]},"faraway":{"key":"cars","id":"car1","object":{"type":"Point","coordinates":[-111.9111156463623,33.414750027566235]},"meters":1210.89}}`,
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|