//===----------------------------------------------------------------------===// // 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 Foundation import Testing @testable import ContainerResource @testable import ContainerizationOS struct RegistryResourceTests { func createRegistryInfo( hostname: String = "docker.io", username: String = "testuser" ) -> RegistryInfo { RegistryInfo( hostname: hostname, username: username, modifiedDate: Date(timeIntervalSince1970: 1_700_000_000), createdDate: Date(timeIntervalSince1970: 1_690_000_000) ) } @Test("RegistryResource id and name are both hostname") func testRegistryResourceIdAndName() { let hostname = "ghcr.io" let registryInfo = createRegistryInfo(hostname: hostname, username: "myuser") let resource = RegistryResource(from: registryInfo) #expect(resource.id == hostname, "id should be the hostname") #expect(resource.name == hostname, "name should be the hostname") #expect(resource.id == resource.name, "id and name should be identical") } @Test("RegistryResource maps RegistryInfo correctly") func testRegistryResourceMapping() { let hostname = "registry.example.com:5000" let username = "developer" let registryInfo = createRegistryInfo(hostname: hostname, username: username) let resource = RegistryResource(from: registryInfo) #expect(resource.id == hostname) #expect(resource.name == hostname) #expect(resource.username == username) #expect(resource.creationDate == registryInfo.createdDate) #expect(resource.modificationDate == registryInfo.modifiedDate) #expect(resource.labels.isEmpty, "default labels should be empty") } @Test("RegistryResource implements ManagedResource") func testManagedResourceConformance() { let registryInfo = createRegistryInfo() let resource = RegistryResource(from: registryInfo) // Test that it conforms to ManagedResource protocol let managedResource: any ManagedResource = resource #expect(managedResource.id == "docker.io") #expect(managedResource.name == "docker.io") #expect(managedResource.creationDate == registryInfo.createdDate) #expect(managedResource.labels.isEmpty) } @Test("RegistryResource is Codable - JSON encoding") func testRegistryResourceJSONEncoding() throws { let hostname = "docker.io" let username = "testuser" let registryInfo = createRegistryInfo(hostname: hostname, username: username) let resource = RegistryResource(from: registryInfo) // Encode to JSON let encoder = JSONEncoder() encoder.outputFormatting = [.sortedKeys, .prettyPrinted] let jsonData = try encoder.encode(resource) let jsonString = String(data: jsonData, encoding: .utf8)! // Verify JSON contains expected fields #expect(jsonString.contains("\"id\""), "JSON should contain id field") #expect(jsonString.contains("\"name\""), "JSON should contain name field") #expect(jsonString.contains("\"username\""), "JSON should contain username field") #expect(jsonString.contains("\"creationDate\""), "JSON should contain creationDate field") #expect(jsonString.contains("\"modificationDate\""), "JSON should contain modificationDate field") #expect(jsonString.contains(hostname), "JSON should contain the hostname") #expect(jsonString.contains(username), "JSON should contain the username") } @Test("RegistryResource is Codable - round trip") func testRegistryResourceRoundTrip() throws { let hostname = "ghcr.io" let username = "developer" let registryInfo = createRegistryInfo(hostname: hostname, username: username) let original = RegistryResource(from: registryInfo) // Encode let encoder = JSONEncoder() let jsonData = try encoder.encode(original) // Decode let decoder = JSONDecoder() let decoded = try decoder.decode(RegistryResource.self, from: jsonData) // Verify #expect(decoded.id == original.id) #expect(decoded.name == original.name) #expect(decoded.username == original.username) #expect(decoded.creationDate.timeIntervalSince1970 == original.creationDate.timeIntervalSince1970) #expect(decoded.modificationDate.timeIntervalSince1970 == original.modificationDate.timeIntervalSince1970) #expect(decoded.labels == original.labels) } @Test("RegistryResource nameValid validates hostnames") func testRegistryResourceNameValidation() { // Valid hostnames #expect(RegistryResource.nameValid("docker.io"), "docker.io should be valid") #expect(RegistryResource.nameValid("ghcr.io"), "ghcr.io should be valid") #expect(RegistryResource.nameValid("registry.example.com"), "registry.example.com should be valid") #expect(RegistryResource.nameValid("localhost:5000"), "localhost:5000 should be valid") #expect(RegistryResource.nameValid("registry.k8s.io"), "registry.k8s.io should be valid") // Invalid hostnames #expect(!RegistryResource.nameValid(""), "empty string should be invalid") #expect(!RegistryResource.nameValid("-invalid.com"), "hostname starting with hyphen should be invalid") #expect(!RegistryResource.nameValid("invalid-.com"), "hostname ending with hyphen should be invalid") } @Test("RegistryResource can have labels") func testRegistryResourceWithLabels() throws { let hostname = "docker.io" let username = "testuser" let labels = [ "environment": "production", ResourceLabelKeys.role: "primary", ] let resource = RegistryResource( hostname: hostname, username: username, creationDate: Date(), modificationDate: Date(), labels: try .init(labels) ) #expect(resource.labels.count == 2) #expect(resource.labels["environment"] == "production") #expect(resource.labels[ResourceLabelKeys.role] == "primary") } @Test("RegistryResource handles hostname with port") func testRegistryResourceWithPort() { let hostname = "localhost:5000" let registryInfo = createRegistryInfo(hostname: hostname, username: "admin") let resource = RegistryResource(from: registryInfo) #expect(resource.id == hostname) #expect(resource.name == hostname) #expect(RegistryResource.nameValid(hostname)) } @Test("Multiple RegistryResources can be encoded as array") func testMultipleRegistryResourcesJSONEncoding() throws { let registries = [ RegistryResource(from: createRegistryInfo(hostname: "docker.io", username: "user1")), RegistryResource(from: createRegistryInfo(hostname: "ghcr.io", username: "user2")), RegistryResource(from: createRegistryInfo(hostname: "quay.io", username: "user3")), ] let encoder = JSONEncoder() encoder.outputFormatting = [.sortedKeys, .prettyPrinted] let jsonData = try encoder.encode(registries) let jsonString = String(data: jsonData, encoding: .utf8)! // Verify all hostnames are present #expect(jsonString.contains("docker.io")) #expect(jsonString.contains("ghcr.io")) #expect(jsonString.contains("quay.io")) // Verify all usernames are present #expect(jsonString.contains("user1")) #expect(jsonString.contains("user2")) #expect(jsonString.contains("user3")) // Print for manual verification print("Encoded JSON:") print(jsonString) } }