Multitenant streams api (#72)

This commit is contained in:
Dominic Wong
2021-03-18 17:21:41 +00:00
committed by GitHub
parent 28ad626d91
commit 8dfe49f813
87 changed files with 1890 additions and 1064 deletions

View File

@@ -93,7 +93,7 @@ func (l *Places) Last(ctx context.Context, req *pb.LastRequest, rsp *pb.ListResp
}
// query the database
q := l.DB.Raw("SELECT DISTINCT ON (place_id) place_id, timestamp, latitude, longitude FROM places WHERE place_id IN (?) ORDER BY place_id, timestamp DESC", req.Ids)
q := l.DB.Raw("SELECT DISTINCT ON (place_id) place_id, timestamp, latitude, longitude FROM locations WHERE place_id IN (?) ORDER BY place_id, timestamp DESC", req.Ids)
var locs []*model.Location
if err := q.Find(&locs).Error; err != nil {
logger.Errorf("Error reading from the database: %v", err)

View File

@@ -7,6 +7,7 @@ import (
"testing"
"time"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/google/uuid"
geo "github.com/hailocab/go-geoindex"
"github.com/stretchr/testify/assert"
@@ -22,29 +23,29 @@ import (
func testHandler(t *testing.T) pb.PlacesHandler {
// connect to the database
db, err := gorm.Open(postgres.Open("postgresql://postgres@localhost:5432/places?sslmode=disable"), &gorm.Config{})
addr := os.Getenv("POSTGRES_URL")
if len(addr) == 0 {
addr = "postgresql://postgres@localhost:5432/postgres?sslmode=disable"
}
db, err := gorm.Open(postgres.Open(addr), &gorm.Config{})
if err != nil {
t.Fatalf("Error connecting to database: %v", err)
}
// clean any data from a previous run
if err := db.Exec("DROP TABLE IF EXISTS locations CASCADE").Error; err != nil {
t.Fatalf("Error cleaning database: %v", err)
}
// migrate the database
if err := db.AutoMigrate(&model.Location{}); err != nil {
t.Fatalf("Error migrating database: %v", err)
}
// clean any data from a previous run
if err := db.Exec("TRUNCATE TABLE places CASCADE").Error; err != nil {
t.Fatalf("Error cleaning database: %v", err)
}
return &handler.Places{DB: db, Geoindex: geo.NewPointsIndex(geo.Km(0.1))}
}
func TestSave(t *testing.T) {
if v := os.Getenv("IN_TRAVIS_CI"); v == "yes" {
return
}
tt := []struct {
Name string
Places []*pb.Location
@@ -116,9 +117,6 @@ func TestSave(t *testing.T) {
}
func TestLast(t *testing.T) {
if v := os.Getenv("IN_TRAVIS_CI"); v == "yes" {
return
}
h := testHandler(t)
t.Run("MissingIDs", func(t *testing.T) {
@@ -134,24 +132,25 @@ func TestLast(t *testing.T) {
assert.NoError(t, err)
assert.Empty(t, rsp.Places)
})
tn := time.Now()
// generate some example data to work with
loc1 := &pb.Location{
Latitude: &wrapperspb.DoubleValue{Value: 51.5007},
Longitude: &wrapperspb.DoubleValue{Value: 0.1246},
Timestamp: timestamppb.New(time.Now()),
Timestamp: timestamppb.New(tn),
Id: "a",
}
loc2 := &pb.Location{
Latitude: &wrapperspb.DoubleValue{Value: 51.6007},
Longitude: &wrapperspb.DoubleValue{Value: 0.1546},
Timestamp: timestamppb.New(time.Now()),
Timestamp: timestamppb.New(tn.Add(1 * time.Microsecond)),
Id: "b",
}
loc3 := &pb.Location{
Latitude: &wrapperspb.DoubleValue{Value: 52.6007},
Longitude: &wrapperspb.DoubleValue{Value: 0.2546},
Timestamp: timestamppb.New(time.Now()),
Timestamp: timestamppb.New(tn.Add(2 * time.Microsecond)),
Id: loc2.Id,
}
err := h.Save(context.TODO(), &pb.SaveRequest{
@@ -162,7 +161,7 @@ func TestLast(t *testing.T) {
t.Run("OneUser", func(t *testing.T) {
var rsp pb.ListResponse
err := h.Last(context.Background(), &pb.LastRequest{
Ids: []string{loc2.Id},
Ids: []string{loc3.Id},
}, &rsp)
assert.NoError(t, err)
@@ -172,8 +171,9 @@ func TestLast(t *testing.T) {
assert.Equal(t, loc3.Id, rsp.Places[0].Id)
assert.Equal(t, loc3.Latitude.Value, rsp.Places[0].Latitude.Value)
assert.Equal(t, loc3.Longitude.Value, rsp.Places[0].Longitude.Value)
assert.Equal(t, loc3.Timestamp.AsTime(), rsp.Places[0].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc3.Timestamp), microSecondTime(rsp.Places[0].Timestamp))
})
t.Run("ManyUser", func(t *testing.T) {
var rsp pb.ListResponse
err := h.Last(context.Background(), &pb.LastRequest{
@@ -193,19 +193,16 @@ func TestLast(t *testing.T) {
assert.Equal(t, loc1.Id, rsp.Places[1].Id)
assert.Equal(t, loc1.Latitude.Value, rsp.Places[1].Latitude.Value)
assert.Equal(t, loc1.Longitude.Value, rsp.Places[1].Longitude.Value)
assert.Equal(t, loc1.Timestamp.AsTime(), rsp.Places[1].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc1.Timestamp), microSecondTime(rsp.Places[1].Timestamp))
assert.Equal(t, loc3.Id, rsp.Places[0].Id)
assert.Equal(t, loc3.Latitude.Value, rsp.Places[0].Latitude.Value)
assert.Equal(t, loc3.Longitude.Value, rsp.Places[0].Longitude.Value)
assert.Equal(t, loc3.Timestamp.AsTime(), rsp.Places[0].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc3.Timestamp), microSecondTime(rsp.Places[0].Timestamp))
})
}
func TestNear(t *testing.T) {
if v := os.Getenv("IN_TRAVIS_CI"); v == "yes" {
return
}
lat := &wrapperspb.DoubleValue{Value: 51.510357}
lng := &wrapperspb.DoubleValue{Value: -0.116773}
rad := &wrapperspb.DoubleValue{Value: 2.0}
@@ -401,9 +398,6 @@ func TestNear(t *testing.T) {
}
func TestRead(t *testing.T) {
if v := os.Getenv("IN_TRAVIS_CI"); v == "yes" {
return
}
h := testHandler(t)
baseTime := time.Now().Add(time.Hour * -24)
@@ -482,12 +476,12 @@ func TestRead(t *testing.T) {
assert.Equal(t, loc2.Id, rsp.Places[0].Id)
assert.Equal(t, loc2.Latitude.Value, rsp.Places[0].Latitude.Value)
assert.Equal(t, loc2.Longitude.Value, rsp.Places[0].Longitude.Value)
assert.Equal(t, loc2.Timestamp.AsTime(), rsp.Places[0].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc2.Timestamp), microSecondTime(rsp.Places[0].Timestamp))
assert.Equal(t, loc3.Id, rsp.Places[1].Id)
assert.Equal(t, loc3.Latitude.Value, rsp.Places[1].Latitude.Value)
assert.Equal(t, loc3.Longitude.Value, rsp.Places[1].Longitude.Value)
assert.Equal(t, loc3.Timestamp.AsTime(), rsp.Places[1].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc3.Timestamp), microSecondTime(rsp.Places[1].Timestamp))
})
t.Run("OnePlaceIDReducedTime", func(t *testing.T) {
@@ -505,7 +499,7 @@ func TestRead(t *testing.T) {
assert.Equal(t, loc2.Id, rsp.Places[0].Id)
assert.Equal(t, loc2.Latitude.Value, rsp.Places[0].Latitude.Value)
assert.Equal(t, loc2.Longitude.Value, rsp.Places[0].Longitude.Value)
assert.Equal(t, loc2.Timestamp.AsTime(), rsp.Places[0].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc2.Timestamp), microSecondTime(rsp.Places[0].Timestamp))
})
t.Run("TwoPlaceIDs", func(t *testing.T) {
@@ -523,11 +517,17 @@ func TestRead(t *testing.T) {
assert.Equal(t, loc1.Id, rsp.Places[0].Id)
assert.Equal(t, loc1.Latitude.Value, rsp.Places[0].Latitude.Value)
assert.Equal(t, loc1.Longitude.Value, rsp.Places[0].Longitude.Value)
assert.Equal(t, loc1.Timestamp.AsTime(), rsp.Places[0].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc1.Timestamp), microSecondTime(rsp.Places[0].Timestamp))
assert.Equal(t, loc2.Id, rsp.Places[1].Id)
assert.Equal(t, loc2.Latitude.Value, rsp.Places[1].Latitude.Value)
assert.Equal(t, loc2.Longitude.Value, rsp.Places[1].Longitude.Value)
assert.Equal(t, loc2.Timestamp.AsTime(), rsp.Places[1].Timestamp.AsTime())
assert.Equal(t, microSecondTime(loc2.Timestamp), microSecondTime(rsp.Places[1].Timestamp))
})
}
// postgres has a resolution of 100microseconds so just test that it's accurate to the second
func microSecondTime(t *timestamp.Timestamp) time.Time {
tt := t.AsTime()
return time.Unix(tt.Unix(), int64(tt.Nanosecond()-tt.Nanosecond()%1000))
}