blob: ed4a2520fe5127fdb4fd9af0b8b5491ca30fc69a [file]
// Copyright 2026 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package task
import (
"context"
"fmt"
"testing"
"github.com/google/uuid"
"golang.org/x/build/internal/workflow"
)
func TestReleaseGovulncheckActionTasks_NewDefinition(t *testing.T) {
fakeRepo := NewFakeRepo(t, "govulncheck-action")
fakeRepo.Tag("v1.1.0", "master")
commit := fakeRepo.Commit(map[string]string{"README.md": "New content"})
fakeGerrit := NewFakeGerrit(t, fakeRepo)
fakeGitHub := &FakeGitHub{
Tags: map[string]bool{"v1.2.0": true},
}
tasks := &ReleaseGovulncheckActionTasks{
Gerrit: fakeGerrit,
GitHub: fakeGitHub,
ApproveAction: func(ctx *workflow.TaskContext) error {
return nil
},
}
wd := tasks.NewDefinition()
ctx := t.Context()
// Start the workflow with version v1.2.0
w, err := workflow.Start(wd, map[string]any{
"Version": "v1.2.0",
})
if err != nil {
t.Fatalf("workflow.Start failed: %v", err)
}
if _, err := w.Run(ctx, &govulncheckActionVerboseListener{t: t}); err != nil {
t.Fatalf("workflow.Run failed: %v", err)
}
// Verify tags
tags, err := fakeGerrit.ListTags(ctx, "govulncheck-action")
if err != nil {
t.Fatalf("ListTags failed: %v", err)
}
foundv120 := false
foundv1 := false
for _, tag := range tags {
if tag == "v1.2.0" {
foundv120 = true
}
if tag == "v1" {
foundv1 = true
}
}
if !foundv120 {
t.Errorf("tag v1.2.0 not found in %v", tags)
}
if !foundv1 {
t.Errorf("major tag v1 not found in %v", tags)
}
// Verify GitHub release
if len(fakeGitHub.Releases) != 1 {
t.Errorf("got %d GitHub releases, want 1", len(fakeGitHub.Releases))
} else {
rel := fakeGitHub.Releases[0]
if *rel.TagName != "v1.2.0" {
t.Errorf("GitHub release TagName = %q, want %q", *rel.TagName, "v1.2.0")
}
if rel.GenerateReleaseNotes == nil || !*rel.GenerateReleaseNotes {
t.Error("GitHub release GenerateReleaseNotes NOT set to true")
}
}
// Verify major tag points to the right commit
info, err := fakeGerrit.GetTag(ctx, "govulncheck-action", "v1")
if err != nil {
t.Fatalf("GetTag v1 failed: %v", err)
}
if info.Revision != commit {
t.Errorf("v1 tag points to %s, want %s", info.Revision, commit)
}
}
func TestReleaseGovulncheckActionTasks_Validation(t *testing.T) {
testCases := []struct {
name string
latest string
new string
wantErr bool
}{
{
name: "valid minor increment",
latest: "v1.1.0",
new: "v1.2.0",
wantErr: false,
},
{
name: "valid major increment",
latest: "v1.5.0",
new: "v2.0.0",
wantErr: false,
},
{
name: "invalid regression",
latest: "v1.2.0",
new: "v1.1.0",
wantErr: true,
},
{
name: "invalid same version",
latest: "v1.2.0",
new: "v1.2.0",
wantErr: true,
},
{
name: "invalid skip major",
latest: "v1.5.0",
new: "v3.0.0",
wantErr: true,
},
{
name: "invalid skip minor",
latest: "v1.3.0",
new: "v1.5.0",
wantErr: true,
},
{
name: "invalid skip patch",
latest: "v1.3.0",
new: "v1.3.2",
wantErr: true,
},
{
name: "valid first version",
latest: "",
new: "v1.0.0",
wantErr: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fakeRepo := NewFakeRepo(t, "govulncheck-action")
if tc.latest != "" {
fakeRepo.Tag(tc.latest, "master")
}
fakeGerrit := NewFakeGerrit(t, fakeRepo)
fakeGitHub := &FakeGitHub{
Tags: map[string]bool{tc.new: true},
}
tasks := &ReleaseGovulncheckActionTasks{
Gerrit: fakeGerrit,
GitHub: fakeGitHub,
ApproveAction: func(ctx *workflow.TaskContext) error {
return nil
},
}
wd := tasks.NewDefinition()
ctx, cancel := context.WithCancel(t.Context())
defer cancel()
w, err := workflow.Start(wd, map[string]any{
"Version": tc.new,
})
if err != nil {
t.Fatalf("workflow.Start failed: %v", err)
}
_, err = w.Run(ctx, &govulncheckActionVerboseListener{t: t, cancel: cancel})
if (err != nil) != tc.wantErr {
t.Errorf("workflow.Run error = %v, wantErr %v", err, tc.wantErr)
}
})
}
}
type govulncheckActionVerboseListener struct {
t *testing.T
cancel context.CancelFunc
}
func (l *govulncheckActionVerboseListener) WorkflowStalled(workflowID uuid.UUID) error {
l.t.Logf("workflow %q: stalled", workflowID.String())
if l.cancel != nil {
l.cancel()
}
return nil
}
func (l *govulncheckActionVerboseListener) TaskStateChanged(_ uuid.UUID, _ string, st *workflow.TaskState) error {
if st.Finished && st.Error != "" {
l.t.Logf("task %-10v: error: %v", st.Name, st.Error)
} else if st.Finished {
l.t.Logf("task %-10v: done: %v", st.Name, st.Result)
}
return nil
}
func (l *govulncheckActionVerboseListener) Logger(_ uuid.UUID, task string) workflow.Logger {
return &govulncheckActionTestLogger{t: l.t, task: task}
}
type govulncheckActionTestLogger struct {
t *testing.T
task string
}
func (l *govulncheckActionTestLogger) Printf(format string, v ...any) {
l.t.Logf("task %-10v: LOG: %s", l.task, fmt.Sprintf(format, v...))
}