зеркало из https://github.com/golang/build.git
452 строки
12 KiB
Go
452 строки
12 KiB
Go
// Copyright 2020 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 buildlet
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/build/buildenv"
|
|
"golang.org/x/build/dashboard"
|
|
"golang.org/x/build/internal/cloud"
|
|
)
|
|
|
|
func TestStartNewVM(t *testing.T) {
|
|
kp, err := NewKeyPair()
|
|
if err != nil {
|
|
t.Fatalf("unable to generate key pair: %s", err)
|
|
}
|
|
buildEnv := &buildenv.Environment{}
|
|
hconf := &dashboard.HostConfig{
|
|
VMImage: "image-x",
|
|
}
|
|
vmName := "sample-vm"
|
|
hostType := "host-sample-os"
|
|
opts := &VMOpts{
|
|
Zone: "us-west",
|
|
ProjectID: "project1",
|
|
TLS: kp,
|
|
Description: "Golang builder for sample",
|
|
Meta: map[string]string{
|
|
"Owner": "george",
|
|
},
|
|
DeleteIn: 45 * time.Second,
|
|
SkipEndpointVerification: true,
|
|
}
|
|
c := &EC2Client{
|
|
client: cloud.NewFakeAWSClient(),
|
|
}
|
|
gotClient, gotErr := c.StartNewVM(context.Background(), buildEnv, hconf, vmName, hostType, opts)
|
|
if gotErr != nil {
|
|
t.Fatalf("error is not nil: %v", gotErr)
|
|
}
|
|
if gotClient == nil {
|
|
t.Fatalf("response is nil")
|
|
}
|
|
}
|
|
|
|
func TestStartNewVMError(t *testing.T) {
|
|
kp, err := NewKeyPair()
|
|
if err != nil {
|
|
t.Fatalf("unable to generate key pair: %s", err)
|
|
}
|
|
|
|
testCases := []struct {
|
|
desc string
|
|
buildEnv *buildenv.Environment
|
|
hconf *dashboard.HostConfig
|
|
vmName string
|
|
hostType string
|
|
opts *VMOpts
|
|
}{
|
|
{
|
|
desc: "nil-buildenv",
|
|
hconf: &dashboard.HostConfig{},
|
|
vmName: "sample-vm",
|
|
hostType: "host-sample-os",
|
|
opts: &VMOpts{
|
|
Zone: "us-west",
|
|
ProjectID: "project1",
|
|
TLS: kp,
|
|
Description: "Golang builder for sample",
|
|
Meta: map[string]string{
|
|
"Owner": "george",
|
|
},
|
|
DeleteIn: 45 * time.Second,
|
|
},
|
|
},
|
|
{
|
|
desc: "nil-hconf",
|
|
buildEnv: &buildenv.Environment{},
|
|
vmName: "sample-vm",
|
|
hostType: "host-sample-os",
|
|
opts: &VMOpts{
|
|
Zone: "us-west",
|
|
ProjectID: "project1",
|
|
TLS: kp,
|
|
Description: "Golang builder for sample",
|
|
Meta: map[string]string{
|
|
"Owner": "george",
|
|
},
|
|
DeleteIn: 45 * time.Second,
|
|
},
|
|
},
|
|
{
|
|
desc: "empty-vnName",
|
|
buildEnv: &buildenv.Environment{},
|
|
hconf: &dashboard.HostConfig{},
|
|
vmName: "",
|
|
hostType: "host-sample-os",
|
|
opts: &VMOpts{
|
|
Zone: "us-west",
|
|
ProjectID: "project1",
|
|
TLS: kp,
|
|
Description: "Golang builder for sample",
|
|
Meta: map[string]string{
|
|
"Owner": "george",
|
|
},
|
|
DeleteIn: 45 * time.Second,
|
|
},
|
|
},
|
|
{
|
|
desc: "empty-hostType",
|
|
buildEnv: &buildenv.Environment{},
|
|
hconf: &dashboard.HostConfig{},
|
|
vmName: "sample-vm",
|
|
hostType: "",
|
|
opts: &VMOpts{
|
|
Zone: "us-west",
|
|
ProjectID: "project1",
|
|
TLS: kp,
|
|
Description: "Golang builder for sample",
|
|
Meta: map[string]string{
|
|
"Owner": "george",
|
|
},
|
|
DeleteIn: 45 * time.Second,
|
|
},
|
|
},
|
|
{
|
|
desc: "missing-certs",
|
|
buildEnv: &buildenv.Environment{},
|
|
hconf: &dashboard.HostConfig{},
|
|
vmName: "sample-vm",
|
|
hostType: "host-sample-os",
|
|
opts: &VMOpts{
|
|
Zone: "us-west",
|
|
ProjectID: "project1",
|
|
Description: "Golang builder for sample",
|
|
Meta: map[string]string{
|
|
"Owner": "george",
|
|
},
|
|
DeleteIn: 45 * time.Second,
|
|
},
|
|
},
|
|
{
|
|
desc: "nil-opts",
|
|
buildEnv: &buildenv.Environment{},
|
|
hconf: &dashboard.HostConfig{},
|
|
vmName: "sample-vm",
|
|
hostType: "host-sample-os",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
c := &EC2Client{
|
|
client: cloud.NewFakeAWSClient(),
|
|
}
|
|
gotClient, gotErr := c.StartNewVM(context.Background(), tc.buildEnv, tc.hconf, tc.vmName, tc.hostType, tc.opts)
|
|
if gotErr == nil {
|
|
t.Errorf("StartNewVM(ctx, %+v, %+v, %s, %s, %+v) = %+v, nil; want error", tc.buildEnv, tc.hconf, tc.vmName, tc.hostType, tc.opts, gotClient)
|
|
}
|
|
if gotClient != nil {
|
|
t.Errorf("got %+v; expected nil", gotClient)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWaitUntilInstanceExists(t *testing.T) {
|
|
vmConfig := &cloud.EC2VMConfiguration{
|
|
ImageID: "foo",
|
|
Type: "type-a",
|
|
Zone: "eu-15",
|
|
}
|
|
invoked := false
|
|
opts := &VMOpts{
|
|
OnInstanceCreated: func() {
|
|
invoked = true
|
|
},
|
|
}
|
|
ctx := context.Background()
|
|
c := &EC2Client{
|
|
client: cloud.NewFakeAWSClient(),
|
|
}
|
|
gotVM, gotErr := c.createVM(ctx, vmConfig, opts)
|
|
if gotErr != nil {
|
|
t.Fatalf("createVM(ctx, %v, %v) failed with %s", vmConfig, opts, gotErr)
|
|
}
|
|
gotErr = c.waitUntilVMExists(ctx, gotVM.ID, opts)
|
|
if gotErr != nil {
|
|
t.Fatalf("WaitUntilVMExists(%v, %v, %v) failed with error %s", ctx, gotVM.ID, opts, gotErr)
|
|
}
|
|
if !invoked {
|
|
t.Errorf("OnInstanceCreated() was not invoked")
|
|
}
|
|
}
|
|
|
|
func TestCreateVM(t *testing.T) {
|
|
vmConfig := &cloud.EC2VMConfiguration{
|
|
ImageID: "foo",
|
|
Type: "type-a",
|
|
Zone: "eu-15",
|
|
}
|
|
invoked := false
|
|
opts := &VMOpts{
|
|
OnInstanceRequested: func() {
|
|
invoked = true
|
|
},
|
|
}
|
|
c := &EC2Client{
|
|
client: cloud.NewFakeAWSClient(),
|
|
}
|
|
gotVM, gotErr := c.createVM(context.Background(), vmConfig, opts)
|
|
if gotErr != nil {
|
|
t.Fatalf("createVM(ctx, %v, %v) failed with %s", vmConfig, opts, gotErr)
|
|
}
|
|
if gotVM.ImageID != vmConfig.ImageID || gotVM.Type != vmConfig.Type || gotVM.Zone != vmConfig.Zone {
|
|
t.Errorf("createVM(ctx, %+v, %+v) = %+v, nil; want vm to match config", vmConfig, opts, gotVM)
|
|
}
|
|
if !invoked {
|
|
t.Errorf("OnInstanceRequested() was not invoked")
|
|
}
|
|
}
|
|
|
|
func TestCreateVMError(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
vmConfig *cloud.EC2VMConfiguration
|
|
opts *VMOpts
|
|
}{
|
|
{
|
|
desc: "missing-vmConfig",
|
|
},
|
|
{
|
|
desc: "missing-image-id",
|
|
vmConfig: &cloud.EC2VMConfiguration{
|
|
Type: "type-a",
|
|
Zone: "eu-15",
|
|
},
|
|
opts: &VMOpts{
|
|
OnInstanceRequested: func() {},
|
|
},
|
|
},
|
|
{
|
|
desc: "missing-instance-id",
|
|
vmConfig: &cloud.EC2VMConfiguration{
|
|
ImageID: "foo",
|
|
Zone: "eu-15",
|
|
},
|
|
opts: &VMOpts{
|
|
OnInstanceRequested: func() {},
|
|
},
|
|
},
|
|
{
|
|
desc: "missing-placement",
|
|
vmConfig: &cloud.EC2VMConfiguration{
|
|
Name: "foo",
|
|
Type: "type-a",
|
|
},
|
|
opts: &VMOpts{
|
|
OnInstanceRequested: func() {},
|
|
},
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
c := &EC2Client{
|
|
client: cloud.NewFakeAWSClient(),
|
|
//client: &fakeAWSClient{},
|
|
}
|
|
gotVM, gotErr := c.createVM(context.Background(), tc.vmConfig, tc.opts)
|
|
if gotErr == nil {
|
|
t.Errorf("createVM(ctx, %v, %v) = %s, %v; want error", tc.vmConfig, tc.opts, gotVM.ID, gotErr)
|
|
}
|
|
if gotVM != nil {
|
|
t.Errorf("createVM(ctx, %v, %v) = %s, %v; %q, error", tc.vmConfig, tc.opts, gotVM.ID, gotErr, "")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEC2BuildletParams(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
inst *cloud.Instance
|
|
opts *VMOpts
|
|
wantURL string
|
|
wantPort string
|
|
wantCalled bool
|
|
wantErr bool
|
|
}{
|
|
{
|
|
desc: "base-case",
|
|
inst: &cloud.Instance{
|
|
IPAddressExternal: "8.8.8.8",
|
|
IPAddressInternal: "3.3.3.3",
|
|
},
|
|
opts: &VMOpts{},
|
|
wantCalled: true,
|
|
wantURL: "https://8.8.8.8",
|
|
wantPort: "8.8.8.8:443",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
desc: "missing-int-ip",
|
|
inst: &cloud.Instance{
|
|
IPAddressExternal: "8.8.8.8",
|
|
},
|
|
opts: &VMOpts{},
|
|
wantCalled: true,
|
|
wantURL: "https://8.8.8.8",
|
|
wantPort: "8.8.8.8:443",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
desc: "missing-ext-ip",
|
|
inst: &cloud.Instance{
|
|
IPAddressInternal: "3.3.3.3",
|
|
},
|
|
opts: &VMOpts{},
|
|
wantCalled: true,
|
|
wantURL: "",
|
|
wantPort: "",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
gotURL, gotPort, gotErr := ec2BuildletParams(tc.inst, tc.opts)
|
|
if gotURL != tc.wantURL || gotPort != tc.wantPort || tc.wantErr != (gotErr != nil) {
|
|
t.Errorf("ec2BuildletParams(%v, %v) = %q, %q, nil; want %q, %q, nil", tc.inst, tc.opts, gotURL, gotPort, tc.wantURL, tc.wantPort)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConfigureVM(t *testing.T) {
|
|
testCases := []struct {
|
|
desc string
|
|
buildEnv *buildenv.Environment
|
|
hconf *dashboard.HostConfig
|
|
hostType string
|
|
opts *VMOpts
|
|
vmName string
|
|
wantDesc string
|
|
wantImageID string
|
|
wantInstanceType string
|
|
wantName string
|
|
wantZone string
|
|
wantBuildletName string
|
|
wantBuildletImage string
|
|
}{
|
|
{
|
|
desc: "default-values",
|
|
buildEnv: &buildenv.Environment{},
|
|
hconf: &dashboard.HostConfig{
|
|
KonletVMImage: "gcr.io/symbolic-datum-552/gobuilder-arm64-aws",
|
|
},
|
|
vmName: "base_vm",
|
|
hostType: "host-foo-bar",
|
|
opts: &VMOpts{},
|
|
wantInstanceType: "e2-standard-8",
|
|
wantName: "base_vm",
|
|
wantBuildletName: "base_vm",
|
|
wantBuildletImage: "gcr.io/symbolic-datum-552/gobuilder-arm64-aws",
|
|
},
|
|
{
|
|
desc: "full-configuration",
|
|
buildEnv: &buildenv.Environment{},
|
|
hconf: &dashboard.HostConfig{
|
|
VMImage: "awesome_image",
|
|
KonletVMImage: "gcr.io/symbolic-datum-552/gobuilder-arm64-aws",
|
|
},
|
|
vmName: "base-vm",
|
|
hostType: "host-foo-bar",
|
|
opts: &VMOpts{
|
|
Zone: "sa-west",
|
|
TLS: KeyPair{
|
|
CertPEM: "abc",
|
|
KeyPEM: "xyz",
|
|
},
|
|
Description: "test description",
|
|
Meta: map[string]string{
|
|
"sample": "value",
|
|
},
|
|
},
|
|
wantDesc: "test description",
|
|
wantImageID: "awesome_image",
|
|
wantInstanceType: "e2-standard-8",
|
|
wantName: "base-vm",
|
|
wantZone: "sa-west",
|
|
wantBuildletName: "base-vm",
|
|
wantBuildletImage: "gcr.io/symbolic-datum-552/gobuilder-arm64-aws",
|
|
},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
got := configureVM(tc.buildEnv, tc.hconf, tc.vmName, tc.hostType, tc.opts)
|
|
if got.ImageID != tc.wantImageID {
|
|
t.Errorf("ImageId got %s; want %s", got.ImageID, tc.wantImageID)
|
|
}
|
|
if got.Type != tc.wantInstanceType {
|
|
t.Errorf("Type got %s; want %s", got.Type, tc.wantInstanceType)
|
|
}
|
|
if got.Zone != tc.wantZone {
|
|
t.Errorf("Zone got %s; want %s", got.Zone, tc.wantZone)
|
|
}
|
|
if got.Name != tc.wantName {
|
|
t.Errorf("Name got %s; want %s", got.Name, tc.wantName)
|
|
}
|
|
if got.Description != tc.wantDesc {
|
|
t.Errorf("Description got %s; want %s", got.Description, tc.wantDesc)
|
|
}
|
|
gotUDJson, err := base64.StdEncoding.DecodeString(got.UserData)
|
|
if err != nil {
|
|
t.Fatalf("unable to base64 decode string %q: %s", got.UserData, err)
|
|
}
|
|
gotUD := &cloud.EC2UserData{}
|
|
err = json.Unmarshal([]byte(gotUDJson), gotUD)
|
|
if err != nil {
|
|
t.Errorf("unable to unmarshal user data: %v", err)
|
|
}
|
|
if gotUD.BuildletBinaryURL != tc.hconf.BuildletBinaryURL(tc.buildEnv) {
|
|
t.Errorf("buildletBinaryURL got %s; want %s", gotUD.BuildletBinaryURL, tc.hconf.BuildletBinaryURL(tc.buildEnv))
|
|
}
|
|
if gotUD.BuildletHostType != tc.hostType {
|
|
t.Errorf("buildletHostType got %s; want %s", gotUD.BuildletHostType, tc.hostType)
|
|
}
|
|
if gotUD.BuildletName != tc.wantBuildletName {
|
|
t.Errorf("buildletName got %s; want %s", gotUD.BuildletName, tc.wantBuildletName)
|
|
}
|
|
if gotUD.BuildletImageURL != tc.wantBuildletImage {
|
|
t.Errorf("buildletImageURL got %s; want %s", gotUD.BuildletImageURL, tc.wantBuildletImage)
|
|
}
|
|
|
|
if gotUD.TLSCert != tc.opts.TLS.CertPEM {
|
|
t.Errorf("TLSCert got %s; want %s", gotUD.TLSCert, tc.opts.TLS.CertPEM)
|
|
}
|
|
if gotUD.TLSKey != tc.opts.TLS.KeyPEM {
|
|
t.Errorf("TLSKey got %s; want %s", gotUD.TLSKey, tc.opts.TLS.KeyPEM)
|
|
}
|
|
if gotUD.TLSPassword != tc.opts.TLS.Password() {
|
|
t.Errorf("TLSPassword got %s; want %s", gotUD.TLSPassword, tc.opts.TLS.Password())
|
|
}
|
|
})
|
|
}
|
|
}
|