//===----------------------------------------------------------------------===// // Copyright © 2025 Apple Inc. and the container project authors. 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 // // 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 extension TestCLIBuildBase { class CLIBuilderTarExportTest: TestCLIBuildBase { override init() throws { try super.init() } deinit { try? builderDelete(force: true) } @Test func testBuildExportTar() throws { let tempDir: URL = try createTempDir() let dockerfile: String = """ FROM scratch ADD emptyFile / """ let context: [FileSystemEntry] = [ .file("emptyFile", content: .zeroFilled(size: 1)) ] try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context) let exportPath = tempDir.appendingPathComponent("export.tar") let response = try run(arguments: [ "build", "-f", tempDir.appendingPathComponent("Dockerfile").path, "-o", "type=tar,dest=\(exportPath.path)", tempDir.appendingPathComponent("context").path, ]) #expect(response.status == 0, "build with tar export should succeed") #expect(FileManager.default.fileExists(atPath: exportPath.path), "tar file should exist at \(exportPath.path)") #expect(response.output.contains("Successfully exported to \(exportPath.path)"), "should show export success message") let attributes = try FileManager.default.attributesOfItem(atPath: exportPath.path) let fileSize = attributes[.size] as? Int ?? 0 #expect(fileSize > 0, "exported tar file should not be empty") } @Test func testBuildExportTarToDirectory() throws { let tempDir: URL = try createTempDir() let dockerfile: String = """ FROM ghcr.io/linuxcontainers/alpine:3.20 RUN echo "test content" > /test.txt """ try createContext(tempDir: tempDir, dockerfile: dockerfile) let exportDir = tempDir.appendingPathComponent("exports") try FileManager.default.createDirectory(at: exportDir, withIntermediateDirectories: true) let response = try run(arguments: [ "build", "-f", tempDir.appendingPathComponent("Dockerfile").path, "-o", "type=tar,dest=\(exportDir.path)", tempDir.appendingPathComponent("context").path, ]) #expect(response.status == 0, "build with tar export to directory should succeed") let expectedTar = exportDir.appendingPathComponent("out.tar") #expect(FileManager.default.fileExists(atPath: expectedTar.path), "tar file should exist at \(expectedTar.path)") #expect(response.output.contains("Successfully exported to \(expectedTar.path)"), "should show export success message") } @Test func testBuildExportTarMultipleRuns() throws { let tempDir: URL = try createTempDir() let dockerfile: String = """ FROM scratch ADD testFile / """ let context: [FileSystemEntry] = [ .file("testFile", content: .data("test data".data(using: .utf8)!)) ] try createContext(tempDir: tempDir, dockerfile: dockerfile, context: context) let exportDir = tempDir.appendingPathComponent("exports") try FileManager.default.createDirectory(at: exportDir, withIntermediateDirectories: true) // First build var response = try run(arguments: [ "build", "-f", tempDir.appendingPathComponent("Dockerfile").path, "-o", "type=tar,dest=\(exportDir.path)", tempDir.appendingPathComponent("context").path, ]) #expect(response.status == 0, "first build should succeed") let firstTar = exportDir.appendingPathComponent("out.tar") #expect(FileManager.default.fileExists(atPath: firstTar.path), "first tar should exist") // Second build - should create out.tar.1 response = try run(arguments: [ "build", "-f", tempDir.appendingPathComponent("Dockerfile").path, "-o", "type=tar,dest=\(exportDir.path)", tempDir.appendingPathComponent("context").path, ]) #expect(response.status == 0, "second build should succeed") let secondTar = exportDir.appendingPathComponent("out.tar.1") #expect(FileManager.default.fileExists(atPath: secondTar.path), "second tar should exist at out.tar.1") } @Test func testBuildExportTarInvalidDest() throws { let tempDir: URL = try createTempDir() let dockerfile: String = """ FROM scratch """ try createContext(tempDir: tempDir, dockerfile: dockerfile) let response = try run(arguments: [ "build", "-f", tempDir.appendingPathComponent("Dockerfile").path, "-o", "type=tar", // Missing dest parameter tempDir.appendingPathComponent("context").path, ]) #expect(response.status != 0, "build without dest should fail") #expect(response.error.contains("dest field is required"), "error should mention missing dest") } } }