mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-07 00:37:36 +00:00
394 lines
12 KiB
Go
394 lines
12 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestExecuteGetPMGStatus(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{})
|
|
result, err := exec.executeGetPMGStatus(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "State provider not available.", result.Content[0].Text)
|
|
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
|
|
result, err = exec.executeGetPMGStatus(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No Proxmox Mail Gateway instances found. PMG monitoring may not be configured.", result.Content[0].Text)
|
|
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{
|
|
ID: "pmg1",
|
|
Name: "gateway-1",
|
|
Host: "pmg.local",
|
|
Status: "online",
|
|
Version: "7.4",
|
|
Nodes: []models.PMGNodeStatus{
|
|
{Name: "node1", Status: "online", Role: "master", Uptime: 100, LoadAvg: "0.10"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
|
|
result, err = exec.executeGetPMGStatus(ctx, map[string]interface{}{
|
|
"instance": "missing",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "PMG instance 'missing' not found.", result.Content[0].Text)
|
|
|
|
result, err = exec.executeGetPMGStatus(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
|
|
var resp PMGStatusResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
require.Len(t, resp.Instances, 1)
|
|
assert.Equal(t, "gateway-1", resp.Instances[0].Name)
|
|
assert.Equal(t, 1, resp.Total)
|
|
|
|
adapter := unifiedresources.NewMonitorAdapter(nil)
|
|
adapter.PopulateFromSnapshot(state)
|
|
exec = NewPulseToolExecutor(ExecutorConfig{UnifiedResourceProvider: adapter})
|
|
|
|
result, err = exec.executeGetPMGStatus(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
require.Len(t, resp.Instances, 1)
|
|
assert.Equal(t, "gateway-1", resp.Instances[0].Name)
|
|
}
|
|
|
|
func TestExecuteGetMailStats(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{})
|
|
result, err := exec.executeGetMailStats(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "State provider not available.", result.Content[0].Text)
|
|
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
|
|
result, err = exec.executeGetMailStats(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No Proxmox Mail Gateway instances found. PMG monitoring may not be configured.", result.Content[0].Text)
|
|
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{ID: "pmg1", Name: "gateway-1"},
|
|
{
|
|
ID: "pmg2",
|
|
Name: "gateway-2",
|
|
MailStats: &models.PMGMailStats{
|
|
Timeframe: "24h",
|
|
CountIn: 5,
|
|
CountOut: 6,
|
|
SpamIn: 1,
|
|
VirusIn: 2,
|
|
BouncesIn: 1,
|
|
BytesIn: 12,
|
|
BytesOut: 34,
|
|
GreylistCount: 2,
|
|
RBLRejects: 3,
|
|
AverageProcessTimeMs: 50,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
|
|
result, err = exec.executeGetMailStats(ctx, map[string]interface{}{
|
|
"instance": "pmg1",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No mail statistics available for PMG instance 'pmg1'.", result.Content[0].Text)
|
|
|
|
result, err = exec.executeGetMailStats(ctx, map[string]interface{}{
|
|
"instance": "missing",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "PMG instance 'missing' not found.", result.Content[0].Text)
|
|
|
|
result, err = exec.executeGetMailStats(ctx, map[string]interface{}{
|
|
"instance": "gateway-2",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
var resp MailStatsResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
assert.Equal(t, "gateway-2", resp.Instance)
|
|
assert.Equal(t, 5.0, resp.Stats.TotalIn)
|
|
assert.Equal(t, 6.0, resp.Stats.TotalOut)
|
|
}
|
|
|
|
func TestExecuteGetMailQueues(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{})
|
|
result, err := exec.executeGetMailQueues(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "State provider not available.", result.Content[0].Text)
|
|
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
|
|
result, err = exec.executeGetMailQueues(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No Proxmox Mail Gateway instances found. PMG monitoring may not be configured.", result.Content[0].Text)
|
|
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{ID: "pmg1", Name: "gateway-1"},
|
|
{
|
|
ID: "pmg2",
|
|
Name: "gateway-2",
|
|
Nodes: []models.PMGNodeStatus{
|
|
{
|
|
Name: "node1",
|
|
QueueStatus: &models.PMGQueueStatus{
|
|
Active: 1, Deferred: 2, Hold: 3, Incoming: 4, Total: 10, OldestAge: 20,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
|
|
result, err = exec.executeGetMailQueues(ctx, map[string]interface{}{
|
|
"instance": "pmg1",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No queue data available for PMG instance 'pmg1'.", result.Content[0].Text)
|
|
|
|
result, err = exec.executeGetMailQueues(ctx, map[string]interface{}{
|
|
"instance": "missing",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "PMG instance 'missing' not found.", result.Content[0].Text)
|
|
|
|
result, err = exec.executeGetMailQueues(ctx, map[string]interface{}{
|
|
"instance": "gateway-2",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
var resp MailQueuesResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
require.Len(t, resp.Queues, 1)
|
|
assert.Equal(t, "node1", resp.Queues[0].Node)
|
|
}
|
|
|
|
func TestExecuteGetSpamStats(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{})
|
|
result, err := exec.executeGetSpamStats(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "State provider not available.", result.Content[0].Text)
|
|
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: models.StateSnapshot{}}})
|
|
result, err = exec.executeGetSpamStats(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No Proxmox Mail Gateway instances found. PMG monitoring may not be configured.", result.Content[0].Text)
|
|
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{
|
|
ID: "pmg1",
|
|
Name: "gateway-1",
|
|
Quarantine: &models.PMGQuarantineTotals{
|
|
Spam: 1, Virus: 2, Attachment: 3, Blacklisted: 4,
|
|
},
|
|
SpamDistribution: []models.PMGSpamBucket{
|
|
{Score: "5-6", Count: 10},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
exec = NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
|
|
result, err = exec.executeGetSpamStats(ctx, map[string]interface{}{
|
|
"instance": "missing",
|
|
})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "PMG instance 'missing' not found.", result.Content[0].Text)
|
|
|
|
result, err = exec.executeGetSpamStats(ctx, map[string]interface{}{
|
|
"instance": "gateway-1",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
var resp SpamStatsResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
assert.Equal(t, "gateway-1", resp.Instance)
|
|
assert.Equal(t, 10, resp.Quarantine.Total)
|
|
assert.Len(t, resp.Distribution, 1)
|
|
assert.Equal(t, "5-6", resp.Distribution[0].Score)
|
|
}
|
|
|
|
func TestExecuteGetSpamStatsEmpty(t *testing.T) {
|
|
ctx := context.Background()
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{ID: "pmg1", Name: "gateway-1"},
|
|
},
|
|
}
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
result, err := exec.executeGetSpamStats(ctx, map[string]interface{}{
|
|
"instance": "gateway-1",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
var resp SpamStatsResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
assert.Equal(t, "gateway-1", resp.Instance)
|
|
assert.Equal(t, 0, resp.Quarantine.Total)
|
|
assert.Len(t, resp.Distribution, 0)
|
|
}
|
|
|
|
func TestPMGResponsesUseCanonicalEmptyCollections(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
raw any
|
|
keys []string
|
|
}{
|
|
{name: "pmg_status", raw: EmptyPMGStatusResponse(), keys: []string{"instances"}},
|
|
{name: "mail_queues", raw: EmptyMailQueuesResponse(), keys: []string{"queues"}},
|
|
{name: "spam_stats", raw: EmptySpamStatsResponse(), keys: []string{"spam_distribution"}},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
payload, err := json.Marshal(tc.raw)
|
|
require.NoError(t, err)
|
|
|
|
var decoded map[string]any
|
|
require.NoError(t, json.Unmarshal(payload, &decoded))
|
|
|
|
for _, key := range tc.keys {
|
|
values, ok := decoded[key].([]any)
|
|
if !ok || len(values) != 0 {
|
|
t.Fatalf("expected %s.%s to be an empty array, got %T (%v)", tc.name, key, decoded[key], decoded[key])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExecuteGetMailStatsFallback(t *testing.T) {
|
|
ctx := context.Background()
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{ID: "pmg1", Name: "gateway-1"},
|
|
},
|
|
}
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
result, err := exec.executeGetMailStats(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No mail statistics available from any PMG instance.", result.Content[0].Text)
|
|
}
|
|
|
|
func TestExecuteGetMailQueuesFallback(t *testing.T) {
|
|
ctx := context.Background()
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{ID: "pmg1", Name: "gateway-1"},
|
|
},
|
|
}
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
result, err := exec.executeGetMailQueues(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "No mail queue data available from any PMG instance.", result.Content[0].Text)
|
|
}
|
|
|
|
func TestExecuteGetMailStatsUsesFirstInstance(t *testing.T) {
|
|
ctx := context.Background()
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{
|
|
ID: "pmg1",
|
|
Name: "gateway-1",
|
|
MailStats: &models.PMGMailStats{
|
|
Timeframe: "24h",
|
|
CountIn: 3,
|
|
CountOut: 4,
|
|
},
|
|
},
|
|
{
|
|
ID: "pmg2",
|
|
Name: "gateway-2",
|
|
MailStats: &models.PMGMailStats{
|
|
Timeframe: "24h",
|
|
CountIn: 5,
|
|
CountOut: 6,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
result, err := exec.executeGetMailStats(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
|
|
var resp MailStatsResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
assert.Equal(t, "gateway-1", resp.Instance)
|
|
assert.Equal(t, 3.0, resp.Stats.TotalIn)
|
|
}
|
|
|
|
func TestExecuteGetPMGStatusNodesEmpty(t *testing.T) {
|
|
ctx := context.Background()
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{ID: "pmg1", Name: "gateway-1"},
|
|
},
|
|
}
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
result, err := exec.executeGetPMGStatus(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
|
|
var resp PMGStatusResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
require.Len(t, resp.Instances, 1)
|
|
assert.Len(t, resp.Instances[0].Nodes, 0)
|
|
}
|
|
|
|
func TestExecuteGetMailQueuesUsesFirstInstance(t *testing.T) {
|
|
ctx := context.Background()
|
|
now := time.Now()
|
|
state := models.StateSnapshot{
|
|
PMGInstances: []models.PMGInstance{
|
|
{
|
|
ID: "pmg1",
|
|
Name: "gateway-1",
|
|
Nodes: []models.PMGNodeStatus{
|
|
{
|
|
Name: "node1",
|
|
QueueStatus: &models.PMGQueueStatus{
|
|
Active: 1, Deferred: 0, Hold: 0, Incoming: 0, Total: 1, OldestAge: 5, UpdatedAt: now,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
exec := NewPulseToolExecutor(ExecutorConfig{StateProvider: &mockStateProvider{state: state}})
|
|
result, err := exec.executeGetMailQueues(ctx, map[string]interface{}{})
|
|
require.NoError(t, err)
|
|
|
|
var resp MailQueuesResponse
|
|
require.NoError(t, json.Unmarshal([]byte(result.Content[0].Text), &resp))
|
|
assert.Equal(t, "gateway-1", resp.Instance)
|
|
require.Len(t, resp.Queues, 1)
|
|
}
|