Notifications repository + service (#4565)
* Notifications repository * feat: notifications repo + service * fix: remove use of notifications/notifications.go * Update persistence/notificationsrepository/notificationsrepository.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: remove unused method --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
package notificationsrepository
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
var (
|
||||
integrationTestDatastore *data.Datastore
|
||||
integrationRepo NotificationsRepository
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Use the shared test datastore from the main test file
|
||||
// This ensures we're using the same database setup
|
||||
integrationTestDatastore = testDatastore
|
||||
if integrationTestDatastore != nil {
|
||||
integrationRepo = New(integrationTestDatastore)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationSetup(t *testing.T) {
|
||||
// This test ensures integration setup works properly
|
||||
// The actual setup is done in the init function below
|
||||
if integrationTestDatastore == nil {
|
||||
integrationTestDatastore = data.GetDatastore()
|
||||
Setup(integrationTestDatastore)
|
||||
integrationRepo = New(integrationTestDatastore)
|
||||
}
|
||||
|
||||
if integrationRepo == nil {
|
||||
t.Error("Integration repository should be initialized")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBrowserPushSetupIntegration(t *testing.T) {
|
||||
// Test that browser push keys are generated during setup
|
||||
configRepo := configrepository.Get()
|
||||
pubKey, err := configRepo.GetBrowserPushPublicKey()
|
||||
if err != nil {
|
||||
t.Errorf("Should be able to get browser push public key: %v", err)
|
||||
}
|
||||
|
||||
privKey, err := configRepo.GetBrowserPushPrivateKey()
|
||||
if err != nil {
|
||||
t.Errorf("Should be able to get browser push private key: %v", err)
|
||||
}
|
||||
|
||||
// Keys should be generated during setup
|
||||
if pubKey == "" || privKey == "" {
|
||||
t.Error("Browser push keys should be generated during setup")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBrowserPushConfigurationIntegration(t *testing.T) {
|
||||
configRepo := configrepository.Get()
|
||||
|
||||
// Test that browser push is enabled by default
|
||||
browserConfig := configRepo.GetBrowserPushConfig()
|
||||
if !browserConfig.Enabled {
|
||||
t.Error("Browser push should be enabled by default")
|
||||
}
|
||||
|
||||
// Test that initial notification configuration flag is set
|
||||
hasConfigured := configRepo.GetHasPerformedInitialNotificationsConfig()
|
||||
if !hasConfigured {
|
||||
t.Error("Should have performed initial notifications configuration")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiscordConfigurationIntegration(t *testing.T) {
|
||||
configRepo := configrepository.Get()
|
||||
|
||||
// Test Discord configuration setup
|
||||
discordConfig := models.DiscordConfiguration{
|
||||
Enabled: true,
|
||||
Webhook: "https://discord.com/api/webhooks/test",
|
||||
GoLiveMessage: "Test stream is live!",
|
||||
}
|
||||
|
||||
err := configRepo.SetDiscordConfig(discordConfig)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to set Discord configuration: %v", err)
|
||||
}
|
||||
|
||||
// Test with disabled Discord
|
||||
disabledConfig := models.DiscordConfiguration{
|
||||
Enabled: false,
|
||||
Webhook: "",
|
||||
}
|
||||
err = configRepo.SetDiscordConfig(disabledConfig)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to disable Discord configuration: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotificationWorkflowIntegration(t *testing.T) {
|
||||
channel := BrowserPushNotification
|
||||
destination := "integration-test-endpoint"
|
||||
|
||||
// Add a notification
|
||||
err := integrationRepo.AddNotification(channel, destination)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to add notification: %v", err)
|
||||
}
|
||||
|
||||
// Verify it was added
|
||||
destinations, err := integrationRepo.GetNotificationDestinationsForChannel(channel)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get notification destinations: %v", err)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, dest := range destinations {
|
||||
if dest == destination {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Error("Notification destination should be found after adding")
|
||||
}
|
||||
|
||||
// Clean up
|
||||
err = integrationRepo.RemoveNotificationForChannel(channel, destination)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to remove notification: %v", err)
|
||||
}
|
||||
|
||||
// Verify removal
|
||||
destinationsAfter, err := integrationRepo.GetNotificationDestinationsForChannel(channel)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get notification destinations after removal: %v", err)
|
||||
}
|
||||
|
||||
for _, dest := range destinationsAfter {
|
||||
if dest == destination {
|
||||
t.Error("Notification destination should be removed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepositoryGetSingleton(t *testing.T) {
|
||||
// Test that Get() returns the same instance
|
||||
repo1 := Get()
|
||||
repo2 := Get()
|
||||
|
||||
if repo1 != repo2 {
|
||||
t.Error("Get() should return the same singleton instance")
|
||||
}
|
||||
|
||||
// Test that it implements the interface
|
||||
var _ NotificationsRepository = repo1
|
||||
}
|
||||
|
||||
func TestDatabaseTransactionIntegrity(t *testing.T) {
|
||||
channel := "TRANSACTION_TEST_CHANNEL"
|
||||
destinations := []string{"dest1", "dest2", "dest3"}
|
||||
|
||||
// Add multiple notifications
|
||||
for _, dest := range destinations {
|
||||
err := integrationRepo.AddNotification(channel, dest)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to add notification %s: %v", dest, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify all were added
|
||||
retrievedDests, err := integrationRepo.GetNotificationDestinationsForChannel(channel)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to retrieve destinations: %v", err)
|
||||
}
|
||||
|
||||
if len(retrievedDests) != len(destinations) {
|
||||
t.Errorf("Expected %d destinations, got %d", len(destinations), len(retrievedDests))
|
||||
}
|
||||
|
||||
// Remove them one by one and verify state consistency
|
||||
for i, dest := range destinations {
|
||||
err := integrationRepo.RemoveNotificationForChannel(channel, dest)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to remove notification %s: %v", dest, err)
|
||||
}
|
||||
|
||||
remaining, err := integrationRepo.GetNotificationDestinationsForChannel(channel)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to get remaining destinations: %v", err)
|
||||
}
|
||||
|
||||
expectedRemaining := len(destinations) - (i + 1)
|
||||
if len(remaining) != expectedRemaining {
|
||||
t.Errorf("Expected %d remaining destinations, got %d", expectedRemaining, len(remaining))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorHandling(t *testing.T) {
|
||||
// Test with empty channel
|
||||
err := integrationRepo.AddNotification("", "test-destination")
|
||||
if err != nil {
|
||||
// Empty channel might be allowed - this documents the behavior
|
||||
t.Logf("Empty channel behavior: %v", err)
|
||||
}
|
||||
|
||||
// Test with empty destination
|
||||
err = integrationRepo.AddNotification("TEST_CHANNEL", "")
|
||||
if err != nil {
|
||||
// Empty destination might be allowed - this documents the behavior
|
||||
t.Logf("Empty destination behavior: %v", err)
|
||||
}
|
||||
|
||||
// Test removing from empty channel
|
||||
err = integrationRepo.RemoveNotificationForChannel("", "test-destination")
|
||||
if err != nil {
|
||||
t.Logf("Remove from empty channel behavior: %v", err)
|
||||
}
|
||||
|
||||
// Test getting destinations for empty channel
|
||||
destinations, err := integrationRepo.GetNotificationDestinationsForChannel("")
|
||||
if err != nil {
|
||||
t.Errorf("Getting destinations for empty channel should not error: %v", err)
|
||||
}
|
||||
|
||||
if len(destinations) > 0 {
|
||||
t.Logf("Empty channel returned %d destinations", len(destinations))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user