[build]: add tests for copy from (#1380)

## Type of Change
- [x] Bug fix
- [ ] New feature  
- [ ] Breaking change
- [ ] Documentation update

## Motivation and Context

Relates to #1240

Test cases added for validation based on changes from
apple/container-builder-shim#73.

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

---------

Co-authored-by: jwhur <57657645+JaewonHur@users.noreply.github.com>
This commit is contained in:
Saehej Kang
2026-04-21 14:30:04 -07:00
committed by GitHub
co-authored by jwhur
parent 7e8c2fe894
commit 049570052c
@@ -1407,5 +1407,149 @@ extension TestCLIBuildBase {
)
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
}
@Test func testCopyFromLocalImage() throws {
let baseTempDir: URL = try createTempDir()
let tempDir: URL = try createTempDir()
defer {
try! FileManager.default.removeItem(at: baseTempDir)
try! FileManager.default.removeItem(at: tempDir)
}
let baseImageName = "local-base:\(UUID().uuidString)"
let baseDockerfile =
"""
FROM scratch
ADD hello.txt /hello.txt
"""
let baseContext: [FileSystemEntry] = [
.file("hello.txt", content: .data("hello\n".data(using: .utf8)!))
]
try createContext(tempDir: baseTempDir, dockerfile: baseDockerfile, context: baseContext)
try self.build(tag: baseImageName, tempDir: baseTempDir)
#expect(try self.inspectImage(baseImageName) == baseImageName, "expected to have successfully built \(baseImageName)")
let dockerfile =
"""
FROM ghcr.io/linuxcontainers/alpine:3.20
COPY --from=\(baseImageName) /hello.txt /copied.txt
RUN cat /copied.txt
"""
try createContext(tempDir: tempDir, dockerfile: dockerfile)
let imageName = "registry.local/copy-from-local:\(UUID().uuidString)"
try self.build(tag: imageName, tempDir: tempDir)
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
}
@Test func testCopyFromBuildStage() throws {
let tempDir: URL = try createTempDir()
defer {
try! FileManager.default.removeItem(at: tempDir)
}
let dockerfile =
"""
FROM scratch AS builder
ADD hello.txt /hello.txt
FROM ghcr.io/linuxcontainers/alpine:3.20
COPY --from=builder /hello.txt /copied.txt
RUN cat /copied.txt
"""
let context: [FileSystemEntry] = [
.file("hello.txt", content: .data("hello\n".data(using: .utf8)!))
]
try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context)
let imageName = "registry.local/copy-from-stage:\(UUID().uuidString)"
try self.build(tag: imageName, tempDir: tempDir)
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
}
@Test func testCopyRenameFromStage() throws {
let tempDir: URL = try createTempDir()
defer {
try! FileManager.default.removeItem(at: tempDir)
}
let dockerfile =
"""
FROM scratch AS builder
ADD hello.txt /hello.txt
FROM ghcr.io/linuxcontainers/alpine:3.20
COPY --from=builder /hello.txt /renamed.txt
RUN cat /renamed.txt
"""
let context: [FileSystemEntry] = [
.file("hello.txt", content: .data("hello\n".data(using: .utf8)!))
]
try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context)
let imageName = "registry.local/copy-rename:\(UUID().uuidString)"
try self.build(tag: imageName, tempDir: tempDir)
#expect(try self.inspectImage(imageName) == imageName, "expected to have successfully built \(imageName)")
}
@Test func testCopyMissingFileFails() throws {
let tempDir: URL = try createTempDir()
defer {
try! FileManager.default.removeItem(at: tempDir)
}
let dockerfile =
"""
FROM scratch AS builder
FROM ghcr.io/linuxcontainers/alpine:3.20
COPY --from=builder /does-not-exist.txt /copied.txt
"""
try createContext(tempDir: tempDir, dockerfile: dockerfile)
let imageName = "registry.local/copy-missing:\(UUID().uuidString)"
#expect(throws: Error.self) {
try self.build(tag: imageName, tempDir: tempDir)
}
}
}
@Test func testCopyInvalidStageFails() throws {
let tempDir: URL = try createTempDir()
defer {
try! FileManager.default.removeItem(at: tempDir)
}
let dockerfile =
"""
FROM ghcr.io/linuxcontainers/alpine:3.20
COPY --from=not_a_stage /hello.txt /copied.txt
"""
try createContext(tempDir: tempDir, dockerfile: dockerfile)
let imageName = "registry.local/copy-invalid-stage:\(UUID().uuidString)"
#expect(throws: Error.self) {
try self.build(tag: imageName, tempDir: tempDir)
}
}
@Test func testCopyFromNonexistentImageFails() throws {
let tempDir: URL = try createTempDir()
defer {
try! FileManager.default.removeItem(at: tempDir)
}
let dockerfile =
"""
FROM ghcr.io/linuxcontainers/alpine:3.20
COPY --from=doesnotexist:latest /hello.txt /copied.txt
"""
try createContext(tempDir: tempDir, dockerfile: dockerfile)
let imageName = "registry.local/copy-bad-image:\(UUID().uuidString)"
#expect(throws: Error.self) {
try self.build(tag: imageName, tempDir: tempDir)
}
}
}