187 строки
6.2 KiB
Go
187 строки
6.2 KiB
Go
package models_test
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"rsgit.ru/rsmon/rsmon/app/models"
|
|
"rsgit.ru/rsmon/rsmon/config/database"
|
|
)
|
|
|
|
func init() {
|
|
database.Init()
|
|
}
|
|
|
|
// TestNotificationCredential_EncryptDecryptRoundTrip verifies that SetSecret
|
|
// followed by GetSecret returns the original plaintext regardless of which
|
|
// encryption mode (AES-GCM or plain: fallback) is active.
|
|
func TestNotificationCredential_EncryptDecryptRoundTrip(t *testing.T) {
|
|
c := &models.NotificationCredential{}
|
|
plaintext := "super-secret-smtp-password"
|
|
|
|
require.NoError(t, c.SetSecret(plaintext))
|
|
|
|
got, err := c.GetSecret()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, plaintext, got)
|
|
}
|
|
|
|
// TestNotificationCredential_EncryptDecryptWithKey verifies that when
|
|
// RSMON_CRED_KEY is configured the stored value is prefixed with "enc:" and
|
|
// can still be decrypted back to the original plaintext.
|
|
func TestNotificationCredential_EncryptDecryptWithKey(t *testing.T) {
|
|
t.Setenv("RSMON_CRED_KEY", "test-key-rotate-me-1234567890")
|
|
|
|
c := &models.NotificationCredential{}
|
|
plaintext := "bot-token-9876543210:ABCDEFG"
|
|
|
|
require.NoError(t, c.SetSecret(plaintext))
|
|
assert.True(t, strings.HasPrefix(c.SecretEnc, "enc:"),
|
|
"expected SecretEnc to start with 'enc:' prefix, got %q", c.SecretEnc)
|
|
assert.NotEqual(t, plaintext, c.SecretEnc, "encrypted value must not equal plaintext")
|
|
|
|
got, err := c.GetSecret()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, plaintext, got)
|
|
}
|
|
|
|
// TestNotificationCredential_CRUD exercises create / find-by-id / find-by-name
|
|
// / delete against the test database.
|
|
func TestNotificationCredential_CRUD(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
server := "smtp.example.com"
|
|
port := 587
|
|
login := "alerts@example.com"
|
|
enabled := true
|
|
c := &models.NotificationCredential{
|
|
Kind: models.CredentialKindSMTP,
|
|
Name: "primary",
|
|
Server: &server,
|
|
Port: &port,
|
|
Login: &login,
|
|
Enabled: &enabled,
|
|
}
|
|
require.NoError(t, c.SetSecret("smtp-password-xyz"))
|
|
require.NoError(t, models.DB().Create(c).Error)
|
|
require.NotZero(t, c.ID, "expected ID to be assigned after Create")
|
|
|
|
found, err := models.FindCredential(c.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "primary", found.Name)
|
|
assert.Equal(t, models.CredentialKindSMTP, found.Kind)
|
|
require.NotNil(t, found.Server)
|
|
assert.Equal(t, "smtp.example.com", *found.Server)
|
|
|
|
gotSecret, err := found.GetSecret()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "smtp-password-xyz", gotSecret)
|
|
assert.Equal(t, "s***z", found.SecretMasked)
|
|
|
|
byName, err := models.FindCredentialByName(models.CredentialKindSMTP, "primary")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, c.ID, byName.ID)
|
|
|
|
require.NoError(t, models.DeleteCredential(c.ID))
|
|
|
|
_, err = models.FindCredential(c.ID)
|
|
assert.Error(t, err, "FindCredential should fail after delete")
|
|
}
|
|
|
|
// TestNotificationCredential_UniqueKindName verifies that two credentials with
|
|
// the same (kind, name) pair violate the unique index.
|
|
func TestNotificationCredential_UniqueKindName(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
enTrue := true
|
|
first := &models.NotificationCredential{
|
|
Kind: models.CredentialKindTelegram,
|
|
Name: "main-bot",
|
|
Enabled: &enTrue,
|
|
}
|
|
require.NoError(t, first.SetSecret("token-a"))
|
|
require.NoError(t, models.DB().Create(first).Error)
|
|
|
|
second := &models.NotificationCredential{
|
|
Kind: models.CredentialKindTelegram,
|
|
Name: "main-bot",
|
|
Enabled: &enTrue,
|
|
}
|
|
require.NoError(t, second.SetSecret("token-b"))
|
|
|
|
err := models.DB().Create(second).Error
|
|
require.Error(t, err, "expected unique constraint violation for duplicate (kind, name)")
|
|
assert.True(t,
|
|
strings.Contains(strings.ToLower(err.Error()), "unique") ||
|
|
strings.Contains(strings.ToLower(err.Error()), "duplicate"),
|
|
"expected error mentioning unique/duplicate, got: %v", err)
|
|
}
|
|
|
|
// TestEnabledCredentialsByKind verifies the kind+enabled filter.
|
|
func TestEnabledCredentialsByKind(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
enTrue := true
|
|
enFalse := false
|
|
enabled := &models.NotificationCredential{Kind: models.CredentialKindSMTP, Name: "enabled-1", Enabled: &enTrue}
|
|
disabled := &models.NotificationCredential{Kind: models.CredentialKindSMTP, Name: "disabled-1", Enabled: &enFalse}
|
|
require.NoError(t, models.DB().Create(enabled).Error)
|
|
require.NoError(t, models.DB().Create(disabled).Error)
|
|
|
|
got, err := models.EnabledCredentialsByKind(models.CredentialKindSMTP)
|
|
require.NoError(t, err)
|
|
|
|
var names []string
|
|
for _, c := range got {
|
|
names = append(names, c.Name)
|
|
}
|
|
assert.Contains(t, names, "enabled-1")
|
|
assert.NotContains(t, names, "disabled-1")
|
|
}
|
|
|
|
func TestNotificationCredentialsAreScopedToSystemOrAccount(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
accountA := &models.Account{Name: "credential-a"}
|
|
accountB := &models.Account{Name: "credential-b"}
|
|
require.NoError(t, models.DB().Create(accountA).Error)
|
|
require.NoError(t, models.DB().Create(accountB).Error)
|
|
enabled := true
|
|
system := &models.NotificationCredential{Kind: models.CredentialKindSMTP, Name: "system", Enabled: &enabled}
|
|
ownedA := &models.NotificationCredential{AccountID: &accountA.ID, Kind: models.CredentialKindSMTP, Name: "owned", Enabled: &enabled}
|
|
ownedB := &models.NotificationCredential{AccountID: &accountB.ID, Kind: models.CredentialKindSMTP, Name: "owned", Enabled: &enabled}
|
|
require.NoError(t, models.DB().Create(system).Error)
|
|
require.NoError(t, models.DB().Create(ownedA).Error)
|
|
require.NoError(t, models.DB().Create(ownedB).Error)
|
|
|
|
systemCreds, err := models.EnabledCredentialsByKind(models.CredentialKindSMTP)
|
|
require.NoError(t, err)
|
|
require.Len(t, systemCreds, 1)
|
|
assert.Equal(t, system.ID, systemCreds[0].ID)
|
|
|
|
accountCreds, err := models.EnabledCredentialsByAccountAndKind(accountA.ID, models.CredentialKindSMTP)
|
|
require.NoError(t, err)
|
|
require.Len(t, accountCreds, 1)
|
|
assert.Equal(t, ownedA.ID, accountCreds[0].ID)
|
|
}
|
|
|
|
func TestNotificationCredentialSecretMasked(t *testing.T) {
|
|
models.Drop()
|
|
models.Migrate()
|
|
|
|
cred := models.NotificationCredential{Kind: models.CredentialKindSMTP, Name: "smtp"}
|
|
require.NoError(t, cred.SetSecret("password"))
|
|
require.NoError(t, models.DB().Create(&cred).Error)
|
|
|
|
loaded, err := models.FindCredential(cred.ID)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "p***d", loaded.SecretMasked)
|
|
}
|