chore: import upstream snapshot with attribution
container project - merge build / Invoke build (push) Successful in 1s
container project - merge build / Invoke build (push) Successful in 1s
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Copyright © 2026 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 Testing
|
||||
|
||||
@Suite
|
||||
struct TestCLIExecCommand {
|
||||
@Test func testCreateExecCommand() async throws {
|
||||
try await ContainerFixture.with { f in
|
||||
let image = try f.copyWarmupImage(ContainerFixture.warmupImages[0])
|
||||
let name = "\(f.testID)-c"
|
||||
try f.doCreate(name: name, image: image)
|
||||
f.addCleanup { try? f.doStop(name) }
|
||||
try f.doStart(name)
|
||||
try await f.waitForContainerRunning(name)
|
||||
let uname = try f.doExec(name, cmd: ["uname"])
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
#expect(uname == "Linux", "expected OS to be Linux, got \(uname)")
|
||||
try f.doStop(name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testExecDetach() async throws {
|
||||
try await ContainerFixture.with { f in
|
||||
let image = try f.copyWarmupImage(ContainerFixture.warmupImages[0])
|
||||
let name = "\(f.testID)-c"
|
||||
try f.doCreate(name: name, image: image)
|
||||
f.addCleanup { try? f.doStop(name) }
|
||||
try f.doStart(name)
|
||||
try await f.waitForContainerRunning(name)
|
||||
|
||||
let output = try f.doExec(name, cmd: ["sh", "-c", "touch /tmp/detach_test_marker"], detach: true)
|
||||
try #require(
|
||||
output.trimmingCharacters(in: .whitespacesAndNewlines) == name,
|
||||
"exec --detach should print the container name")
|
||||
|
||||
let ls = try f.doExec(name, cmd: ["ls", "/"])
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
try #require(ls.contains("tmp"), "container should still be running after detached exec")
|
||||
|
||||
// Retry until the detached process creates the marker file.
|
||||
var markerFound = false
|
||||
for _ in 0..<3 {
|
||||
let result = try f.run(["exec", name, "test", "-f", "/tmp/detach_test_marker"])
|
||||
if result.status == 0 {
|
||||
markerFound = true
|
||||
break
|
||||
}
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
}
|
||||
try #require(markerFound, "marker file should be created by detached process within 3 seconds")
|
||||
|
||||
try f.doStop(name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testExecDetachProcessRunning() async throws {
|
||||
try await ContainerFixture.with { f in
|
||||
let image = try f.copyWarmupImage(ContainerFixture.warmupImages[0])
|
||||
let name = "\(f.testID)-c"
|
||||
try f.doCreate(name: name, image: image)
|
||||
f.addCleanup { try? f.doStop(name) }
|
||||
try f.doStart(name)
|
||||
try await f.waitForContainerRunning(name)
|
||||
|
||||
let output = try f.doExec(name, cmd: ["sleep", "10"], detach: true)
|
||||
try #require(
|
||||
output.trimmingCharacters(in: .whitespacesAndNewlines) == name,
|
||||
"exec --detach should print the container name")
|
||||
|
||||
let ps = try f.doExec(name, cmd: ["ps", "aux"])
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
try #require(ps.contains("sleep 10"), "detached 'sleep 10' should appear in ps output")
|
||||
|
||||
try f.doStop(name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test func testExecOnExitingContainer() async throws {
|
||||
try await ContainerFixture.with { f in
|
||||
let image = try f.copyWarmupImage(ContainerFixture.warmupImages[0])
|
||||
let name = "\(f.testID)-c"
|
||||
// sh exits immediately in detached mode with no stdin; container stops on its own.
|
||||
try f.doLongRun(name: name, image: image, containerArgs: ["sh"], autoRemove: false)
|
||||
f.addCleanup { try? f.doRemove(name) }
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
try f.doStart(name)
|
||||
let execResult = try f.run(["exec", name, "sleep", "infinity"])
|
||||
if execResult.status != 0 {
|
||||
#expect(
|
||||
execResult.error.contains("is not running")
|
||||
|| execResult.error.contains("failed to create process"),
|
||||
"expected 'not running' error, got: \(execResult.error)")
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
// Container should still exist even if exec failed.
|
||||
_ = try f.getContainerStatus(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user