Files
container/Tests/CLITests/Subcommands/Containers/TestCLIExec.swift
T
Saehej KangandJ Logan e49a563912 [tests]: refactor run function for stdin/stdout support (#830)
When working on test cases for #827 and #734 the following issues
occurred
  1. There was no support to pass in `Data` for `stdin` (input pipe added
    + new argument for the data)
  2. Pipes were getting blocked during the `try process.run()` and
    `process.waitUntilExit()` (order of operations were fixed)
  3. We need the binary data for directly piping the `stdout` data to
    `stdin`, and converting the data to a `string`, returns `""` (added a
    new value to the tuple)

I opened a new PR here for this as I did not want to bloat the other PRs
with so many updates. At first I thought of creating a new function
named `runStdinStdout`, but that seemed redundant as it pretty much was
going to do the same thing as `run`.

## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs

---------

Co-authored-by: J Logan <john_logan@apple.com>
2025-11-14 21:01:31 -03:00

111 lines
4.4 KiB
Swift

//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the container project authors.
//
// 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
//
// https://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.
//===----------------------------------------------------------------------===//
import Foundation
import Testing
class TestCLIExecCommand: CLITest {
private func getTestName() -> String {
Test.current!.name.trimmingCharacters(in: ["(", ")"]).lowercased()
}
@Test func testCreateExecCommand() throws {
do {
let name = getTestName()
try doCreate(name: name)
defer {
try? doStop(name: name)
}
try doStart(name: name)
var unameActual = try doExec(name: name, cmd: ["uname"])
unameActual = unameActual.trimmingCharacters(in: .whitespacesAndNewlines)
#expect(unameActual == "Linux", "expected OS to be Linux, instead got \(unameActual)")
try doStop(name: name)
} catch {
Issue.record("failed to exec in container \(error)")
return
}
}
@Test func testExecDetach() throws {
do {
let name = getTestName()
try doCreate(name: name)
defer {
try? doStop(name: name)
}
try doStart(name: name)
// Run a long-running process in detached mode
let output = try doExec(name: name, cmd: ["sh", "-c", "touch /tmp/detach_test_marker"], detach: true)
let containerIdOutput = output.trimmingCharacters(in: .whitespacesAndNewlines)
try #require(containerIdOutput == name, "exec --detach should print the container ID")
// Verify the detached process is running by checking if we can still exec commands
var lsActual = try doExec(name: name, cmd: ["ls", "/"])
lsActual = lsActual.trimmingCharacters(in: .whitespacesAndNewlines)
try #require(lsActual.contains("tmp"), "container should still be running and accepting exec commands")
// Retry loop to check if the marker file was created by the detached process
var markerFound = false
for _ in 0..<3 {
let (_, _, _, status) = try run(arguments: [
"exec",
name,
"test", "-f", "/tmp/detach_test_marker",
])
if status == 0 {
markerFound = true
break
}
sleep(1)
}
try #require(markerFound, "marker file should be created by detached process within 3 seconds")
try doStop(name: name)
} catch {
Issue.record("failed to exec with detach in container \(error)")
return
}
}
@Test func testExecDetachProcessRunning() throws {
do {
let name = getTestName()
try doCreate(name: name)
defer {
try? doStop(name: name)
}
try doStart(name: name)
// Run a long-running process in detached mode
let output = try doExec(name: name, cmd: ["sleep", "10"], detach: true)
let containerIdOutput = output.trimmingCharacters(in: .whitespacesAndNewlines)
try #require(containerIdOutput == name, "exec --detach should print the container ID")
// Immediately check if the process is running using ps
var psOutput = try doExec(name: name, cmd: ["ps", "aux"])
psOutput = psOutput.trimmingCharacters(in: .whitespacesAndNewlines)
try #require(psOutput.contains("sleep 10"), "detached process 'sleep 10' should be visible in ps output")
try doStop(name: name)
} catch {
Issue.record("failed to verify detached process is running \(error)")
return
}
}
}