blob: 99e2147325b8e943885c3bdd93d85cd70e19132b [file] [log] [blame]
// Copyright 2024 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 (
"archive/zip"
"bytes"
"context"
"fmt"
"io"
"path/filepath"
"regexp"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"golang.org/x/build/internal/workflow"
)
func TestVSCodeGoReleaseTask_buildVSCGO(t *testing.T) {
mustHaveShell(t)
tests := []struct {
name string
revision string
wantBuildError bool
}{
{
name: "success",
revision: "release",
},
{
name: "broken build",
revision: "master", // broken
wantBuildError: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
repo := NewFakeRepo(t, "vscode-go")
t1 := repo.Commit(map[string]string{
"go.mod": "module github.com/golang/vscode-go\n",
"go.sum": "\n",
"vscgo/main.go": "package main\nfunc main() { println(\"v1\") }\n",
})
repo.Branch("release", t1)
_ = repo.Commit(map[string]string{
"vscgo/broken.go": "package broken\n", // broken at master
})
gerrit := NewFakeGerrit(t, repo)
scratchDir := t.TempDir()
// fakeGo will record the invocation command in the fake output.
const fakeGo = `#!/bin/bash -eu
function find_output_value() {
# returns -o flag value.
while [[ $# -gt 0 ]]; do
case "$1" in
-o)
if [[ $# -gt 1 ]]; then
echo "$2"
shift 2
else
echo "Error: No argument provided after '-o'"
exit 1
fi
;;
*)
shift
;;
esac
done
}
case "$1" in
"build")
if [[ -f "vscgo/broken.go" ]]; then
echo build broken
exit 1
fi
out=$(find_output_value "$@")
echo "GOOS=${GOOS} GOARCH=${GOARCH} $0 $@" > "${out}"
exit 0
;;
*)
echo unexpected command $@
;;
esac
`
releaseTask := &VSCodeGoReleaseTask{
CloudBuild: NewFakeCloudBuild(t, gerrit, "vscode-go", nil, fakeGo),
ScratchFS: &ScratchFS{BaseURL: "file://" + scratchDir},
Revision: test.revision,
}
wd := releaseTask.NewDefinition()
w, err := workflow.Start(wd, map[string]interface{}{
vscgoVersionParam.Name: "v0.0.0",
})
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
outputs, err := w.Run(ctx, &verboseListener{t: t, onStall: cancel})
if err != nil {
if test.wantBuildError {
return // expected build error.
}
t.Fatal(err)
}
buildArtifacts, ok := outputs["build artifacts"].([]goBuildArtifact)
if !ok {
t.Fatalf("unexpected build artifacts: %T (%+v): ", outputs, outputs)
}
var want []goBuildArtifact
for _, p := range vscgoPlatforms {
want = append(want, goBuildArtifact{
Platform: p.Platform,
})
}
sortSlice := cmpopts.SortSlices(
func(x, y goBuildArtifact) bool { return x.Platform < y.Platform },
)
ignoreFilename := cmpopts.IgnoreFields(goBuildArtifact{}, "Filename")
if diff := cmp.Diff(buildArtifacts, want, sortSlice, ignoreFilename); diff != "" {
t.Fatal(diff)
}
// HACK: Reading directly from the scratch filesystem.
envMap := make(map[string][]string)
for _, p := range vscgoPlatforms {
envMap[p.Platform] = p.Env
}
re := regexp.MustCompile(`-([a-z0-9]+-[a-z0-9]+)-vscgo\.zip$`)
for _, a := range buildArtifacts {
m := re.FindStringSubmatch(a.Filename)
if m == nil {
t.Errorf(
"artifact file with unexpected file name: %q, want <platform>-<arch>-vscgo.zip",
a.Filename,
)
continue
}
platform := m[1]
if platform != a.Platform {
t.Errorf(
"artifact file with unexpected platform: %q, want %q",
a.Platform,
platform,
)
continue
}
// The output files are zip files.
executable := "vscgo"
if strings.HasPrefix(platform, "win32") {
executable = "vscgo.exe"
}
data, err := extractFileZip(t, filepath.Join(scratchDir, w.ID.String(), a.Filename), executable)
if err != nil {
t.Errorf("%v: %v", a.Platform, err)
}
envs := envMap[a.Platform]
if !bytes.Contains(data, []byte(strings.Join(envs, " "))) {
t.Errorf("%v: unexpected contents: %s", a.Platform, data)
}
}
})
}
}
func extractFileZip(t *testing.T, zipfile, fileToExtract string) ([]byte, error) {
r, err := zip.OpenReader(zipfile)
if err != nil {
return nil, err
}
defer r.Close()
// Iterate through the files in the archive,
// return the contents of the requested file.
for _, f := range r.File {
if f.Name != fileToExtract {
t.Errorf("unexpected file in zip: %q", f.Name)
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
return io.ReadAll(rc)
}
return nil, fmt.Errorf("file %q not found", fileToExtract)
}