mirror of
https://github.com/fankes/beszel.git
synced 2025-10-18 09:19:27 +08:00
248 lines
8.0 KiB
Go
248 lines
8.0 KiB
Go
//go:build testing
|
|
// +build testing
|
|
|
|
package config_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/henrygd/beszel/internal/tests"
|
|
|
|
"github.com/henrygd/beszel/internal/hub/config"
|
|
|
|
"github.com/pocketbase/pocketbase/core"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Config struct for testing (copied from config package since it's not exported)
|
|
type testConfig struct {
|
|
Systems []testSystemConfig `yaml:"systems"`
|
|
}
|
|
|
|
type testSystemConfig struct {
|
|
Name string `yaml:"name"`
|
|
Host string `yaml:"host"`
|
|
Port uint16 `yaml:"port,omitempty"`
|
|
Users []string `yaml:"users"`
|
|
Token string `yaml:"token,omitempty"`
|
|
}
|
|
|
|
// Helper function to create a test system for config tests
|
|
// func createConfigTestSystem(app core.App, name, host string, port uint16, userIDs []string) (*core.Record, error) {
|
|
// systemCollection, err := app.FindCollectionByNameOrId("systems")
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
|
|
// system := core.NewRecord(systemCollection)
|
|
// system.Set("name", name)
|
|
// system.Set("host", host)
|
|
// system.Set("port", port)
|
|
// system.Set("users", userIDs)
|
|
// system.Set("status", "pending")
|
|
|
|
// return system, app.Save(system)
|
|
// }
|
|
|
|
// Helper function to create a fingerprint record
|
|
func createConfigTestFingerprint(app core.App, systemID, token, fingerprint string) (*core.Record, error) {
|
|
fingerprintCollection, err := app.FindCollectionByNameOrId("fingerprints")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fp := core.NewRecord(fingerprintCollection)
|
|
fp.Set("system", systemID)
|
|
fp.Set("token", token)
|
|
fp.Set("fingerprint", fingerprint)
|
|
|
|
return fp, app.Save(fp)
|
|
}
|
|
|
|
// TestConfigSyncWithTokens tests the config.SyncSystems function with various token scenarios
|
|
func TestConfigSyncWithTokens(t *testing.T) {
|
|
testHub, err := tests.NewTestHub()
|
|
require.NoError(t, err)
|
|
defer testHub.Cleanup()
|
|
|
|
// Create test user
|
|
user, err := tests.CreateUser(testHub.App, "admin@example.com", "testtesttest")
|
|
require.NoError(t, err)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
setupFunc func() (string, *core.Record, *core.Record) // Returns: existing token, system record, fingerprint record
|
|
configYAML string
|
|
expectToken string // Expected token after sync
|
|
description string
|
|
}{
|
|
{
|
|
name: "new system with token in config",
|
|
setupFunc: func() (string, *core.Record, *core.Record) {
|
|
return "", nil, nil // No existing system
|
|
},
|
|
configYAML: `systems:
|
|
- name: "new-server"
|
|
host: "new.example.com"
|
|
port: 45876
|
|
users:
|
|
- "admin@example.com"
|
|
token: "explicit-token-123"`,
|
|
expectToken: "explicit-token-123",
|
|
description: "New system should use token from config",
|
|
},
|
|
{
|
|
name: "existing system without token in config (preserve existing)",
|
|
setupFunc: func() (string, *core.Record, *core.Record) {
|
|
// Create existing system and fingerprint
|
|
system, err := tests.CreateRecord(testHub.App, "systems", map[string]any{
|
|
"name": "preserve-server",
|
|
"host": "preserve.example.com",
|
|
"port": 45876,
|
|
"users": []string{user.Id},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
fingerprint, err := createConfigTestFingerprint(testHub.App, system.Id, "preserve-token-999", "preserve-fingerprint")
|
|
require.NoError(t, err)
|
|
|
|
return "preserve-token-999", system, fingerprint
|
|
},
|
|
configYAML: `systems:
|
|
- name: "preserve-server"
|
|
host: "preserve.example.com"
|
|
port: 45876
|
|
users:
|
|
- "admin@example.com"`,
|
|
expectToken: "preserve-token-999",
|
|
description: "Existing system should preserve original token when config doesn't specify one",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Setup test data
|
|
_, existingSystem, existingFingerprint := tc.setupFunc()
|
|
|
|
// Write config file
|
|
configPath := filepath.Join(testHub.DataDir(), "config.yml")
|
|
err := os.WriteFile(configPath, []byte(tc.configYAML), 0644)
|
|
require.NoError(t, err)
|
|
|
|
// Create serve event and sync
|
|
event := &core.ServeEvent{App: testHub.App}
|
|
err = config.SyncSystems(event)
|
|
require.NoError(t, err)
|
|
|
|
// Parse the config to get the system name for verification
|
|
var configData testConfig
|
|
err = yaml.Unmarshal([]byte(tc.configYAML), &configData)
|
|
require.NoError(t, err)
|
|
require.Len(t, configData.Systems, 1)
|
|
systemName := configData.Systems[0].Name
|
|
|
|
// Find the system after sync
|
|
systems, err := testHub.FindRecordsByFilter("systems", "name = {:name}", "", -1, 0, map[string]any{"name": systemName})
|
|
require.NoError(t, err)
|
|
require.Len(t, systems, 1)
|
|
system := systems[0]
|
|
|
|
// Find the fingerprint record
|
|
fingerprints, err := testHub.FindRecordsByFilter("fingerprints", "system = {:system}", "", -1, 0, map[string]any{"system": system.Id})
|
|
require.NoError(t, err)
|
|
require.Len(t, fingerprints, 1)
|
|
fingerprint := fingerprints[0]
|
|
|
|
// Verify token
|
|
actualToken := fingerprint.GetString("token")
|
|
if tc.expectToken == "" {
|
|
// For generated tokens, just verify it's not empty and is a valid UUID format
|
|
assert.NotEmpty(t, actualToken, tc.description)
|
|
assert.Len(t, actualToken, 36, "Generated token should be UUID format") // UUID length
|
|
} else {
|
|
assert.Equal(t, tc.expectToken, actualToken, tc.description)
|
|
}
|
|
|
|
// For existing systems, verify fingerprint is preserved
|
|
if existingFingerprint != nil {
|
|
actualFingerprint := fingerprint.GetString("fingerprint")
|
|
expectedFingerprint := existingFingerprint.GetString("fingerprint")
|
|
assert.Equal(t, expectedFingerprint, actualFingerprint, "Fingerprint should be preserved")
|
|
}
|
|
|
|
// Cleanup for next test
|
|
if existingSystem != nil {
|
|
testHub.Delete(existingSystem)
|
|
}
|
|
if existingFingerprint != nil {
|
|
testHub.Delete(existingFingerprint)
|
|
}
|
|
// Clean up the new records
|
|
testHub.Delete(system)
|
|
testHub.Delete(fingerprint)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestConfigMigrationScenario tests the specific migration scenario mentioned in the discussion
|
|
func TestConfigMigrationScenario(t *testing.T) {
|
|
testHub, err := tests.NewTestHub(t.TempDir())
|
|
require.NoError(t, err)
|
|
defer testHub.Cleanup()
|
|
|
|
// Create test user
|
|
user, err := tests.CreateUser(testHub.App, "admin@example.com", "testtesttest")
|
|
require.NoError(t, err)
|
|
|
|
// Simulate migration scenario: system exists with token from migration
|
|
existingSystem, err := tests.CreateRecord(testHub.App, "systems", map[string]any{
|
|
"name": "migrated-server",
|
|
"host": "migrated.example.com",
|
|
"port": 45876,
|
|
"users": []string{user.Id},
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
migrationToken := "migration-generated-token-123"
|
|
existingFingerprint, err := createConfigTestFingerprint(testHub.App, existingSystem.Id, migrationToken, "existing-fingerprint-from-agent")
|
|
require.NoError(t, err)
|
|
|
|
// User exports config BEFORE this update (so no token field in YAML)
|
|
oldConfigYAML := `systems:
|
|
- name: "migrated-server"
|
|
host: "migrated.example.com"
|
|
port: 45876
|
|
users:
|
|
- "admin@example.com"`
|
|
|
|
// Write old config file and import
|
|
configPath := filepath.Join(testHub.DataDir(), "config.yml")
|
|
err = os.WriteFile(configPath, []byte(oldConfigYAML), 0644)
|
|
require.NoError(t, err)
|
|
|
|
event := &core.ServeEvent{App: testHub.App}
|
|
err = config.SyncSystems(event)
|
|
require.NoError(t, err)
|
|
|
|
// Verify the original token is preserved
|
|
updatedFingerprint, err := testHub.FindRecordById("fingerprints", existingFingerprint.Id)
|
|
require.NoError(t, err)
|
|
|
|
actualToken := updatedFingerprint.GetString("token")
|
|
assert.Equal(t, migrationToken, actualToken, "Migration token should be preserved when config doesn't specify a token")
|
|
|
|
// Verify fingerprint is also preserved
|
|
actualFingerprint := updatedFingerprint.GetString("fingerprint")
|
|
assert.Equal(t, "existing-fingerprint-from-agent", actualFingerprint, "Existing fingerprint should be preserved")
|
|
|
|
// Verify system still exists and is updated correctly
|
|
updatedSystem, err := testHub.FindRecordById("systems", existingSystem.Id)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "migrated-server", updatedSystem.GetString("name"))
|
|
assert.Equal(t, "migrated.example.com", updatedSystem.GetString("host"))
|
|
}
|