Files
virtual-kubelet/vendor/github.com/vmware/govmomi/toolbox/command_test.go
Loc Nguyen 513cebe7b7 VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC

Initial virtual kubelet provider for VMware VIC.  This provider currently
handles creating and starting of a pod VM via the VIC portlayer and persona
server.  Image store handling via the VIC persona server.  This provider
currently requires the feature/wolfpack branch of VIC.

* Added pod stop and delete.  Also added node capacity.

Added the ability to stop and delete pod VMs via VIC.  Also retrieve
node capacity information from the VCH.

* Cleanup and readme file

Some file clean up and added a Readme.md markdown file for the VIC
provider.

* Cleaned up errors, added function comments, moved operation code

1. Cleaned up error handling.  Set standard for creating errors.
2. Added method prototype comments for all interface functions.
3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder.

* Add mocking code and unit tests for podcache, podcreator, and podstarter

Used the unit test framework used in VIC to handle assertions in the provider's
unit test.  Mocking code generated using OSS project mockery, which is compatible
with the testify assertion framework.

* Vendored packages for the VIC provider

Requires feature/wolfpack branch of VIC and a few specific commit sha of
projects used within VIC.

* Implementation of POD Stopper and Deleter unit tests (#4)

* Updated files for initial PR
2018-06-04 15:41:32 -07:00

973 lines
20 KiB
Go

/*
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package toolbox
import (
"bytes"
"context"
"encoding"
"encoding/binary"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
"github.com/vmware/govmomi/toolbox/hgfs"
"github.com/vmware/govmomi/toolbox/vix"
)
type CommandClient struct {
Service *Service
Header *vix.CommandRequestHeader
creds []byte
}
func NewCommandClient() *CommandClient {
Trace = testing.Verbose()
hgfs.Trace = Trace
creds, _ := (&vix.UserCredentialNamePassword{
Name: "user",
Password: "pass",
}).MarshalBinary()
header := new(vix.CommandRequestHeader)
header.Magic = vix.CommandMagicWord
header.UserCredentialType = vix.UserCredentialTypeNamePassword
header.CredentialLength = uint32(len(creds))
in := new(mockChannelIn)
out := new(mockChannelOut)
return &CommandClient{
creds: creds,
Header: header,
Service: NewService(in, out),
}
}
func (c *CommandClient) Request(op uint32, m encoding.BinaryMarshaler) []byte {
b, err := m.MarshalBinary()
if err != nil {
panic(err)
}
c.Header.OpCode = op
c.Header.BodyLength = uint32(len(b))
var buf bytes.Buffer
_, _ = buf.Write([]byte("\"reqname\"\x00"))
_ = binary.Write(&buf, binary.LittleEndian, c.Header)
_, _ = buf.Write(b)
data := append(buf.Bytes(), c.creds...)
reply, err := c.Service.Command.Dispatch(data)
if err != nil {
panic(err)
}
return reply
}
func vixRC(buf []byte) int {
args := bytes.SplitN(buf, []byte{' '}, 2)
rc, err := strconv.Atoi(string(args[0]))
if err != nil {
panic(err)
}
return rc
}
func TestVixRelayedCommandHandler(t *testing.T) {
Trace = true
if !testing.Verbose() {
// cover Trace paths but discard output
traceLog = ioutil.Discard
}
in := new(mockChannelIn)
out := new(mockChannelOut)
service := NewService(in, out)
cmd := service.Command
msg := []byte("\"reqname\"\x00")
_, err := cmd.Dispatch(msg) // io.EOF
if err == nil {
t.Fatal("expected error")
}
header := new(vix.CommandRequestHeader)
marshal := func(m ...encoding.BinaryMarshaler) []byte {
var buf bytes.Buffer
_, _ = buf.Write(msg)
_ = binary.Write(&buf, binary.LittleEndian, header)
for _, e := range m {
b, err := e.MarshalBinary()
if err != nil {
panic(err)
}
_, _ = buf.Write(b)
}
return buf.Bytes()
}
// header.Magic not set
reply, _ := cmd.Dispatch(marshal())
rc := vixRC(reply)
if rc != vix.InvalidMessageHeader {
t.Fatalf("%q", reply)
}
// header.OpCode not set
header.Magic = vix.CommandMagicWord
reply, _ = cmd.Dispatch(marshal())
rc = vixRC(reply)
if rc != vix.UnrecognizedCommandInGuest {
t.Fatalf("%q", reply)
}
// valid request for GetToolsState
header.OpCode = vix.CommandGetToolsState
reply, _ = cmd.Dispatch(marshal())
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("%q", reply)
}
// header.UserCredentialType not set
header.OpCode = vix.CommandStartProgram
request := new(vix.StartProgramRequest)
buf := marshal(request)
reply, _ = cmd.Dispatch(marshal())
rc = vixRC(reply)
if rc != vix.AuthenticationFail {
t.Fatalf("%q", reply)
}
creds, _ := (&vix.UserCredentialNamePassword{
Name: "user",
Password: "pass",
}).MarshalBinary()
header.BodyLength = uint32(binary.Size(request.Body))
header.UserCredentialType = vix.UserCredentialTypeNamePassword
header.CredentialLength = uint32(len(creds))
// ProgramPath not set
buf = append(marshal(request), creds...)
reply, _ = cmd.Dispatch(buf)
rc = vixRC(reply)
if rc != vix.FileNotFound {
t.Fatalf("%q", reply)
}
cmd.ProcessStartCommand = func(pm *ProcessManager, r *vix.StartProgramRequest) (int64, error) {
return -1, nil
}
// valid request for StartProgram
buf = append(marshal(request), creds...)
reply, _ = cmd.Dispatch(buf)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("%q", reply)
}
cmd.Authenticate = func(_ vix.CommandRequestHeader, data []byte) error {
var c vix.UserCredentialNamePassword
if err := c.UnmarshalBinary(data); err != nil {
panic(err)
}
return errors.New("you shall not pass")
}
// fail auth with our own handler
buf = append(marshal(request), creds...)
reply, _ = cmd.Dispatch(buf)
rc = vixRC(reply)
if rc != vix.AuthenticationFail {
t.Fatalf("%q", reply)
}
cmd.Authenticate = nil
// cause Vix.UserCredentialNamePassword.UnmarshalBinary to error
// first by EOF reading header, second in base64 decode
for _, l := range []uint32{1, 10} {
header.CredentialLength = l
buf = append(marshal(request), creds...)
reply, _ = cmd.Dispatch(buf)
rc = vixRC(reply)
if rc != vix.AuthenticationFail {
t.Fatalf("%q", reply)
}
}
}
// cover misc error paths
func TestVixCommandErrors(t *testing.T) {
r := new(vix.StartProgramRequest)
err := r.UnmarshalBinary(nil)
if err == nil {
t.Error("expected error")
}
r.Body.NumEnvVars = 1
buf, _ := r.MarshalBinary()
err = r.UnmarshalBinary(buf)
if err == nil {
t.Error("expected error")
}
c := new(CommandServer)
_, err = c.StartCommand(r.CommandRequestHeader, nil)
if err == nil {
t.Error("expected error")
}
}
func TestVixInitiateDirTransfer(t *testing.T) {
c := NewCommandClient()
dir := os.TempDir()
for _, enable := range []bool{true, false} {
expect := vix.NotAFile
if enable {
expect = vix.OK
} else {
// validate we behave as open-vm-tools does when the directory archive feature is disabled
c.Service.Command.FileServer.RegisterFileHandler(hgfs.ArchiveScheme, nil)
}
fromGuest := &vix.ListFilesRequest{GuestPathName: dir}
toGuest := &vix.InitiateFileTransferToGuestRequest{GuestPathName: dir}
toGuest.Body.Overwrite = true
tests := []struct {
op uint32
request encoding.BinaryMarshaler
}{
{vix.CommandInitiateFileTransferFromGuest, fromGuest},
{vix.CommandInitiateFileTransferToGuest, toGuest},
}
for _, test := range tests {
reply := c.Request(test.op, test.request)
rc := vixRC(reply)
if rc != expect {
t.Errorf("rc=%d", rc)
}
}
}
}
func TestVixInitiateFileTransfer(t *testing.T) {
c := NewCommandClient()
request := new(vix.ListFilesRequest)
f, err := ioutil.TempFile("", "toolbox")
if err != nil {
t.Fatal(err)
}
for _, s := range []string{"a", "b", "c", "d", "e"} {
_, _ = f.WriteString(strings.Repeat(s, 40))
}
_ = f.Close()
name := f.Name()
// 1st pass file exists == OK, 2nd pass does not exist == FAIL
for _, fail := range []bool{false, true} {
request.GuestPathName = name
reply := c.Request(vix.CommandInitiateFileTransferFromGuest, request)
rc := vixRC(reply)
if Trace {
fmt.Fprintf(os.Stderr, "%s: %s\n", name, string(reply))
}
if fail {
if rc == vix.OK {
t.Errorf("%s: %d", name, rc)
}
} else {
if rc != vix.OK {
t.Errorf("%s: %d", name, rc)
}
err = os.Remove(name)
if err != nil {
t.Error(err)
}
}
}
}
func TestVixInitiateFileTransferWrite(t *testing.T) {
c := NewCommandClient()
request := new(vix.InitiateFileTransferToGuestRequest)
f, err := ioutil.TempFile("", "toolbox")
if err != nil {
t.Fatal(err)
}
_ = f.Close()
name := f.Name()
tests := []struct {
force bool
fail bool
}{
{false, true}, // exists == FAIL
{true, false}, // exists, but overwrite == OK
{false, false}, // does not exist == OK
}
for i, test := range tests {
request.GuestPathName = name
request.Body.Overwrite = test.force
reply := c.Request(vix.CommandInitiateFileTransferToGuest, request)
rc := vixRC(reply)
if Trace {
fmt.Fprintf(os.Stderr, "%s: %s\n", name, string(reply))
}
if test.fail {
if rc == vix.OK {
t.Errorf("%d: %d", i, rc)
}
} else {
if rc != vix.OK {
t.Errorf("%d: %d", i, rc)
}
if test.force {
_ = os.Remove(name)
}
}
}
}
func TestVixProcessHgfsPacket(t *testing.T) {
c := NewCommandClient()
c.Header.CommonFlags = vix.CommandGuestReturnsBinary
request := new(vix.CommandHgfsSendPacket)
op := new(hgfs.RequestCreateSessionV4)
packet := new(hgfs.Packet)
packet.Payload, _ = op.MarshalBinary()
packet.Header.Version = hgfs.HeaderVersion
packet.Header.Dummy = hgfs.OpNewHeader
packet.Header.HeaderSize = uint32(binary.Size(&packet.Header))
packet.Header.PacketSize = packet.Header.HeaderSize + uint32(len(packet.Payload))
packet.Header.Op = hgfs.OpCreateSessionV4
request.Packet, _ = packet.MarshalBinary()
request.Body.PacketSize = uint32(len(request.Packet))
reply := c.Request(vix.HgfsSendPacketCommand, request)
rc := vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
ix := bytes.IndexByte(reply, '#')
reply = reply[ix+1:]
err := packet.UnmarshalBinary(reply)
if err != nil {
t.Fatal(err)
}
if packet.Status != hgfs.StatusSuccess {
t.Errorf("status=%d", packet.Status)
}
if packet.Dummy != hgfs.OpNewHeader {
t.Errorf("dummy=%d", packet.Dummy)
}
session := new(hgfs.ReplyCreateSessionV4)
err = session.UnmarshalBinary(packet.Payload)
if err != nil {
t.Fatal(err)
}
if session.NumCapabilities == 0 || int(session.NumCapabilities) != len(session.Capabilities) {
t.Errorf("NumCapabilities=%d", session.NumCapabilities)
}
}
func TestVixListProcessesEx(t *testing.T) {
c := NewCommandClient()
pm := c.Service.Command.ProcessManager
c.Service.Command.ProcessStartCommand = func(pm *ProcessManager, r *vix.StartProgramRequest) (int64, error) {
var p *Process
switch r.ProgramPath {
case "foo":
p = NewProcessFunc(func(ctx context.Context, arg string) error {
return nil
})
default:
return -1, os.ErrNotExist
}
return pm.Start(r, p)
}
exec := &vix.StartProgramRequest{
ProgramPath: "foo",
}
reply := c.Request(vix.CommandStartProgram, exec)
rc := vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
r := bytes.Trim(bytes.Split(reply, []byte{' '})[2], "\x00")
pid, _ := strconv.Atoi(string(r))
exec.ProgramPath = "bar"
reply = c.Request(vix.CommandStartProgram, exec)
rc = vixRC(reply)
t.Log(vix.Error(rc).Error())
if rc != vix.FileNotFound {
t.Fatalf("rc: %d", rc)
}
if vix.ErrorCode(os.ErrNotExist) != rc {
t.Fatalf("rc: %d", rc)
}
pm.wg.Wait()
ps := new(vix.ListProcessesRequest)
ps.Pids = []int64{int64(pid)}
reply = c.Request(vix.CommandListProcessesEx, ps)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
n := bytes.Count(reply, []byte("<proc>"))
if n != len(ps.Pids) {
t.Errorf("ps -p %d=%d", pid, n)
}
kill := new(vix.KillProcessRequest)
kill.Body.Pid = ps.Pids[0]
reply = c.Request(vix.CommandTerminateProcess, kill)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
kill.Body.Pid = 33333
reply = c.Request(vix.CommandTerminateProcess, kill)
rc = vixRC(reply)
if rc != vix.NoSuchProcess {
t.Fatalf("rc: %d", rc)
}
}
func TestVixGetenv(t *testing.T) {
c := NewCommandClient()
env := os.Environ()
key := strings.SplitN(env[0], "=", 2)[0]
tests := []struct {
names []string
expect int
}{
{nil, len(env)}, // all env
{[]string{key, "ENOENT"}, 1}, // specific vars, 1 exists 1 does not
}
for i, test := range tests {
env := &vix.ReadEnvironmentVariablesRequest{
Names: test.names,
}
reply := c.Request(vix.CommandReadEnvVariables, env)
rc := vixRC(reply)
if rc != vix.OK {
t.Fatalf("%d) rc: %d", i, rc)
}
num := bytes.Count(reply, []byte("<ev>"))
if num != test.expect {
t.Errorf("%d) getenv(%v): %d", i, test.names, num)
}
}
}
func TestVixDirectories(t *testing.T) {
c := NewCommandClient()
mktemp := &vix.CreateTempFileRequest{
FilePrefix: "toolbox-",
}
// mktemp -d
reply := c.Request(vix.CommandCreateTemporaryDirectory, mktemp)
rc := vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
dir := strings.TrimSuffix(string(reply[4:]), "\x00")
mkdir := &vix.DirRequest{
GuestPathName: dir,
}
// mkdir $dir == EEXIST
reply = c.Request(vix.CommandCreateDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.FileAlreadyExists {
t.Fatalf("rc: %d", rc)
}
// mkdir $dir/ok == OK
mkdir.GuestPathName = dir + "/ok"
reply = c.Request(vix.CommandCreateDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
// rm of a dir should fail, regardless if empty or not
reply = c.Request(vix.CommandDeleteGuestFileEx, &vix.FileRequest{
GuestPathName: mkdir.GuestPathName,
})
rc = vixRC(reply)
if rc != vix.NotAFile {
t.Errorf("rc: %d", rc)
}
// rmdir $dir/ok == OK
reply = c.Request(vix.CommandDeleteGuestDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
// rmdir $dir/ok == ENOENT
reply = c.Request(vix.CommandDeleteGuestDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.FileNotFound {
t.Fatalf("rc: %d", rc)
}
// mkdir $dir/1/2 == ENOENT (parent directory does not exist)
mkdir.GuestPathName = dir + "/1/2"
reply = c.Request(vix.CommandCreateDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.FileNotFound {
t.Fatalf("rc: %d", rc)
}
// mkdir -p $dir/1/2 == OK
mkdir.Body.Recursive = true
reply = c.Request(vix.CommandCreateDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
// rmdir $dir == ENOTEMPTY
mkdir.GuestPathName = dir
mkdir.Body.Recursive = false
reply = c.Request(vix.CommandDeleteGuestDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.DirectoryNotEmpty {
t.Fatalf("rc: %d", rc)
}
// rm -rf $dir == OK
mkdir.Body.Recursive = true
reply = c.Request(vix.CommandDeleteGuestDirectoryEx, mkdir)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
}
func TestVixFiles(t *testing.T) {
c := NewCommandClient()
mktemp := &vix.CreateTempFileRequest{
FilePrefix: "toolbox-",
}
// mktemp -d
reply := c.Request(vix.CommandCreateTemporaryDirectory, mktemp)
rc := vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
dir := strings.TrimSuffix(string(reply[4:]), "\x00")
max := 12
var total int
// mktemp
for i := 0; i <= max; i++ {
mktemp = &vix.CreateTempFileRequest{
DirectoryPath: dir,
}
reply = c.Request(vix.CommandCreateTemporaryFileEx, mktemp)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
}
// name of the last file temp file we created, we'll mess around with it then delete it
name := strings.TrimSuffix(string(reply[4:]), "\x00")
// for testing symlinks
link := filepath.Join(dir, "a-link")
err := os.Symlink(name, link)
if err != nil {
t.Fatal(err)
}
for _, fpath := range []string{name, link} {
// test ls of a single file
ls := &vix.ListFilesRequest{
GuestPathName: fpath,
}
reply = c.Request(vix.CommandListFiles, ls)
rc = vixRC(reply)
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
num := bytes.Count(reply, []byte("<fxi>"))
if num != 1 {
t.Errorf("ls %s: %d", name, num)
}
num = bytes.Count(reply, []byte("<rem>0</rem>"))
if num != 1 {
t.Errorf("ls %s: %d", name, num)
}
ft := 0
target := ""
if fpath == link {
target = name
ft = vix.FileAttributesSymlink
}
num = bytes.Count(reply, []byte(fmt.Sprintf("<slt>%s</slt>", target)))
if num != 1 {
t.Errorf("ls %s: %d", name, num)
}
num = bytes.Count(reply, []byte(fmt.Sprintf("<ft>%d</ft>", ft)))
if num != 1 {
t.Errorf("ls %s: %d", name, num)
}
}
mv := &vix.RenameFileRequest{
OldPathName: name,
NewPathName: name + "-new",
}
for _, expect := range []int{vix.OK, vix.FileNotFound} {
reply = c.Request(vix.CommandMoveGuestFileEx, mv)
rc = vixRC(reply)
if rc != expect {
t.Errorf("rc: %d", rc)
}
if expect == vix.OK {
// test file type is properly checked
reply = c.Request(vix.CommandMoveGuestDirectory, &vix.RenameFileRequest{
OldPathName: mv.NewPathName,
NewPathName: name,
})
rc = vixRC(reply)
if rc != vix.NotADirectory {
t.Errorf("rc: %d", rc)
}
// test Overwrite flag is properly checked
reply = c.Request(vix.CommandMoveGuestFileEx, &vix.RenameFileRequest{
OldPathName: mv.NewPathName,
NewPathName: mv.NewPathName,
})
rc = vixRC(reply)
if rc != vix.FileAlreadyExists {
t.Errorf("rc: %d", rc)
}
}
}
// rmdir of a file should fail
reply = c.Request(vix.CommandDeleteGuestDirectoryEx, &vix.DirRequest{
GuestPathName: mv.NewPathName,
})
rc = vixRC(reply)
if rc != vix.NotADirectory {
t.Errorf("rc: %d", rc)
}
file := &vix.FileRequest{
GuestPathName: mv.NewPathName,
}
for _, expect := range []int{vix.OK, vix.FileNotFound} {
reply = c.Request(vix.CommandDeleteGuestFileEx, file)
rc = vixRC(reply)
if rc != expect {
t.Errorf("rc: %d", rc)
}
}
// ls again now that file is gone
reply = c.Request(vix.CommandListFiles, &vix.ListFilesRequest{
GuestPathName: name,
})
rc = vixRC(reply)
if rc != vix.FileNotFound {
t.Errorf("rc: %d", rc)
}
// ls
ls := &vix.ListFilesRequest{
GuestPathName: dir,
}
ls.Body.MaxResults = 5 // default is 50
for i := 0; i < 5; i++ {
reply = c.Request(vix.CommandListFiles, ls)
if Trace {
fmt.Fprintf(os.Stderr, "%s: %q\n", dir, string(reply[4:]))
}
var rem int
_, err := fmt.Fscanf(bytes.NewReader(reply[4:]), "<rem>%d</rem>", &rem)
if err != nil {
t.Fatal(err)
}
num := bytes.Count(reply, []byte("<fxi>"))
total += num
ls.Body.Offset += uint64(num)
if rem == 0 {
break
}
}
if total != max+1 {
t.Errorf("expected %d, got %d", max, total)
}
// Test invalid offset, making sure it doesn't cause panic (issue #934)
ls.Body.Offset += 10
_ = c.Request(vix.CommandListFiles, ls)
// mv $dir ${dir}-old
mv = &vix.RenameFileRequest{
OldPathName: dir,
NewPathName: dir + "-old",
}
for _, expect := range []int{vix.OK, vix.FileNotFound} {
reply = c.Request(vix.CommandMoveGuestDirectory, mv)
rc = vixRC(reply)
if rc != expect {
t.Errorf("rc: %d", rc)
}
if expect == vix.OK {
// test file type is properly checked
reply = c.Request(vix.CommandMoveGuestFileEx, &vix.RenameFileRequest{
OldPathName: mv.NewPathName,
NewPathName: dir,
})
rc = vixRC(reply)
if rc != vix.NotAFile {
t.Errorf("rc: %d", rc)
}
// test Overwrite flag is properly checked
reply = c.Request(vix.CommandMoveGuestDirectory, &vix.RenameFileRequest{
OldPathName: mv.NewPathName,
NewPathName: mv.NewPathName,
})
rc = vixRC(reply)
if rc != vix.FileAlreadyExists {
t.Errorf("rc: %d", rc)
}
}
}
rmdir := &vix.DirRequest{
GuestPathName: mv.NewPathName,
}
// rm -rm $dir
for _, rmr := range []bool{false, true} {
rmdir.Body.Recursive = rmr
reply = c.Request(vix.CommandDeleteGuestDirectoryEx, rmdir)
rc = vixRC(reply)
if rmr {
if rc != vix.OK {
t.Fatalf("rc: %d", rc)
}
} else {
if rc != vix.DirectoryNotEmpty {
t.Fatalf("rc: %d", rc)
}
}
}
}
func TestVixFileChangeAttributes(t *testing.T) {
if os.Getuid() == 0 {
t.Skip("running as root")
}
c := NewCommandClient()
f, err := ioutil.TempFile("", "toolbox-")
if err != nil {
t.Fatal(err)
}
_ = f.Close()
name := f.Name()
// touch,chown,chmod
chattr := &vix.SetGuestFileAttributesRequest{
GuestPathName: name,
}
h := &chattr.Body
tests := []struct {
expect int
f func()
}{
{
vix.OK, func() {},
},
{
vix.OK, func() {
h.FileOptions = vix.FileAttributeSetModifyDate
h.ModificationTime = time.Now().Unix()
},
},
{
vix.OK, func() {
h.FileOptions = vix.FileAttributeSetAccessDate
h.AccessTime = time.Now().Unix()
},
},
{
vix.FileAccessError, func() {
h.FileOptions = vix.FileAttributeSetUnixOwnerid
h.OwnerID = 0 // fails as we are not root
},
},
{
vix.FileAccessError, func() {
h.FileOptions = vix.FileAttributeSetUnixGroupid
h.GroupID = 0 // fails as we are not root
},
},
{
vix.OK, func() {
h.FileOptions = vix.FileAttributeSetUnixOwnerid
h.OwnerID = int32(os.Getuid())
},
},
{
vix.OK, func() {
h.FileOptions = vix.FileAttributeSetUnixGroupid
h.GroupID = int32(os.Getgid())
},
},
{
vix.OK, func() {
h.FileOptions = vix.FileAttributeSetUnixPermissions
h.Permissions = int32(os.FileMode(0755).Perm())
},
},
{
vix.FileNotFound, func() {
_ = os.Remove(name)
},
},
}
for i, test := range tests {
test.f()
reply := c.Request(vix.CommandSetGuestFileAttributes, chattr)
rc := vixRC(reply)
if rc != test.expect {
t.Errorf("%d: rc=%d", i, rc)
}
}
}