2023-09-21 04:01:13 +00:00
|
|
|
//go:build include_postgres_tests
|
|
|
|
// +build include_postgres_tests
|
|
|
|
|
2023-10-03 16:02:23 +00:00
|
|
|
package utils
|
2021-10-21 13:14:14 +00:00
|
|
|
|
|
|
|
import (
|
2023-03-09 15:48:25 +00:00
|
|
|
"context"
|
2021-10-21 13:14:14 +00:00
|
|
|
"database/sql"
|
2023-09-19 06:28:11 +00:00
|
|
|
"fmt"
|
2021-10-21 13:14:14 +00:00
|
|
|
"testing"
|
2021-11-05 14:27:30 +00:00
|
|
|
"time"
|
2021-10-21 13:14:14 +00:00
|
|
|
|
2023-08-16 01:40:00 +00:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2021-10-21 13:14:14 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/tests"
|
2023-10-03 16:02:23 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/persistence"
|
|
|
|
"github.com/waku-org/go-waku/waku/persistence/postgres"
|
|
|
|
"github.com/waku-org/go-waku/waku/persistence/sqlite"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol"
|
2024-05-03 16:07:03 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/legacy_store/pb"
|
2022-12-09 03:08:04 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/timesource"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/utils"
|
2024-01-03 16:49:54 +00:00
|
|
|
"go.uber.org/zap"
|
2023-11-20 12:51:29 +00:00
|
|
|
"google.golang.org/protobuf/proto"
|
2021-10-21 13:14:14 +00:00
|
|
|
)
|
|
|
|
|
2023-10-03 16:02:23 +00:00
|
|
|
func TestStore(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
2024-01-03 16:49:54 +00:00
|
|
|
fn func(t *testing.T, db *sql.DB, migrationFn func(*sql.DB, *zap.Logger) error)
|
2023-10-03 16:02:23 +00:00
|
|
|
}{
|
|
|
|
{"testDbStore", testDbStore},
|
|
|
|
{"testStoreRetention", testStoreRetention},
|
|
|
|
{"testQuery", testQuery},
|
|
|
|
}
|
|
|
|
for _, driverName := range []string{"postgres", "sqlite"} {
|
|
|
|
// all tests are run for each db
|
|
|
|
for _, tc := range tests {
|
|
|
|
db, migrationFn := getDB(driverName)
|
|
|
|
t.Run(driverName+"_"+tc.name, func(t *testing.T) {
|
|
|
|
tc.fn(t, db, migrationFn)
|
|
|
|
})
|
|
|
|
}
|
2023-01-04 17:58:14 +00:00
|
|
|
}
|
2021-10-21 13:14:14 +00:00
|
|
|
}
|
|
|
|
|
2024-01-03 16:49:54 +00:00
|
|
|
func getDB(driver string) (*sql.DB, func(*sql.DB, *zap.Logger) error) {
|
2023-10-03 16:02:23 +00:00
|
|
|
switch driver {
|
|
|
|
case "postgres":
|
|
|
|
return postgres.NewMockPgDB(), postgres.Migrations
|
|
|
|
case "sqlite":
|
|
|
|
return sqlite.NewMockSqliteDB(), sqlite.Migrations
|
|
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
}
|
2024-01-03 16:49:54 +00:00
|
|
|
func testDbStore(t *testing.T, db *sql.DB, migrationFn func(*sql.DB, *zap.Logger) error) {
|
2023-10-03 16:02:23 +00:00
|
|
|
store, err := persistence.NewDBStore(prometheus.DefaultRegisterer, utils.Logger(), persistence.WithDB(db), persistence.WithMigrations(migrationFn))
|
2021-10-21 13:14:14 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-03-09 15:48:25 +00:00
|
|
|
err = store.Start(context.Background(), timesource.NewDefaultClock())
|
2022-12-09 03:08:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-10-21 13:14:14 +00:00
|
|
|
res, err := store.GetAll()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, res)
|
|
|
|
|
2023-11-20 12:51:29 +00:00
|
|
|
err = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test", utils.GetUnixEpoch()), *utils.GetUnixEpoch(), "test"))
|
2021-10-21 13:14:14 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
res, err = store.GetAll()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, res)
|
|
|
|
}
|
2021-11-05 14:27:30 +00:00
|
|
|
|
2024-01-03 16:49:54 +00:00
|
|
|
func testStoreRetention(t *testing.T, db *sql.DB, migrationFn func(*sql.DB, *zap.Logger) error) {
|
2023-10-03 16:02:23 +00:00
|
|
|
store, err := persistence.NewDBStore(prometheus.DefaultRegisterer, utils.Logger(), persistence.WithDB(db), persistence.WithMigrations(migrationFn), persistence.WithRetentionPolicy(5, 20*time.Second))
|
2021-11-05 14:27:30 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-03-09 15:48:25 +00:00
|
|
|
err = store.Start(context.Background(), timesource.NewDefaultClock())
|
2022-12-09 03:08:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-11-05 14:27:30 +00:00
|
|
|
insertTime := time.Now()
|
2023-11-20 12:51:29 +00:00
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test1", proto.Int64(insertTime.Add(-70*time.Second).UnixNano())), insertTime.Add(-70*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test2", proto.Int64(insertTime.Add(-60*time.Second).UnixNano())), insertTime.Add(-60*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test3", proto.Int64(insertTime.Add(-50*time.Second).UnixNano())), insertTime.Add(-50*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test4", proto.Int64(insertTime.Add(-40*time.Second).UnixNano())), insertTime.Add(-40*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test5", proto.Int64(insertTime.Add(-30*time.Second).UnixNano())), insertTime.Add(-30*time.Second).UnixNano(), "test"))
|
2021-11-05 14:27:30 +00:00
|
|
|
|
|
|
|
dbResults, err := store.GetAll()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, dbResults, 5)
|
|
|
|
|
2023-11-20 12:51:29 +00:00
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test6", proto.Int64(insertTime.Add(-20*time.Second).UnixNano())), insertTime.Add(-20*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test7", proto.Int64(insertTime.Add(-10*time.Second).UnixNano())), insertTime.Add(-10*time.Second).UnixNano(), "test"))
|
2021-11-05 14:27:30 +00:00
|
|
|
|
|
|
|
// This step simulates starting go-waku again from scratch
|
|
|
|
|
2023-10-03 16:02:23 +00:00
|
|
|
store, err = persistence.NewDBStore(prometheus.DefaultRegisterer, utils.Logger(), persistence.WithDB(db), persistence.WithRetentionPolicy(5, 40*time.Second))
|
2021-11-05 14:27:30 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-03-09 15:48:25 +00:00
|
|
|
err = store.Start(context.Background(), timesource.NewDefaultClock())
|
2022-12-09 03:08:04 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-11-05 14:27:30 +00:00
|
|
|
dbResults, err = store.GetAll()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, dbResults, 3)
|
2022-05-30 18:48:22 +00:00
|
|
|
require.Equal(t, "test5", dbResults[0].Message.ContentTopic)
|
|
|
|
require.Equal(t, "test6", dbResults[1].Message.ContentTopic)
|
|
|
|
require.Equal(t, "test7", dbResults[2].Message.ContentTopic)
|
2023-09-19 06:28:11 +00:00
|
|
|
// checking the number of all the message in the db
|
|
|
|
msgCount, err := store.Count()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, msgCount, 3)
|
|
|
|
}
|
|
|
|
|
2024-01-03 16:49:54 +00:00
|
|
|
func testQuery(t *testing.T, db *sql.DB, migrationFn func(*sql.DB, *zap.Logger) error) {
|
2023-10-03 16:02:23 +00:00
|
|
|
store, err := persistence.NewDBStore(prometheus.DefaultRegisterer, utils.Logger(), persistence.WithDB(db), persistence.WithMigrations(migrationFn), persistence.WithRetentionPolicy(5, 20*time.Second))
|
2023-09-19 06:28:11 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
insertTime := time.Now()
|
|
|
|
//////////////////////////////////
|
2023-11-20 12:51:29 +00:00
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test1", proto.Int64(insertTime.Add(-40*time.Second).UnixNano())), insertTime.Add(-10*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test2", proto.Int64(insertTime.Add(-30*time.Second).UnixNano())), insertTime.Add(-10*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test3", proto.Int64(insertTime.Add(-20*time.Second).UnixNano())), insertTime.Add(-10*time.Second).UnixNano(), "test"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test3", proto.Int64(insertTime.Add(-20*time.Second).UnixNano())), insertTime.Add(-10*time.Second).UnixNano(), "test2"))
|
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test4", proto.Int64(insertTime.Add(-10*time.Second).UnixNano())), insertTime.Add(-10*time.Second).UnixNano(), "test"))
|
2023-09-19 06:28:11 +00:00
|
|
|
|
|
|
|
// Range [startTime-endTime]
|
|
|
|
// Check: matching ContentTopics and pubsubTopic, and ts of msg in range
|
|
|
|
// this filters test1,test2 contentTopics. test3 matches list of contentTopic but its not within the time range
|
|
|
|
cursor, msgs, err := store.Query(&pb.HistoryQuery{
|
|
|
|
PubsubTopic: "test",
|
|
|
|
ContentFilters: []*pb.ContentFilter{
|
|
|
|
{ContentTopic: "test1"},
|
|
|
|
{ContentTopic: "test2"},
|
|
|
|
{ContentTopic: "test3"},
|
|
|
|
},
|
|
|
|
PagingInfo: &pb.PagingInfo{PageSize: 10},
|
2023-11-20 12:51:29 +00:00
|
|
|
StartTime: proto.Int64(insertTime.Add(-40 * time.Second).UnixNano()),
|
|
|
|
EndTime: proto.Int64(insertTime.Add(-20 * time.Second).UnixNano()),
|
2023-09-19 06:28:11 +00:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
2023-10-12 12:42:53 +00:00
|
|
|
require.Len(t, msgs, 3)
|
2023-09-19 06:28:11 +00:00
|
|
|
|
2023-11-20 12:51:29 +00:00
|
|
|
_ = store.Put(protocol.NewEnvelope(tests.CreateWakuMessage("test5", proto.Int64(insertTime.UnixNano())), insertTime.Add(-10*time.Second).UnixNano(), "test"))
|
2023-09-19 06:28:11 +00:00
|
|
|
|
|
|
|
// Range [cursor-endTime]
|
|
|
|
// Check: matching ContentTopic,pubsubTopic, pageSize
|
|
|
|
// cursor has last message id of test2 which is now-30second
|
|
|
|
// endTime is now+1sec
|
|
|
|
// matched messages are both test4,test5, but the len of returned result depends on pageSize
|
|
|
|
var cursor2 *pb.Index
|
|
|
|
for _, pageSize := range []int{1, 2} {
|
|
|
|
cursorLocal, msgs, err := store.Query(&pb.HistoryQuery{
|
|
|
|
PubsubTopic: "test",
|
|
|
|
ContentFilters: []*pb.ContentFilter{
|
|
|
|
{ContentTopic: "test4"},
|
|
|
|
{ContentTopic: "test5"},
|
|
|
|
},
|
|
|
|
PagingInfo: &pb.PagingInfo{Cursor: cursor, PageSize: uint64(pageSize), Direction: pb.PagingInfo_FORWARD},
|
2023-11-20 12:51:29 +00:00
|
|
|
EndTime: proto.Int64(insertTime.Add(1 * time.Second).UnixNano()),
|
2023-09-19 06:28:11 +00:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, msgs, pageSize) // due to pageSize
|
|
|
|
require.Equal(t, msgs[0].Message.ContentTopic, "test4")
|
|
|
|
if len(msgs) > 1 {
|
|
|
|
require.Equal(t, msgs[1].Message.ContentTopic, "test5")
|
|
|
|
}
|
|
|
|
cursor2 = cursorLocal
|
|
|
|
}
|
|
|
|
|
|
|
|
// range [startTime-cursor(test5_ContentTopic_Msg)],
|
|
|
|
// Check: backend range with cursor excludes test1 ContentTopic, matching ContentTopic
|
|
|
|
// check backward pagination
|
|
|
|
_, msgs, err = store.Query(&pb.HistoryQuery{
|
|
|
|
PubsubTopic: "test",
|
|
|
|
ContentFilters: []*pb.ContentFilter{
|
|
|
|
{ContentTopic: "test1"}, // contentTopic test1 is out of the range
|
|
|
|
{ContentTopic: "test2"},
|
|
|
|
{ContentTopic: "test3"},
|
|
|
|
{ContentTopic: "test4"},
|
|
|
|
},
|
|
|
|
PagingInfo: &pb.PagingInfo{Cursor: cursor2, PageSize: 4, Direction: pb.PagingInfo_BACKWARD},
|
2023-11-20 12:51:29 +00:00
|
|
|
StartTime: proto.Int64(insertTime.Add(-39 * time.Second).UnixNano()),
|
2023-09-19 06:28:11 +00:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, msgs, 3) // due to pageSize
|
|
|
|
// Check:this also makes returned messages are sorted ascending
|
|
|
|
for ind, msg := range msgs {
|
|
|
|
require.Equal(t, msg.Message.ContentTopic, fmt.Sprintf("test%d", ind+2)) // test2,test3,test4
|
|
|
|
}
|
|
|
|
|
|
|
|
// checking most recent timestamp in db
|
|
|
|
timestamp, err := store.MostRecentTimestamp()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, timestamp, insertTime.UnixNano())
|
2021-11-05 14:27:30 +00:00
|
|
|
}
|