182 lines
5.3 KiB
Go
182 lines
5.3 KiB
Go
package oci
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/oracle/oci-go-sdk/v65/core"
|
|
)
|
|
|
|
func TestShellSingleQuote(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
in string
|
|
want string
|
|
}{
|
|
{name: "普通", in: "Passw0rd", want: "'Passw0rd'"},
|
|
{name: "含单引号", in: "a'b", want: `'a'\''b'`},
|
|
{name: "含空格特殊符", in: "p @ss!", want: "'p @ss!'"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := shellSingleQuote(tt.in); got != tt.want {
|
|
t.Errorf("shellSingleQuote(%q) = %q, want %q", tt.in, got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRootPasswordUserData(t *testing.T) {
|
|
encoded := rootPasswordUserData("Secret123")
|
|
raw, err := base64.StdEncoding.DecodeString(encoded)
|
|
if err != nil {
|
|
t.Fatalf("result is not base64: %v", err)
|
|
}
|
|
script := string(raw)
|
|
for _, want := range []string{
|
|
"#!/bin/bash",
|
|
"echo root:'Secret123' | chpasswd",
|
|
"PermitRootLogin yes",
|
|
"PasswordAuthentication yes",
|
|
"systemctl restart sshd",
|
|
} {
|
|
if !strings.Contains(script, want) {
|
|
t.Errorf("script missing %q\n---\n%s", want, script)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildInstanceMetadataRootPasswordOverridesUserData(t *testing.T) {
|
|
md := buildInstanceMetadata(CreateInstanceInput{
|
|
RootPassword: "pw",
|
|
UserData: "ZXhwbGljaXQ=", // "explicit"
|
|
})
|
|
decoded, _ := base64.StdEncoding.DecodeString(md["user_data"])
|
|
if !strings.Contains(string(decoded), "chpasswd") {
|
|
t.Errorf("user_data = %q, want root password script (not explicit userData)", md["user_data"])
|
|
}
|
|
}
|
|
|
|
func TestBuildInstanceSourceVpusPerGB(t *testing.T) {
|
|
src := buildInstanceSource(CreateInstanceInput{ImageID: "img", BootVolumeSizeGBs: 100, BootVolumeVpusPerGB: 20})
|
|
img, ok := src.(core.InstanceSourceViaImageDetails)
|
|
if !ok {
|
|
t.Fatalf("source type = %T, want image", src)
|
|
}
|
|
if img.BootVolumeVpusPerGB == nil || *img.BootVolumeVpusPerGB != 20 {
|
|
t.Errorf("BootVolumeVpusPerGB = %v, want 20", img.BootVolumeVpusPerGB)
|
|
}
|
|
}
|
|
|
|
func TestBuildInstanceSource(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
in CreateInstanceInput
|
|
wantType string
|
|
}{
|
|
{
|
|
name: "从镜像启动",
|
|
in: CreateInstanceInput{ImageID: "ocid1.image..a", BootVolumeSizeGBs: 100},
|
|
wantType: "image",
|
|
},
|
|
{
|
|
name: "从引导卷启动",
|
|
in: CreateInstanceInput{BootVolumeID: "ocid1.bootvolume..b"},
|
|
wantType: "bootVolume",
|
|
},
|
|
{
|
|
name: "引导卷优先于镜像",
|
|
in: CreateInstanceInput{ImageID: "ocid1.image..a", BootVolumeID: "ocid1.bootvolume..b"},
|
|
wantType: "bootVolume",
|
|
},
|
|
{
|
|
name: "两者皆无返回 nil",
|
|
in: CreateInstanceInput{},
|
|
wantType: "nil",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
src := buildInstanceSource(tt.in)
|
|
switch tt.wantType {
|
|
case "image":
|
|
img, ok := src.(core.InstanceSourceViaImageDetails)
|
|
if !ok {
|
|
t.Fatalf("source type = %T, want InstanceSourceViaImageDetails", src)
|
|
}
|
|
if got, want := *img.BootVolumeSizeInGBs, tt.in.BootVolumeSizeGBs; got != want {
|
|
t.Errorf("BootVolumeSizeInGBs = %d, want %d", got, want)
|
|
}
|
|
case "bootVolume":
|
|
if _, ok := src.(core.InstanceSourceViaBootVolumeDetails); !ok {
|
|
t.Fatalf("source type = %T, want InstanceSourceViaBootVolumeDetails", src)
|
|
}
|
|
case "nil":
|
|
if src != nil {
|
|
t.Fatalf("source = %v, want nil", src)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildLaunchDetails(t *testing.T) {
|
|
in := CreateInstanceInput{
|
|
AvailabilityDomain: "AD-1",
|
|
DisplayName: "vm1",
|
|
Shape: "VM.Standard.A1.Flex",
|
|
Ocpus: 2,
|
|
MemoryInGBs: 12,
|
|
ImageID: "ocid1.image..a",
|
|
SubnetID: "ocid1.subnet..s",
|
|
AssignPublicIP: true,
|
|
AssignIpv6: true,
|
|
SSHPublicKey: "ssh-ed25519 AAA",
|
|
}
|
|
details, err := buildLaunchDetails("ocid1.tenancy..t", in)
|
|
if err != nil {
|
|
t.Fatalf("buildLaunchDetails: %v", err)
|
|
}
|
|
if got, want := *details.ShapeConfig.Ocpus, float32(2); got != want {
|
|
t.Errorf("Ocpus = %v, want %v", got, want)
|
|
}
|
|
if got, want := *details.ShapeConfig.MemoryInGBs, float32(12); got != want {
|
|
t.Errorf("MemoryInGBs = %v, want %v", got, want)
|
|
}
|
|
if got, want := *details.CreateVnicDetails.SubnetId, in.SubnetID; got != want {
|
|
t.Errorf("SubnetId = %v, want %v", got, want)
|
|
}
|
|
if details.CreateVnicDetails.AssignIpv6Ip == nil || !*details.CreateVnicDetails.AssignIpv6Ip {
|
|
t.Error("AssignIpv6Ip not set, want true")
|
|
}
|
|
if got, want := details.Metadata["ssh_authorized_keys"], in.SSHPublicKey; got != want {
|
|
t.Errorf("ssh_authorized_keys = %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestBuildLaunchDetailsRequiresSource(t *testing.T) {
|
|
_, err := buildLaunchDetails("ocid1.tenancy..t", CreateInstanceInput{
|
|
AvailabilityDomain: "AD-1", DisplayName: "vm1", Shape: "shape", SubnetID: "sub",
|
|
})
|
|
if err == nil {
|
|
t.Error("buildLaunchDetails without source: got nil error, want failure")
|
|
}
|
|
}
|
|
|
|
func TestBuildLaunchDetailsNoShapeConfig(t *testing.T) {
|
|
details, err := buildLaunchDetails("t", CreateInstanceInput{
|
|
AvailabilityDomain: "AD-1", DisplayName: "vm1", Shape: "VM.Standard.E2.1.Micro",
|
|
ImageID: "img", SubnetID: "sub",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("buildLaunchDetails: %v", err)
|
|
}
|
|
if details.ShapeConfig != nil {
|
|
t.Errorf("ShapeConfig = %+v, want nil for fixed shape", details.ShapeConfig)
|
|
}
|
|
if details.Metadata != nil {
|
|
t.Errorf("Metadata = %v, want nil when no key and user data", details.Metadata)
|
|
}
|
|
}
|