Files
portainer/api/http/handler/gitops/sources/utils_test.go
2026-05-18 18:01:36 -03:00

171 lines
5.3 KiB
Go

package sources
import (
"testing"
portainer "github.com/portainer/portainer/api"
gittypes "github.com/portainer/portainer/api/git/types"
ce "github.com/portainer/portainer/api/gitops/workflows"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestWorkflowsBySourceID(t *testing.T) {
t.Parallel()
t.Run("groups workflows with same URL and credentials", func(t *testing.T) {
t.Parallel()
cfg := gitCfg("https://github.com/org/repo")
wfs := []ce.Workflow{{GitConfig: cfg}, {GitConfig: cfg}}
byID := workflowsBySourceID(wfs)
assert.Len(t, byID, 1)
for _, group := range byID {
assert.Len(t, group, 2)
}
})
t.Run("separates workflows with same URL but different credentials", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{
{GitConfig: &gittypes.RepoConfig{URL: "https://github.com/org/repo",
Authentication: &gittypes.GitAuthentication{Username: "alice", Password: "pass1"}}},
{GitConfig: &gittypes.RepoConfig{URL: "https://github.com/org/repo",
Authentication: &gittypes.GitAuthentication{Username: "bob", Password: "pass2"}}},
}
byID := workflowsBySourceID(wfs)
assert.Len(t, byID, 2)
})
t.Run("skips workflows with nil GitConfig", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{{}, {GitConfig: gitCfg("https://github.com/org/repo")}}
byID := workflowsBySourceID(wfs)
assert.Len(t, byID, 1)
})
}
func TestBuildSource(t *testing.T) {
t.Parallel()
t.Run("status is the worst across all workflows", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{
{Status: ce.WorkflowStatusObject{Source: ce.WorkflowPhaseStatus{Status: ce.StatusHealthy}}},
{Status: ce.WorkflowStatusObject{Source: ce.WorkflowPhaseStatus{Status: ce.StatusError, Error: "boom"}}},
}
s := buildSource("id", "https://github.com/org/repo.git", wfs)
assert.Equal(t, ce.StatusError, s.Status)
assert.Equal(t, "boom", s.Error)
})
t.Run("usedBy equals the number of workflows", func(t *testing.T) {
t.Parallel()
wfs := make([]ce.Workflow, 3)
s := buildSource("id", "https://github.com/org/repo", wfs)
assert.Equal(t, 3, s.UsedBy)
})
t.Run("environments deduplicates endpoint IDs", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{
{Target: ce.Target{EndpointID: portainer.EndpointID(1)}},
{Target: ce.Target{EndpointID: portainer.EndpointID(1)}}, // duplicate
{Target: ce.Target{EndpointID: portainer.EndpointID(2)}},
}
s := buildSource("id", "https://github.com/org/repo", wfs)
assert.Equal(t, 2, s.Environments)
})
t.Run("name is extracted from URL", func(t *testing.T) {
t.Parallel()
s := buildSource("id", "https://github.com/org/my-app.git", []ce.Workflow{{}})
assert.Equal(t, "my-app", s.Name)
})
t.Run("lastSync is the maximum across all workflows", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{
{LastSyncDate: 100},
{LastSyncDate: 300},
{LastSyncDate: 200},
}
s := buildSource("id", "https://github.com/org/repo", wfs)
assert.Equal(t, int64(300), s.LastSync)
})
}
func TestRedactWorkflowCredentials(t *testing.T) {
t.Parallel()
t.Run("clears password and preserves username", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{{GitConfig: &gittypes.RepoConfig{
Authentication: &gittypes.GitAuthentication{Username: "user", Password: "s3cr3t"},
}}}
got := redactWorkflowCredentials(wfs)
require.NotNil(t, got[0].GitConfig.Authentication)
assert.Equal(t, "user", got[0].GitConfig.Authentication.Username)
assert.Empty(t, got[0].GitConfig.Authentication.Password)
})
t.Run("does not mutate the original slice", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{{GitConfig: &gittypes.RepoConfig{
Authentication: &gittypes.GitAuthentication{Password: "s3cr3t"},
}}}
_ = redactWorkflowCredentials(wfs)
assert.Equal(t, "s3cr3t", wfs[0].GitConfig.Authentication.Password)
})
t.Run("nil GitConfig is safe", func(t *testing.T) {
t.Parallel()
assert.NotPanics(t, func() { redactWorkflowCredentials([]ce.Workflow{{}}) })
})
t.Run("nil Authentication is safe", func(t *testing.T) {
t.Parallel()
wfs := []ce.Workflow{{GitConfig: &gittypes.RepoConfig{}}}
assert.NotPanics(t, func() { redactWorkflowCredentials(wfs) })
})
}
func TestBuildAutoUpdateInfo(t *testing.T) {
t.Parallel()
assert.Nil(t, buildAutoUpdateInfo(nil))
assert.Nil(t, buildAutoUpdateInfo(&portainer.AutoUpdateSettings{}))
got := buildAutoUpdateInfo(&portainer.AutoUpdateSettings{Interval: "5m"})
require.NotNil(t, got)
assert.Equal(t, "Interval", got.Mechanism)
assert.Equal(t, "5m", got.FetchInterval)
got = buildAutoUpdateInfo(&portainer.AutoUpdateSettings{Webhook: "abc123"})
require.NotNil(t, got)
assert.Equal(t, "Webhook", got.Mechanism)
assert.Empty(t, got.FetchInterval)
}
func TestBuildConnectionInfo(t *testing.T) {
t.Parallel()
assert.Nil(t, buildConnectionInfo(nil))
cfg := &gittypes.RepoConfig{
ReferenceName: "refs/heads/main",
ConfigFilePath: "docker-compose.yml",
TLSSkipVerify: true,
Authentication: &gittypes.GitAuthentication{Username: "user"},
}
got := buildConnectionInfo(cfg)
require.NotNil(t, got)
assert.Equal(t, "refs/heads/main", got.ReferenceName)
assert.Equal(t, "docker-compose.yml", got.ConfigFilePath)
assert.True(t, got.TLSSkipVerify)
assert.True(t, got.Authentication)
got = buildConnectionInfo(&gittypes.RepoConfig{})
assert.False(t, got.Authentication)
}