blob: fb0691fe35abcbbd4d15bec6832b41476c6a07be [file] [edit]
// Copyright 2026 Google 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 packages
import (
"os"
"os/exec"
"testing"
"github.com/GoogleCloudPlatform/osconfig/util/utiltest"
"golang.org/x/sys/unix"
)
// CheckPtmxAvailability skips the test if /dev/ptmx is not available
func CheckPtmxAvailability(t *testing.T) {
if _, err := os.Stat("/dev/ptmx"); os.IsNotExist(err) {
t.Skip("/dev/ptmx not found, skipping PTY tests")
}
}
// TestIoctlError ensures that the ioctl function correctly handles and returns errors
func TestIoctlError(t *testing.T) {
// Use an invalid file descriptor to trigger an error in ioctl
err := ioctl(^uintptr(0), unix.TIOCSPTLCK, 0)
if err == nil {
t.Error("ioctl() expected error with invalid fd, got nil")
}
}
// TestRunWithPty tests the runWithPty function with various cases:
// successful command execution, commands returning non-zero exit codes, handling execution errors like missing binaries
func TestRunWithPty(t *testing.T) {
CheckPtmxAvailability(t)
tests := []struct {
name string
cmd *exec.Cmd
wantOut string
wantStderr string
wantErr error
}{
{
name: "command with exit code 0 returns nil",
cmd: exec.Command("echo"),
wantOut: "",
wantErr: nil,
},
{
name: "command with exit code 1 returns output",
cmd: exec.Command("sh", "-c", "echo 'updates found'; exit 1"),
wantOut: "updates found\r\n",
wantErr: nil,
},
{
name: "command with stderr and exit code 1",
cmd: exec.Command("sh", "-c", "echo 'stdout message'; echo 'stderr message' >&2; exit 1"),
wantOut: "stdout message\r\n",
wantStderr: "stderr message\n",
wantErr: nil,
},
{
name: "command with multiple lines of output",
cmd: exec.Command("sh", "-c", "printf 'line1\nline2\nline3\n'; exit 1"),
wantOut: "line1\r\nline2\r\nline3\r\n",
wantErr: nil,
},
{
name: "non existent command returns error",
cmd: exec.Command("this-command-does-not-exist"),
wantOut: "",
wantErr: &exec.Error{Name: "this-command-does-not-exist", Err: exec.ErrNotFound},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
stdout, stderr, err := runWithPty(tt.cmd)
utiltest.AssertErrorMatch(t, err, tt.wantErr)
utiltest.AssertEquals(t, string(stdout), tt.wantOut)
utiltest.AssertEquals(t, string(stderr), tt.wantStderr)
})
}
}