Add various deleted flags to entities | Add active to subscriptions | Add DeleteUser && DeleteChannel endpoints [skip-tests]
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
)
|
||||
|
||||
func TestCreateChannel(t *testing.T) {
|
||||
@@ -1233,3 +1234,94 @@ func TestChannelMessageCounter(t *testing.T) {
|
||||
assertCounter(6, 1, 3)
|
||||
|
||||
}
|
||||
|
||||
func TestDeleteChannel(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
|
||||
// Initialize default data set
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
// User 16 owns channels, User 1 will subscribe
|
||||
user16 := data.User[16]
|
||||
user1 := data.User[1]
|
||||
|
||||
// Find channel "Chan2" belonging to user 16
|
||||
var chan2 tt.ChanData
|
||||
for _, ch := range user16.Channels {
|
||||
if ch.InternalName == "Chan2" {
|
||||
chan2 = ch
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertNotEqual(t, "Channel Chan2 ID", "", chan2.ChannelID) // Ensure channel was found
|
||||
|
||||
// --- Subscribe User 1 to User 16's Chan2 ---
|
||||
chanInfo := tt.RequestAuthGet[gin.H](t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s", user16.UID, chan2.ChannelID))
|
||||
subKey := chanInfo["subscribe_key"].(string)
|
||||
|
||||
subReq := tt.RequestAuthPost[gin.H](t, user1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?chan_subscribe_key=%s", user1.UID, subKey), gin.H{
|
||||
"channel_id": chan2.ChannelID, // Provide channel ID for subscription
|
||||
})
|
||||
subscriptionID := subReq["subscription_id"].(string)
|
||||
|
||||
// Confirm subscription by owner (user 16)
|
||||
tt.RequestAuthPatch[gin.H](t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user16.UID, subscriptionID), gin.H{
|
||||
"confirmed": true,
|
||||
})
|
||||
|
||||
// --- Pre-checks ---
|
||||
|
||||
// 1. Check channel exists
|
||||
tt.RequestAuthGet[gin.H](t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s", user16.UID, chan2.ChannelID))
|
||||
|
||||
// 2. Check channel messages exist (assuming mglist type from previous tests)
|
||||
type msg struct {
|
||||
MessageId string `json:"message_id"`
|
||||
}
|
||||
type mglist struct {
|
||||
Messages []msg `json:"messages"`
|
||||
}
|
||||
msgs := tt.RequestAuthGet[mglist](t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user16.UID, chan2.ChannelID))
|
||||
tt.AssertTrue(t, "pre-check messages exist", len(msgs.Messages) > 0)
|
||||
|
||||
// 3. Check subscription exists for User 1 (outgoing)
|
||||
type subobj struct {
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
}
|
||||
type sublist struct {
|
||||
Subscriptions []subobj `json:"subscriptions"`
|
||||
}
|
||||
subs1 := tt.RequestAuthGet[sublist](t, user1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=outgoing", user1.UID))
|
||||
foundSub1 := langext.ArrAny(subs1.Subscriptions, func(v subobj) bool { return v.SubscriptionId == subscriptionID })
|
||||
tt.AssertTrue(t, "pre-check user1 subs outgoing", foundSub1)
|
||||
|
||||
// 4. Check subscription exists for User 16 (incoming)
|
||||
subs16 := tt.RequestAuthGet[sublist](t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=incoming", user16.UID))
|
||||
foundSub16 := langext.ArrAny(subs16.Subscriptions, func(v subobj) bool { return v.SubscriptionId == subscriptionID })
|
||||
tt.AssertTrue(t, "pre-check user16 subs incoming", foundSub16)
|
||||
|
||||
// --- Delete Channel ---
|
||||
tt.RequestAuthDelete[tt.Void](t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s", user16.UID, chan2.ChannelID), nil)
|
||||
|
||||
// --- Post-checks ---
|
||||
|
||||
// 1. Check channel fetch fails
|
||||
tt.RequestAuthGetShouldFail(t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s", user16.UID, chan2.ChannelID), 404, apierr.CHANNEL_NOT_FOUND)
|
||||
|
||||
// 2. Check channel messages fetch fails
|
||||
tt.RequestAuthGetShouldFail(t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user16.UID, chan2.ChannelID), 404, apierr.CHANNEL_NOT_FOUND)
|
||||
|
||||
// Check subscriber cannot fetch messages either
|
||||
tt.RequestAuthGetShouldFail(t, user1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user16.UID, chan2.ChannelID), 404, apierr.CHANNEL_NOT_FOUND) // Auth fails because subscription is gone
|
||||
|
||||
// 3. Check subscription is gone for User 1
|
||||
subs1After := tt.RequestAuthGet[sublist](t, user1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=outgoing", user1.UID))
|
||||
foundSub1After := langext.ArrAny(subs1After.Subscriptions, func(v subobj) bool { return v.SubscriptionId == subscriptionID })
|
||||
tt.AssertEqual(t, "post-check user1 subs outgoing", false, foundSub1After)
|
||||
|
||||
// 4. Check subscription is gone for User 16
|
||||
subs16After := tt.RequestAuthGet[sublist](t, user16.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=incoming", user16.UID))
|
||||
foundSub16After := langext.ArrAny(subs16After.Subscriptions, func(v subobj) bool { return v.SubscriptionId == subscriptionID })
|
||||
tt.AssertEqual(t, "post-check user16 subs incoming", false, foundSub16After)
|
||||
}
|
||||
|
@@ -304,6 +304,8 @@ func TestPrimaryDB_Migrate_from_3_to_latest(t *testing.T) {
|
||||
tt.AssertAny(dbf3)
|
||||
tt.AssertAny(conf)
|
||||
|
||||
schemavers := 3
|
||||
|
||||
{
|
||||
url := fmt.Sprintf("file:%s", dbf1)
|
||||
|
||||
@@ -312,8 +314,6 @@ func TestPrimaryDB_Migrate_from_3_to_latest(t *testing.T) {
|
||||
|
||||
qqdb := sq.NewDB(xdb, sq.DBOptions{})
|
||||
|
||||
schemavers := 3
|
||||
|
||||
dbschema := schema.PrimarySchema[schemavers]
|
||||
|
||||
_, err = qqdb.Exec(ctx, dbschema.SQL, sq.PP{})
|
||||
@@ -351,7 +351,7 @@ func TestPrimaryDB_Migrate_from_3_to_latest(t *testing.T) {
|
||||
|
||||
schema1, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema1", 3, schema1)
|
||||
tt.AssertEqual(t, "schema1", schemavers, schema1)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
@@ -400,6 +400,8 @@ func TestPrimaryDB_Migrate_from_4_to_latest(t *testing.T) {
|
||||
tt.AssertAny(dbf3)
|
||||
tt.AssertAny(conf)
|
||||
|
||||
schemavers := 4
|
||||
|
||||
{
|
||||
url := fmt.Sprintf("file:%s", dbf1)
|
||||
|
||||
@@ -408,8 +410,6 @@ func TestPrimaryDB_Migrate_from_4_to_latest(t *testing.T) {
|
||||
|
||||
qqdb := sq.NewDB(xdb, sq.DBOptions{})
|
||||
|
||||
schemavers := 4
|
||||
|
||||
dbschema := schema.PrimarySchema[schemavers]
|
||||
|
||||
_, err = qqdb.Exec(ctx, dbschema.SQL, sq.PP{})
|
||||
@@ -447,7 +447,391 @@ func TestPrimaryDB_Migrate_from_4_to_latest(t *testing.T) {
|
||||
|
||||
schema1, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema1", 4, schema1)
|
||||
tt.AssertEqual(t, "schema1", schemavers, schema1)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
//================================================
|
||||
{
|
||||
err = db1.Migrate(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
//================================================
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema2, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema2", schema.PrimarySchemaVersion, schema2)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, db1.DB())
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", schema.PrimarySchema[schema.PrimarySchemaVersion].Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = db1.Stop(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrimaryDB_Migrate_from_5_to_latest(t *testing.T) {
|
||||
dbf1, dbf2, dbf3, conf, stop := tt.StartSimpleTestspace(t)
|
||||
defer stop()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
tt.AssertAny(dbf1)
|
||||
tt.AssertAny(dbf2)
|
||||
tt.AssertAny(dbf3)
|
||||
tt.AssertAny(conf)
|
||||
|
||||
schemavers := 5
|
||||
|
||||
{
|
||||
url := fmt.Sprintf("file:%s", dbf1)
|
||||
|
||||
xdb, err := sqlx.Open("sqlite3", url)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
qqdb := sq.NewDB(xdb, sq.DBOptions{})
|
||||
|
||||
dbschema := schema.PrimarySchema[schemavers]
|
||||
|
||||
_, err = qqdb.Exec(ctx, dbschema.SQL, sq.PP{})
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_int) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_int = :val", sq.PP{
|
||||
"key": "schema",
|
||||
"val": schemavers,
|
||||
})
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_txt) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_txt = :val", sq.PP{
|
||||
"key": "schema_hash",
|
||||
"val": dbschema.Hash,
|
||||
})
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, qqdb)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", dbschema.Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = qqdb.Exit()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
db1, err := primary.NewPrimaryDatabase(conf)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema1, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema1", schemavers, schema1)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
//================================================
|
||||
{
|
||||
err = db1.Migrate(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
//================================================
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema2, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema2", schema.PrimarySchemaVersion, schema2)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, db1.DB())
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", schema.PrimarySchema[schema.PrimarySchemaVersion].Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = db1.Stop(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrimaryDB_Migrate_from_6_to_latest(t *testing.T) {
|
||||
dbf1, dbf2, dbf3, conf, stop := tt.StartSimpleTestspace(t)
|
||||
defer stop()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
tt.AssertAny(dbf1)
|
||||
tt.AssertAny(dbf2)
|
||||
tt.AssertAny(dbf3)
|
||||
tt.AssertAny(conf)
|
||||
|
||||
schemavers := 6
|
||||
|
||||
{
|
||||
url := fmt.Sprintf("file:%s", dbf1)
|
||||
|
||||
xdb, err := sqlx.Open("sqlite3", url)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
qqdb := sq.NewDB(xdb, sq.DBOptions{})
|
||||
|
||||
dbschema := schema.PrimarySchema[schemavers]
|
||||
|
||||
_, err = qqdb.Exec(ctx, dbschema.SQL, sq.PP{})
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_int) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_int = :val", sq.PP{
|
||||
"key": "schema",
|
||||
"val": schemavers,
|
||||
})
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_txt) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_txt = :val", sq.PP{
|
||||
"key": "schema_hash",
|
||||
"val": dbschema.Hash,
|
||||
})
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, qqdb)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", dbschema.Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = qqdb.Exit()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
db1, err := primary.NewPrimaryDatabase(conf)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema1, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema1", schemavers, schema1)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
//================================================
|
||||
{
|
||||
err = db1.Migrate(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
//================================================
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema2, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema2", schema.PrimarySchemaVersion, schema2)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, db1.DB())
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", schema.PrimarySchema[schema.PrimarySchemaVersion].Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = db1.Stop(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrimaryDB_Migrate_from_7_to_latest(t *testing.T) {
|
||||
dbf1, dbf2, dbf3, conf, stop := tt.StartSimpleTestspace(t)
|
||||
defer stop()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
tt.AssertAny(dbf1)
|
||||
tt.AssertAny(dbf2)
|
||||
tt.AssertAny(dbf3)
|
||||
tt.AssertAny(conf)
|
||||
|
||||
schemavers := 7
|
||||
|
||||
{
|
||||
url := fmt.Sprintf("file:%s", dbf1)
|
||||
|
||||
xdb, err := sqlx.Open("sqlite3", url)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
qqdb := sq.NewDB(xdb, sq.DBOptions{})
|
||||
|
||||
dbschema := schema.PrimarySchema[schemavers]
|
||||
|
||||
_, err = qqdb.Exec(ctx, dbschema.SQL, sq.PP{})
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_int) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_int = :val", sq.PP{
|
||||
"key": "schema",
|
||||
"val": schemavers,
|
||||
})
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_txt) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_txt = :val", sq.PP{
|
||||
"key": "schema_hash",
|
||||
"val": dbschema.Hash,
|
||||
})
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, qqdb)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", dbschema.Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = qqdb.Exit()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
db1, err := primary.NewPrimaryDatabase(conf)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema1, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema1", schemavers, schema1)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
//================================================
|
||||
{
|
||||
err = db1.Migrate(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
//================================================
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema2, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema2", schema.PrimarySchemaVersion, schema2)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, db1.DB())
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", schema.PrimarySchema[schema.PrimarySchemaVersion].Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = db1.Stop(ctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrimaryDB_Migrate_from_8_to_latest(t *testing.T) {
|
||||
dbf1, dbf2, dbf3, conf, stop := tt.StartSimpleTestspace(t)
|
||||
defer stop()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
tt.AssertAny(dbf1)
|
||||
tt.AssertAny(dbf2)
|
||||
tt.AssertAny(dbf3)
|
||||
tt.AssertAny(conf)
|
||||
|
||||
schemavers := 8
|
||||
|
||||
{
|
||||
url := fmt.Sprintf("file:%s", dbf1)
|
||||
|
||||
xdb, err := sqlx.Open("sqlite3", url)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
qqdb := sq.NewDB(xdb, sq.DBOptions{})
|
||||
|
||||
dbschema := schema.PrimarySchema[schemavers]
|
||||
|
||||
_, err = qqdb.Exec(ctx, dbschema.SQL, sq.PP{})
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_int) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_int = :val", sq.PP{
|
||||
"key": "schema",
|
||||
"val": schemavers,
|
||||
})
|
||||
|
||||
_, err = qqdb.Exec(ctx, "INSERT INTO meta (meta_key, value_txt) VALUES (:key, :val) ON CONFLICT(meta_key) DO UPDATE SET value_txt = :val", sq.PP{
|
||||
"key": "schema_hash",
|
||||
"val": dbschema.Hash,
|
||||
})
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
schemHashDB, err := sq.HashSqliteDatabase(tctx, qqdb)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schemHashDB", dbschema.Hash, schemHashDB)
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
err = qqdb.Exit()
|
||||
tt.TestFailIfErr(t, err)
|
||||
}
|
||||
|
||||
{
|
||||
db1, err := primary.NewPrimaryDatabase(conf)
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
||||
{
|
||||
tctx := simplectx.CreateSimpleContext(ctx, nil)
|
||||
|
||||
schema1, err := db1.ReadSchema(tctx)
|
||||
tt.TestFailIfErr(t, err)
|
||||
tt.AssertEqual(t, "schema1", schemavers, schema1)
|
||||
|
||||
err = tctx.CommitTransaction()
|
||||
tt.TestFailIfErr(t, err)
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"github.com/glebarez/go-sqlite"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"os"
|
||||
@@ -12,5 +14,9 @@ func TestMain(m *testing.M) {
|
||||
exerr.Init(exerr.ErrorPackageConfigInit{ZeroLogErrTraces: langext.PFalse, ZeroLogAllTraces: langext.PFalse})
|
||||
}
|
||||
|
||||
if !langext.InArray("sqlite3", sql.Drivers()) {
|
||||
sqlite.RegisterAsSQLITE3()
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
@@ -1,15 +1,16 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
"blackforestbytes.com/simplecloudnotifier/models"
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
)
|
||||
|
||||
func TestSearchMessageFTSSimple(t *testing.T) {
|
||||
@@ -901,3 +902,293 @@ func TestListMessagesStringSearch(t *testing.T) {
|
||||
tt.AssertEqual(t, "msgList.filter["+testdata.Name+"].len", testdata.Count, msgList.TotalCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeactivatedSubscriptionListMessages(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
type subobj struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelInternalName string `json:"channel_internal_name"`
|
||||
ChannelOwnerUserId string `json:"channel_owner_user_id"`
|
||||
Confirmed bool `json:"confirmed"`
|
||||
Active bool `json:"active"`
|
||||
SubscriberUserId string `json:"subscriber_user_id"`
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
TimestampCreated string `json:"timestamp_created"`
|
||||
}
|
||||
type msg struct {
|
||||
Title string `json:"title"`
|
||||
}
|
||||
type mglist struct {
|
||||
Messages []msg `json:"messages"`
|
||||
}
|
||||
|
||||
user14 := data.User[14] // Subscriber
|
||||
user15 := data.User[15] // Owner
|
||||
chanName := "chan_other_accepted"
|
||||
|
||||
subscriptionID, channelID := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName)
|
||||
|
||||
gsub0 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "gsub1.active", gsub0.Active)
|
||||
tt.AssertTrue(t, "gsub1.confirmed", gsub0.Confirmed)
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{"active": false})
|
||||
|
||||
gsub1 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertFalse(t, "gsub1.active", gsub1.Active)
|
||||
tt.AssertTrue(t, "gsub1.confirmed", gsub1.Confirmed)
|
||||
|
||||
gsub2 := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertFalse(t, "gsub2.active", gsub2.Active)
|
||||
tt.AssertTrue(t, "gsub2.confirmed", gsub2.Confirmed)
|
||||
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
// subscription.active == false && subscription.confirmed == true
|
||||
{
|
||||
msgListSub := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessageSub := false
|
||||
for _, m := range msgListSub.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageSub = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertFalse(t, "foundActivatedMessageSub", foundActivatedMessageSub)
|
||||
|
||||
msgListDirect := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user15.UID, channelID))
|
||||
|
||||
foundActivatedMessageDirect := false
|
||||
for _, m := range msgListDirect.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageDirect = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertTrue(t, "foundActivatedMessageDirect", foundActivatedMessageDirect)
|
||||
}
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{"active": true})
|
||||
|
||||
// subscription.active == true && subscription.confirmed == true
|
||||
{
|
||||
msgListSub := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessageSub := false
|
||||
for _, m := range msgListSub.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageSub = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertTrue(t, "foundActivatedMessageSub", foundActivatedMessageSub)
|
||||
|
||||
msgListDirect := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user15.UID, channelID))
|
||||
|
||||
foundActivatedMessageDirect := false
|
||||
for _, m := range msgListDirect.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageDirect = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertTrue(t, "foundActivatedMessageDirect", foundActivatedMessageDirect)
|
||||
}
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID), gin.H{"confirmed": false})
|
||||
|
||||
// subscription.active == true && subscription.confirmed == false
|
||||
{
|
||||
msgListSub := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessageSub := false
|
||||
for _, m := range msgListSub.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageSub = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertFalse(t, "foundActivatedMessageSub", foundActivatedMessageSub)
|
||||
|
||||
tt.RequestAuthGetShouldFail(t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user15.UID, channelID), 401, apierr.USER_AUTH_FAILED)
|
||||
}
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{"active": false})
|
||||
|
||||
// subscription.active == false && subscription.confirmed == false
|
||||
{
|
||||
msgListSub := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessageSub := false
|
||||
for _, m := range msgListSub.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageSub = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertFalse(t, "foundActivatedMessageSub", foundActivatedMessageSub)
|
||||
|
||||
tt.RequestAuthGetShouldFail(t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user15.UID, channelID), 401, apierr.USER_AUTH_FAILED)
|
||||
}
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID), gin.H{"confirmed": true})
|
||||
tt.RequestAuthPatch[gin.H](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{"active": true})
|
||||
|
||||
// subscription.active == true && subscription.confirmed == true
|
||||
{
|
||||
msgListSub := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessageSub := false
|
||||
for _, m := range msgListSub.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageSub = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertTrue(t, "foundActivatedMessageSub", foundActivatedMessageSub)
|
||||
|
||||
msgListDirect := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user15.UID, channelID))
|
||||
|
||||
foundActivatedMessageDirect := false
|
||||
for _, m := range msgListDirect.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageDirect = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertTrue(t, "foundActivatedMessageDirect", foundActivatedMessageDirect)
|
||||
}
|
||||
|
||||
tt.RequestAuthDelete[gin.H](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{})
|
||||
|
||||
// subscription -> deleted
|
||||
{
|
||||
msgListSub := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessageSub := false
|
||||
for _, m := range msgListSub.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageSub = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertFalse(t, "foundActivatedMessageSub", foundActivatedMessageSub)
|
||||
|
||||
tt.RequestAuthGetShouldFail(t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/channels/%s/messages", user15.UID, channelID), 401, apierr.USER_AUTH_FAILED)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveSubscriptionListMessages(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
type subobj struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelInternalName string `json:"channel_internal_name"`
|
||||
ChannelOwnerUserId string `json:"channel_owner_user_id"`
|
||||
Confirmed bool `json:"confirmed"`
|
||||
Active bool `json:"active"`
|
||||
SubscriberUserId string `json:"subscriber_user_id"`
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
TimestampCreated string `json:"timestamp_created"`
|
||||
}
|
||||
type msg struct {
|
||||
Title string `json:"title"`
|
||||
}
|
||||
type mglist struct {
|
||||
Messages []msg `json:"messages"`
|
||||
}
|
||||
|
||||
user14 := data.User[14] // Subscriber
|
||||
user15 := data.User[15] // Owner
|
||||
chanName := "chan_other_accepted"
|
||||
|
||||
subscriptionID, _ := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName)
|
||||
|
||||
gsub1 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "gsub1.active", gsub1.Active)
|
||||
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
{
|
||||
msgListSub := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessageSub := false
|
||||
for _, m := range msgListSub.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessageSub = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertTrue(t, "foundActivatedMessageSub", foundActivatedMessageSub)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnconfirmedSubscriptionListMessages(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
type subobj struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelInternalName string `json:"channel_internal_name"`
|
||||
ChannelOwnerUserId string `json:"channel_owner_user_id"`
|
||||
Confirmed bool `json:"confirmed"`
|
||||
Active bool `json:"active"`
|
||||
SubscriberUserId string `json:"subscriber_user_id"`
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
TimestampCreated string `json:"timestamp_created"`
|
||||
}
|
||||
type msg struct {
|
||||
Title string `json:"title"`
|
||||
}
|
||||
type mglist struct {
|
||||
Messages []msg `json:"messages"`
|
||||
}
|
||||
|
||||
user14 := data.User[14] // Subscriber
|
||||
user15 := data.User[15] // Owner
|
||||
chanName := "chan_other_request"
|
||||
|
||||
subscriptionID, _ := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName)
|
||||
|
||||
gsub1 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "gsub1.active", gsub1.Active)
|
||||
tt.AssertFalse(t, "gsub1.confirmed", gsub1.Confirmed)
|
||||
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
msgList := tt.RequestAuthGet[mglist](t, user14.AdminKey, baseUrl, "/api/v2/messages")
|
||||
|
||||
foundActivatedMessage := false
|
||||
for _, m := range msgList.Messages {
|
||||
if m.Title == newMessageTitle {
|
||||
foundActivatedMessage = true
|
||||
break
|
||||
}
|
||||
}
|
||||
tt.AssertFalse(t, "foundActivatedMessage", foundActivatedMessage)
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@ func TestResponseChannel(t *testing.T) {
|
||||
"channel_internal_name": "string",
|
||||
"timestamp_created": "rfc3339",
|
||||
"confirmed": "bool",
|
||||
"active": "bool",
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -179,6 +180,7 @@ func TestResponseMessage(t *testing.T) {
|
||||
"sender_user_id": "id",
|
||||
"channel_internal_name": "string",
|
||||
"channel_id": "id",
|
||||
"channel_owner_user_id": "id",
|
||||
"sender_name": "string",
|
||||
"sender_ip": "string",
|
||||
"timestamp": "rfc3339",
|
||||
@@ -207,6 +209,7 @@ func TestResponseSubscription(t *testing.T) {
|
||||
"channel_internal_name": "string",
|
||||
"timestamp_created": "rfc3339",
|
||||
"confirmed": "bool",
|
||||
"active": "bool",
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"math/rand/v2"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -1807,3 +1808,176 @@ func TestSendWithPermissionSendKey(t *testing.T) {
|
||||
func TestSendDeliveryRetry(t *testing.T) {
|
||||
t.SkipNow() //TODO
|
||||
}
|
||||
|
||||
func TestDeactivatedSubscriptionReceiveMessage(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
type subobj struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelInternalName string `json:"channel_internal_name"`
|
||||
ChannelOwnerUserId string `json:"channel_owner_user_id"`
|
||||
Confirmed bool `json:"confirmed"`
|
||||
Active bool `json:"active"`
|
||||
SubscriberUserId string `json:"subscriber_user_id"`
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
TimestampCreated string `json:"timestamp_created"`
|
||||
}
|
||||
|
||||
pusher := ws.Pusher.(*push.TestSink)
|
||||
pusher.Clear()
|
||||
|
||||
user14 := data.User[14] // Subscriber
|
||||
user15 := data.User[15] // Owner
|
||||
chanName := "chan_other_accepted"
|
||||
|
||||
subscriptionID, _ := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName)
|
||||
|
||||
gsub0 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "gsub0.active", gsub0.Active)
|
||||
tt.AssertTrue(t, "gsub0.confirmed", gsub0.Confirmed)
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{"active": false})
|
||||
|
||||
gsub1 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertFalse(t, "gsub1.active", gsub1.Active)
|
||||
tt.AssertTrue(t, "gsub1.confirmed", gsub1.Confirmed)
|
||||
|
||||
// sub is active=false && confirmed=true
|
||||
{
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
pushObj := langext.ArrFirstOrNil(pusher.Data, func(d push.SinkData) bool { return d.Client.UserID.String() == user14.UID })
|
||||
|
||||
tt.AssertNil(t, "pushObj", pushObj)
|
||||
|
||||
pusher.Clear()
|
||||
}
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{"active": true})
|
||||
|
||||
gsub2 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "gsub1.active", gsub2.Active)
|
||||
tt.AssertTrue(t, "gsub1.confirmed", gsub2.Confirmed)
|
||||
|
||||
// sub is active=true && confirmed=true
|
||||
{
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
pushObj := langext.ArrFirstOrNil(pusher.Data, func(d push.SinkData) bool { return d.Client.UserID.String() == user14.UID })
|
||||
|
||||
tt.AssertNotNil(t, "pushObj", pushObj)
|
||||
tt.AssertStrRepEqual(t, "msg.title", newMessageTitle, pushObj.Message.Title)
|
||||
tt.AssertStrRepEqual(t, "msg.content", nil, pushObj.Message.Content)
|
||||
tt.AssertStrRepEqual(t, "msg.scn_msg_id", msg1["scn_msg_id"], pushObj.Message.MessageID)
|
||||
tt.AssertStrRepEqual(t, "msg.scn_msg_id", user14.UID, pushObj.Client.UserID)
|
||||
|
||||
pusher.Clear()
|
||||
}
|
||||
|
||||
tt.RequestAuthPatch[gin.H](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID), gin.H{"confirmed": false})
|
||||
|
||||
gsub3 := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "gsub1.active", gsub3.Active)
|
||||
tt.AssertFalse(t, "gsub1.confirmed", gsub3.Confirmed)
|
||||
|
||||
// sub is active=true && confirmed=false
|
||||
{
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
pushObj := langext.ArrFirstOrNil(pusher.Data, func(d push.SinkData) bool { return d.Client.UserID.String() == user14.UID })
|
||||
|
||||
tt.AssertNil(t, "pushObj", pushObj)
|
||||
|
||||
pusher.Clear()
|
||||
}
|
||||
|
||||
tt.RequestAuthDelete[gin.H](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID), gin.H{})
|
||||
|
||||
tt.RequestAuthGetShouldFail(t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), 404, apierr.SUBSCRIPTION_NOT_FOUND)
|
||||
tt.RequestAuthGetShouldFail(t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID), 404, apierr.SUBSCRIPTION_NOT_FOUND)
|
||||
|
||||
// sub is deleted
|
||||
{
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
pushObj := langext.ArrFirstOrNil(pusher.Data, func(d push.SinkData) bool { return d.Client.UserID.String() == user14.UID })
|
||||
|
||||
tt.AssertNil(t, "pushObj", pushObj)
|
||||
|
||||
pusher.Clear()
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveSubscriptionReceiveMessage(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
type subobj struct {
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelInternalName string `json:"channel_internal_name"`
|
||||
ChannelOwnerUserId string `json:"channel_owner_user_id"`
|
||||
Confirmed bool `json:"confirmed"`
|
||||
Active bool `json:"active"`
|
||||
SubscriberUserId string `json:"subscriber_user_id"`
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
TimestampCreated string `json:"timestamp_created"`
|
||||
}
|
||||
|
||||
pusher := ws.Pusher.(*push.TestSink)
|
||||
pusher.Clear()
|
||||
|
||||
user14 := data.User[14] // Subscriber
|
||||
user15 := data.User[15] // Owner
|
||||
chanName := "chan_other_accepted"
|
||||
|
||||
subscriptionID, _ := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName)
|
||||
|
||||
gsub1 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "gsub1.active", gsub1.Active)
|
||||
tt.AssertTrue(t, "gsub1.confirmed", gsub1.Confirmed)
|
||||
|
||||
newMessageTitle := langext.RandBase62(48)
|
||||
msg1 := tt.RequestPost[gin.H](t, baseUrl, "/", gin.H{
|
||||
"key": user15.AdminKey,
|
||||
"user_id": user15.UID,
|
||||
"channel": chanName,
|
||||
"title": newMessageTitle,
|
||||
})
|
||||
|
||||
pushObj := langext.ArrFirstOrNil(pusher.Data, func(d push.SinkData) bool { return d.Client.UserID.String() == user14.UID })
|
||||
|
||||
tt.AssertNotNil(t, "pushObj", pushObj)
|
||||
tt.AssertStrRepEqual(t, "msg.title", newMessageTitle, pushObj.Message.Title)
|
||||
tt.AssertStrRepEqual(t, "msg.content", nil, pushObj.Message.Content)
|
||||
tt.AssertStrRepEqual(t, "msg.scn_msg_id", msg1["scn_msg_id"], pushObj.Message.MessageID)
|
||||
tt.AssertStrRepEqual(t, "msg.scn_msg_id", user14.UID, pushObj.Client.UserID)
|
||||
|
||||
pusher.Clear()
|
||||
}
|
||||
|
@@ -1,12 +1,13 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"blackforestbytes.com/simplecloudnotifier/api/apierr"
|
||||
tt "blackforestbytes.com/simplecloudnotifier/test/util"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListSubscriptionsOfUser(t *testing.T) {
|
||||
@@ -1240,3 +1241,106 @@ func TestCancelOutgoingSubscription(t *testing.T) {
|
||||
tt.RequestAuthGetShouldFail(t, data1.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", data1.UID, sub1.SubscriptionId), 404, apierr.SUBSCRIPTION_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubscriptionDeactivate(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
user14 := data.User[14]
|
||||
user15 := data.User[15]
|
||||
chanName := "chan_other_accepted"
|
||||
|
||||
subscriptionID, _ := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName)
|
||||
|
||||
type subobj struct {
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
|
||||
initialSub := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "initialSub.Active", initialSub.Active)
|
||||
|
||||
// subscriber deactivates
|
||||
{
|
||||
tt.RequestAuthPatch[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{
|
||||
"active": false,
|
||||
})
|
||||
|
||||
sub1 := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub1.Active", false, sub1.Active)
|
||||
|
||||
sub2 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub2.Active", false, sub2.Active)
|
||||
}
|
||||
|
||||
// subscriber activates
|
||||
{
|
||||
tt.RequestAuthPatch[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{
|
||||
"active": true,
|
||||
})
|
||||
|
||||
sub1 := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub1.Active", true, sub1.Active)
|
||||
|
||||
sub2 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub2.Active", true, sub2.Active)
|
||||
}
|
||||
|
||||
// owner deactivates
|
||||
{
|
||||
tt.RequestAuthPatch[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID), gin.H{
|
||||
"active": false,
|
||||
})
|
||||
|
||||
sub1 := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub1.Active", false, sub1.Active)
|
||||
|
||||
sub2 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub2.Active", false, sub2.Active)
|
||||
}
|
||||
|
||||
// owner activates
|
||||
{
|
||||
tt.RequestAuthPatch[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID), gin.H{
|
||||
"active": true,
|
||||
})
|
||||
|
||||
sub1 := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub1.Active", true, sub1.Active)
|
||||
|
||||
sub2 := tt.RequestAuthGet[subobj](t, user15.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user15.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "sub2.Active", true, sub2.Active)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubscriptionActivate(t *testing.T) {
|
||||
ws, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
data := tt.InitDefaultData(t, ws)
|
||||
|
||||
user14 := data.User[14]
|
||||
user15 := data.User[15]
|
||||
chanName := "chan_other_accepted"
|
||||
|
||||
subscriptionID, _ := tt.FindSubscriptionByChanName(t, baseUrl, user14, user15.UID, chanName)
|
||||
|
||||
type subobj struct {
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
|
||||
tt.RequestAuthPatch[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{
|
||||
"active": false,
|
||||
})
|
||||
|
||||
deactivatedSub := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertEqual(t, "deactivatedSub.Active", false, deactivatedSub.Active)
|
||||
|
||||
tt.RequestAuthPatch[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID), gin.H{
|
||||
"active": true,
|
||||
})
|
||||
|
||||
finalSub := tt.RequestAuthGet[subobj](t, user14.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", user14.UID, subscriptionID))
|
||||
tt.AssertTrue(t, "finalSub.Active", finalSub.Active)
|
||||
}
|
||||
|
@@ -185,8 +185,6 @@ func TestFailedUgradeUserToPro(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDeleteUser(t *testing.T) {
|
||||
t.SkipNow() // TODO DeleteUser Not implemented
|
||||
|
||||
_, baseUrl, stop := tt.StartSimpleWebserver(t)
|
||||
defer stop()
|
||||
|
||||
@@ -199,15 +197,18 @@ func TestDeleteUser(t *testing.T) {
|
||||
|
||||
uid := fmt.Sprintf("%v", r0["user_id"])
|
||||
admintok := r0["admin_key"].(string)
|
||||
readtok := r0["read_key"].(string)
|
||||
sendtok := r0["send_key"].(string)
|
||||
|
||||
tt.RequestAuthGet[gin.H](t, admintok, baseUrl, "/api/v2/users/"+uid)
|
||||
|
||||
tt.RequestAuthDeleteShouldFail(t, admintok, baseUrl, "/api/v2/users/"+uid, nil, 401, apierr.USER_AUTH_FAILED)
|
||||
tt.RequestAuthDeleteShouldFail(t, readtok, baseUrl, "/api/v2/users/"+uid, nil, 401, apierr.USER_AUTH_FAILED)
|
||||
|
||||
tt.RequestAuthDeleteShouldFail(t, sendtok, baseUrl, "/api/v2/users/"+uid, nil, 401, apierr.USER_AUTH_FAILED)
|
||||
|
||||
tt.RequestAuthDelete[tt.Void](t, admintok, baseUrl, "/api/v2/users/"+uid, nil)
|
||||
|
||||
tt.RequestAuthGetShouldFail(t, admintok, baseUrl, "/api/v2/users/"+uid, 404, apierr.USER_NOT_FOUND)
|
||||
|
||||
tt.RequestAuthGetShouldFail(t, admintok, baseUrl, "/api/v2/users/"+uid, 401, apierr.USER_AUTH_FAILED)
|
||||
}
|
||||
|
||||
func TestCreateProUser(t *testing.T) {
|
||||
|
@@ -177,6 +177,14 @@ func AssertTrue(t *testing.T, key string, v bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func AssertFalse(t *testing.T, key string, v bool) {
|
||||
if v {
|
||||
t.Errorf("AssertFalse(%s) failed", key)
|
||||
t.Error(string(debug.Stack()))
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func AssertNotDefault[T comparable](t *testing.T, key string, v T) {
|
||||
if v == *new(T) {
|
||||
t.Errorf("AssertNotDefault(%s) failed", key)
|
||||
@@ -307,7 +315,7 @@ func AssertAny(v any) {
|
||||
}
|
||||
|
||||
func AssertNil(t *testing.T, key string, v any) {
|
||||
if v != nil {
|
||||
if !langext.IsNil(v) {
|
||||
t.Errorf("AssertNil(%s) failed - actual value:\n%+v", key, v)
|
||||
t.Error(string(debug.Stack()))
|
||||
t.FailNow()
|
||||
@@ -315,7 +323,7 @@ func AssertNil(t *testing.T, key string, v any) {
|
||||
}
|
||||
|
||||
func AssertNotNil(t *testing.T, key string, v any) {
|
||||
if v == nil {
|
||||
if langext.IsNil(v) {
|
||||
t.Errorf("AssertNotNil(%s) failed", key)
|
||||
t.Error(string(debug.Stack()))
|
||||
t.FailNow()
|
||||
|
@@ -467,8 +467,10 @@ func InitDefaultData(t *testing.T, ws *logic.Application) DefData {
|
||||
users[i].Subscriptions = langext.ArrMap(r0.Subs, func(v ssub) string { return v.ID })
|
||||
}
|
||||
|
||||
// Sub/Unsub for Users 12+13
|
||||
|
||||
// Sub/Unsub for Users 14+15
|
||||
// - User 14 is not subscribed to (own) channel "chan_self_unsub"
|
||||
// - User 14 has an unconfirmed request to User15's channel "chan_other_request"
|
||||
// - User 14 has a confirmed+active subscription to User15's channel "chan_other_accepted"
|
||||
{
|
||||
doUnsubscribe(t, baseUrl, users[14], users[14], "chan_self_unsub")
|
||||
doSubscribe(t, baseUrl, users[14], users[15], "chan_other_request")
|
||||
|
34
scnserver/test/util/helper.go
Normal file
34
scnserver/test/util/helper.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func FindSubscriptionByChanName(t *testing.T, baseUrl string, subscriber Userdat, ownerUID string, chanName string) (subscriptionID string, channelID string) {
|
||||
type subobj struct {
|
||||
SubscriptionId string `json:"subscription_id"`
|
||||
ChannelId string `json:"channel_id"`
|
||||
ChannelInternalName string `json:"channel_internal_name"`
|
||||
ChannelOwnerUserId string `json:"channel_owner_user_id"`
|
||||
Confirmed bool `json:"confirmed"`
|
||||
Active bool `json:"active"`
|
||||
}
|
||||
type sublist struct {
|
||||
Subscriptions []subobj `json:"subscriptions"`
|
||||
}
|
||||
|
||||
subs := RequestAuthGet[sublist](t, subscriber.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions?direction=outgoing", subscriber.UID))
|
||||
|
||||
for _, sub := range subs.Subscriptions {
|
||||
if sub.ChannelOwnerUserId == ownerUID && sub.ChannelInternalName == chanName {
|
||||
fullSub := RequestAuthGet[subobj](t, subscriber.AdminKey, baseUrl, fmt.Sprintf("/api/v2/users/%s/subscriptions/%s", subscriber.UID, sub.SubscriptionId))
|
||||
if fullSub.ChannelOwnerUserId == ownerUID && fullSub.ChannelInternalName == chanName {
|
||||
return fullSub.SubscriptionId, fullSub.ChannelId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.Fatalf("Could not find subscription for user %s to channel %s owned by %s", subscriber.UID, chanName, ownerUID)
|
||||
return "", ""
|
||||
}
|
Reference in New Issue
Block a user