mirror of
https://github.com/hanzoai/deploy.git
synced 2026-10-07 08:44:50 +00:00
go.mod still declared `module github.com/hanzoai/deploy` after the repo was renamed. A Go module path is not cosmetic — it is the resolvable location. So `go get github.com/hanzoai/cd` could not work, and anything importing this module had to spell a name that no longer exists at that address. The build log of v3.6.0 is where it surfaced: the compiler was still emitting github.com/hanzoai/deploy/cmd/cd/commands. 3541 import paths across 690 .go, 19 .proto, 4 .yaml, 3 .sh, 2 .mod, Procfile and Makefile. Plus the 62 ghcr.io/hanzoai/deploy image references, moved to ghcr.io/hanzoai/cd to match hanzo.yml's build target — a distinct string from the module path, replaced separately so neither could clobber the other. go mod tidy clean, CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./... clean. Co-authored-by: Hanzo Dev <[email protected]>
357 lines
11 KiB
Go
357 lines
11 KiB
Go
package template
|
|
|
|
import (
|
|
"errors"
|
|
"maps"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/assert"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"github.com/hanzoai/cd/applicationset/generators"
|
|
genmock "github.com/hanzoai/cd/applicationset/generators/mocks"
|
|
"github.com/hanzoai/cd/applicationset/utils"
|
|
rendmock "github.com/hanzoai/cd/applicationset/utils/mocks"
|
|
"github.com/hanzoai/cd/pkg/apis/application"
|
|
"github.com/hanzoai/cd/pkg/apis/application/v1alpha1"
|
|
)
|
|
|
|
func TestGenerateApplications(t *testing.T) {
|
|
t.Parallel()
|
|
scheme := runtime.NewScheme()
|
|
err := v1alpha1.AddToScheme(scheme)
|
|
require.NoError(t, err)
|
|
|
|
err = v1alpha1.AddToScheme(scheme)
|
|
require.NoError(t, err)
|
|
|
|
for _, c := range []struct {
|
|
name string
|
|
params []map[string]any
|
|
template v1alpha1.ApplicationSetTemplate
|
|
generateParamsError error
|
|
rendererError error
|
|
expectErr bool
|
|
expectedReason v1alpha1.ApplicationSetReasonType
|
|
}{
|
|
{
|
|
name: "Generate two applications",
|
|
params: []map[string]any{{"name": "app1"}, {"name": "app2"}},
|
|
template: v1alpha1.ApplicationSetTemplate{
|
|
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
|
Name: "name",
|
|
Namespace: "namespace",
|
|
Labels: map[string]string{"label_name": "label_value"},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{},
|
|
},
|
|
expectedReason: "",
|
|
},
|
|
{
|
|
name: "Handles error from the generator",
|
|
generateParamsError: errors.New("error"),
|
|
expectErr: true,
|
|
expectedReason: v1alpha1.ApplicationSetReasonApplicationParamsGenerationError,
|
|
},
|
|
{
|
|
name: "Handles error from the render",
|
|
params: []map[string]any{{"name": "app1"}, {"name": "app2"}},
|
|
template: v1alpha1.ApplicationSetTemplate{
|
|
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
|
Name: "name",
|
|
Namespace: "namespace",
|
|
Labels: map[string]string{"label_name": "label_value"},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{},
|
|
},
|
|
rendererError: errors.New("error"),
|
|
expectErr: true,
|
|
expectedReason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
|
|
},
|
|
} {
|
|
cc := c
|
|
app := v1alpha1.Application{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test",
|
|
Namespace: "namespace",
|
|
},
|
|
TypeMeta: metav1.TypeMeta{
|
|
Kind: application.ApplicationKind,
|
|
APIVersion: "apps.hanzo.ai/v1alpha1",
|
|
},
|
|
}
|
|
|
|
t.Run(cc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
generatorMock := &genmock.Generator{}
|
|
generator := v1alpha1.ApplicationSetGenerator{
|
|
List: &v1alpha1.ListGenerator{},
|
|
}
|
|
|
|
generatorMock.EXPECT().GenerateParams(&generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
|
|
Return(cc.params, cc.generateParamsError)
|
|
|
|
generatorMock.EXPECT().GetTemplate(&generator).
|
|
Return(&v1alpha1.ApplicationSetTemplate{})
|
|
|
|
rendererMock := &rendmock.Renderer{}
|
|
|
|
var expectedApps []v1alpha1.Application
|
|
|
|
if cc.generateParamsError == nil {
|
|
for _, p := range cc.params {
|
|
if cc.rendererError != nil {
|
|
rendererMock.EXPECT().RenderTemplateParams(GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
|
|
Return(nil, cc.rendererError)
|
|
} else {
|
|
rendererMock.EXPECT().RenderTemplateParams(GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
|
|
Return(&app, nil)
|
|
expectedApps = append(expectedApps, app)
|
|
}
|
|
}
|
|
}
|
|
|
|
generators := map[string]generators.Generator{
|
|
"List": generatorMock,
|
|
}
|
|
renderer := rendererMock
|
|
|
|
got, reason, err := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "name",
|
|
Namespace: "namespace",
|
|
},
|
|
Spec: v1alpha1.ApplicationSetSpec{
|
|
Generators: []v1alpha1.ApplicationSetGenerator{generator},
|
|
Template: cc.template,
|
|
},
|
|
},
|
|
generators,
|
|
renderer,
|
|
nil,
|
|
)
|
|
|
|
if cc.expectErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
assert.Equal(t, expectedApps, got)
|
|
assert.Equal(t, cc.expectedReason, reason)
|
|
generatorMock.AssertNumberOfCalls(t, "GenerateParams", 1)
|
|
|
|
if cc.generateParamsError == nil {
|
|
rendererMock.AssertNumberOfCalls(t, "RenderTemplateParams", len(cc.params))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMergeTemplateApplications(t *testing.T) {
|
|
t.Parallel()
|
|
for _, c := range []struct {
|
|
name string
|
|
params []map[string]any
|
|
template v1alpha1.ApplicationSetTemplate
|
|
overrideTemplate v1alpha1.ApplicationSetTemplate
|
|
expectedMerged v1alpha1.ApplicationSetTemplate
|
|
expectedApps []v1alpha1.Application
|
|
}{
|
|
{
|
|
name: "Generate app",
|
|
params: []map[string]any{{"name": "app1"}},
|
|
template: v1alpha1.ApplicationSetTemplate{
|
|
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
|
Name: "name",
|
|
Namespace: "namespace",
|
|
Labels: map[string]string{"label_name": "label_value"},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{},
|
|
},
|
|
overrideTemplate: v1alpha1.ApplicationSetTemplate{
|
|
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
|
Name: "test",
|
|
Labels: map[string]string{"foo": "bar"},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{},
|
|
},
|
|
expectedMerged: v1alpha1.ApplicationSetTemplate{
|
|
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
|
Name: "test",
|
|
Namespace: "namespace",
|
|
Labels: map[string]string{"label_name": "label_value", "foo": "bar"},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{},
|
|
},
|
|
expectedApps: []v1alpha1.Application{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "test",
|
|
Namespace: "test",
|
|
Labels: map[string]string{"foo": "bar"},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{},
|
|
},
|
|
},
|
|
},
|
|
} {
|
|
cc := c
|
|
|
|
t.Run(cc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
generatorMock := &genmock.Generator{}
|
|
generator := v1alpha1.ApplicationSetGenerator{
|
|
List: &v1alpha1.ListGenerator{},
|
|
}
|
|
|
|
generatorMock.EXPECT().GenerateParams(&generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
|
|
Return(cc.params, nil)
|
|
|
|
generatorMock.EXPECT().GetTemplate(&generator).
|
|
Return(&cc.overrideTemplate)
|
|
|
|
rendererMock := &rendmock.Renderer{}
|
|
|
|
rendererMock.EXPECT().RenderTemplateParams(GetTempApplication(cc.expectedMerged), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), cc.params[0], false, []string(nil)).
|
|
Return(&cc.expectedApps[0], nil)
|
|
|
|
generators := map[string]generators.Generator{
|
|
"List": generatorMock,
|
|
}
|
|
renderer := rendererMock
|
|
|
|
got, _, _ := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "name",
|
|
Namespace: "namespace",
|
|
},
|
|
Spec: v1alpha1.ApplicationSetSpec{
|
|
Generators: []v1alpha1.ApplicationSetGenerator{generator},
|
|
Template: cc.template,
|
|
},
|
|
},
|
|
generators,
|
|
renderer,
|
|
nil,
|
|
)
|
|
|
|
assert.Equal(t, cc.expectedApps, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
// Test app generation from a go template application set using a pull request generator
|
|
func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
|
|
t.Parallel()
|
|
for _, cases := range []struct {
|
|
name string
|
|
params []map[string]any
|
|
template v1alpha1.ApplicationSetTemplate
|
|
expectedApp []v1alpha1.Application
|
|
}{
|
|
{
|
|
name: "Generate an application from a go template application set manifest using a pull request generator",
|
|
params: []map[string]any{
|
|
{
|
|
"number": "1",
|
|
"title": "title1",
|
|
"branch": "branch1",
|
|
"branch_slug": "branchSlug1",
|
|
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
|
|
"head_short_sha": "089d92cb",
|
|
"branch_slugify_default": "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
|
|
"branch_slugify_smarttruncate_disabled": "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature",
|
|
"branch_slugify_smarttruncate_enabled": "feat/testwithsmarttruncateenabledramdomlonglistofcharacters",
|
|
"labels": []string{"label1"},
|
|
},
|
|
},
|
|
template: v1alpha1.ApplicationSetTemplate{
|
|
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
|
|
Name: "AppSet-{{.branch}}-{{.number}}",
|
|
Labels: map[string]string{
|
|
"app1": "{{index .labels 0}}",
|
|
"branch-test1": "AppSet-{{.branch_slugify_default | slugify }}",
|
|
"branch-test2": "AppSet-{{.branch_slugify_smarttruncate_disabled | slugify 49 false }}",
|
|
"branch-test3": "AppSet-{{.branch_slugify_smarttruncate_enabled | slugify 50 true }}",
|
|
},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{
|
|
Source: &v1alpha1.ApplicationSource{
|
|
RepoURL: "https://testurl/testRepo",
|
|
TargetRevision: "{{.head_short_sha}}",
|
|
},
|
|
Destination: v1alpha1.ApplicationDestination{
|
|
Server: "https://kubernetes.default.svc",
|
|
Namespace: "AppSet-{{.branch_slug}}-{{.head_sha}}",
|
|
},
|
|
},
|
|
},
|
|
expectedApp: []v1alpha1.Application{
|
|
{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "AppSet-branch1-1",
|
|
Labels: map[string]string{
|
|
"app1": "label1",
|
|
"branch-test1": "AppSet-feat-a-really-long-pull-request-name-to-test-argo",
|
|
"branch-test2": "AppSet-feat-areallylongpullrequestnametotestargoslugific",
|
|
"branch-test3": "AppSet-feat",
|
|
},
|
|
},
|
|
Spec: v1alpha1.ApplicationSpec{
|
|
Source: &v1alpha1.ApplicationSource{
|
|
RepoURL: "https://testurl/testRepo",
|
|
TargetRevision: "089d92cb",
|
|
},
|
|
Destination: v1alpha1.ApplicationDestination{
|
|
Server: "https://kubernetes.default.svc",
|
|
Namespace: "AppSet-branchSlug1-089d92cbf9ff857a39e6feccd32798ca700fb958",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
} {
|
|
t.Run(cases.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
generatorMock := &genmock.Generator{}
|
|
generator := v1alpha1.ApplicationSetGenerator{
|
|
PullRequest: &v1alpha1.PullRequestGenerator{},
|
|
}
|
|
|
|
generatorMock.EXPECT().GenerateParams(&generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
|
|
Return(cases.params, nil)
|
|
|
|
generatorMock.EXPECT().GetTemplate(&generator).
|
|
Return(&cases.template)
|
|
|
|
generators := map[string]generators.Generator{
|
|
"PullRequest": generatorMock,
|
|
}
|
|
renderer := &utils.Render{}
|
|
|
|
gotApp, _, _ := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
|
|
Spec: v1alpha1.ApplicationSetSpec{
|
|
GoTemplate: true,
|
|
Generators: []v1alpha1.ApplicationSetGenerator{{
|
|
PullRequest: &v1alpha1.PullRequestGenerator{},
|
|
}},
|
|
Template: cases.template,
|
|
},
|
|
},
|
|
generators,
|
|
renderer,
|
|
nil,
|
|
)
|
|
assert.Equal(t, cases.expectedApp[0].Name, gotApp[0].Name)
|
|
assert.Equal(t, cases.expectedApp[0].Spec.Source.TargetRevision, gotApp[0].Spec.Source.TargetRevision)
|
|
assert.Equal(t, cases.expectedApp[0].Spec.Destination.Namespace, gotApp[0].Spec.Destination.Namespace)
|
|
assert.True(t, maps.Equal(cases.expectedApp[0].Labels, gotApp[0].Labels))
|
|
})
|
|
}
|
|
}
|