containerization: Add additional tests (#273)

Add additional tests, with varying levels of utility.

Before: Overall Code Coverage: 41.73%
After: Overall Code Coverage: 42.95%

Signed-off-by: Eric Ernst <eric_ernst@apple.com>
This commit is contained in:
Eric Ernst
2025-08-26 13:13:05 -07:00
committed by GitHub
parent 4099bdccd6
commit f92c0cd8c6
7 changed files with 325 additions and 0 deletions
@@ -0,0 +1,54 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the Containerization 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
@testable import Containerization
struct DNSTests {
@Test func dnsResolvConfWithAllFields() {
let dns = DNS(
nameservers: ["8.8.8.8", "1.1.1.1"],
domain: "example.com",
searchDomains: ["internal.com", "test.com"],
options: ["ndots:2", "timeout:1"]
)
let expected = "nameserver 8.8.8.8\nnameserver 1.1.1.1\ndomain example.com\nsearch internal.com test.com\nopts ndots:2 timeout:1\n"
#expect(dns.resolvConf == expected)
}
@Test func dnsResolvConfWithEmptyFields() {
let dns = DNS(
nameservers: [],
domain: nil,
searchDomains: [],
options: []
)
// Should return empty string when all fields are empty
#expect(dns.resolvConf == "")
}
@Test func dnsResolvConfWithOnlyNameservers() {
let dns = DNS(nameservers: ["8.8.8.8"])
let expected = "nameserver 8.8.8.8\n"
#expect(dns.resolvConf == expected)
}
}
@@ -0,0 +1,38 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the Containerization 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
@testable import Containerization
struct HashTests {
@Test func hashMountSourceWithValidString() throws {
let result = try hashMountSource(source: "/valid/path")
// Should produce a non-empty hash
#expect(!result.isEmpty)
// Same input should produce same hash (deterministic)
let result2 = try hashMountSource(source: "/valid/path")
#expect(result == result2)
// Different inputs should produce different hashes
let result3 = try hashMountSource(source: "/different/path")
#expect(result != result3)
}
}
@@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the Containerization 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
@testable import Containerization
struct HostsTests {
@Test func hostsEntryRenderedWithAllFields() {
let entry = Hosts.Entry(
ipAddress: "192.168.1.100",
hostnames: ["myserver", "server.local"],
comment: "My local server"
)
let expected = "192.168.1.100 myserver server.local # My local server "
#expect(entry.rendered == expected)
}
@Test func hostsEntryRenderedWithoutComment() {
let entry = Hosts.Entry(
ipAddress: "10.0.0.1",
hostnames: ["gateway"]
)
let expected = "10.0.0.1 gateway"
#expect(entry.rendered == expected)
}
@Test func hostsEntryRenderedWithEmptyHostnames() {
let entry = Hosts.Entry(
ipAddress: "172.16.0.1",
hostnames: [],
comment: "Empty hostnames"
)
let expected = "172.16.0.1 # Empty hostnames "
#expect(entry.rendered == expected)
}
@Test func hostsFileWithCommentAndEntries() {
let hosts = Hosts(
entries: [
Hosts.Entry(ipAddress: "127.0.0.1", hostnames: ["localhost"]),
Hosts.Entry(ipAddress: "192.168.1.10", hostnames: ["server"], comment: "Main server"),
],
comment: "Generated hosts file"
)
let expected = "# Generated hosts file\n127.0.0.1 localhost\n192.168.1.10 server # Main server \n"
#expect(hosts.hostsFile == expected)
}
}
@@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the Containerization 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 ContainerizationOCI
import Foundation
import Testing
@testable import Containerization
struct ImageTests {
@Test func imageDescriptionComputedProperties() {
let descriptor = Descriptor(
mediaType: "application/vnd.oci.image.manifest.v1+json",
digest: "sha256:abc123def456",
size: 1024
)
let description = Image.Description(reference: "myapp:latest", descriptor: descriptor)
#expect(description.digest == "sha256:abc123def456")
#expect(description.mediaType == "application/vnd.oci.image.manifest.v1+json")
#expect(description.reference == "myapp:latest")
}
}
@@ -39,4 +39,20 @@ final class KernelTests {
let cmdline = kernel.commandLine.kernelArgs.joined(separator: " ")
#expect(cmdline == expected)
}
@Test func kernelCommandLineInitWithDebugTrue() {
let commandLine = Kernel.CommandLine(debug: true, panic: 5, initArgs: ["--verbose"])
#expect(commandLine.kernelArgs == ["console=hvc0", "tsc=reliable", "debug", "panic=5"])
#expect(commandLine.initArgs == ["--verbose"])
}
@Test func kernelCommandLineMutatingMethods() {
var commandLine = Kernel.CommandLine(kernelArgs: ["console=hvc0"], initArgs: [])
commandLine.addDebug()
commandLine.addPanic(level: 10)
#expect(commandLine.kernelArgs == ["console=hvc0", "debug", "panic=10"])
}
}
@@ -0,0 +1,69 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the Containerization 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 ContainerizationOCI
import Foundation
import Testing
@testable import Containerization
struct LinuxContainerTests {
@Test func processInitFromImageConfigWithAllFields() {
let imageConfig = ImageConfig(
user: "appuser",
env: ["NODE_ENV=production", "PORT=3000"],
entrypoint: ["/usr/bin/node"],
cmd: ["app.js", "--verbose"],
workingDir: "/app"
)
let process = LinuxContainer.Configuration.Process(from: imageConfig)
#expect(process.workingDirectory == "/app")
#expect(process.environmentVariables == ["NODE_ENV=production", "PORT=3000"])
#expect(process.arguments == ["/usr/bin/node", "app.js", "--verbose"])
#expect(process.user.username == "appuser")
}
@Test func processInitFromImageConfigWithNilValues() {
let imageConfig = ImageConfig(
user: nil,
env: nil,
entrypoint: nil,
cmd: nil,
workingDir: nil
)
let process = LinuxContainer.Configuration.Process(from: imageConfig)
#expect(process.workingDirectory == "/")
#expect(process.environmentVariables == [])
#expect(process.arguments == [])
#expect(process.user.username == "") // Default User() has empty string username
}
@Test func processInitFromImageConfigEntrypointAndCmdConcatenation() {
let imageConfig = ImageConfig(
entrypoint: ["/bin/sh", "-c"],
cmd: ["echo 'hello'", "&&", "sleep 10"]
)
let process = LinuxContainer.Configuration.Process(from: imageConfig)
#expect(process.arguments == ["/bin/sh", "-c", "echo 'hello'", "&&", "sleep 10"])
}
}
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the Containerization 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
@testable import Containerization
struct MountTests {
@Test func mountShareCreatesVirtiofsMount() {
let mount = Mount.share(
source: "/host/shared",
destination: "/guest/shared",
options: ["rw", "noatime"],
runtimeOptions: ["tag=shared"]
)
#expect(mount.type == "virtiofs")
#expect(mount.source == "/host/shared")
#expect(mount.destination == "/guest/shared")
#expect(mount.options == ["rw", "noatime"])
if case .virtiofs(let opts) = mount.runtimeOptions {
#expect(opts == ["tag=shared"])
} else {
#expect(Bool(false), "Expected virtiofs runtime options")
}
}
}