Files
container/Tests/ContainerClientTests/UtilityTests.swift
T
Amir AlperinandGitHub df368b790e Fix port validation to allow same port for different protocols (#992) (#1000)
- Fixes: #992 
- Port validation previously rejected valid configurations
  when the same port number was used for different
  protocols (TCP and UDP). For example:
 `-p 1024:1024/udp -p 1024:1024/tcp`
  Although this is a valid and common use case, the
  validation logic treated it as a conflict.

To fix this, I updated the validation key to include the protocol name.
The validation now checks for overlapping port numbers only within the
same protocol, rather than across all protocols.

This change enables binding the same port number for both TCP and UDP,
aligning the validation behavior with real-world networking
requirements.

## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs
2026-01-04 10:49:22 -08:00

134 lines
4.3 KiB
Swift

//===----------------------------------------------------------------------===//
// Copyright © 2025-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 ContainerizationError
import Foundation
import Testing
@testable import ContainerClient
struct UtilityTests {
@Test("Parse simple key-value pairs")
func testSimpleKeyValuePairs() {
let result = Utility.parseKeyValuePairs(["key1=value1", "key2=value2"])
#expect(result["key1"] == "value1")
#expect(result["key2"] == "value2")
}
@Test("Parse standalone keys")
func testStandaloneKeys() {
let result = Utility.parseKeyValuePairs(["standalone"])
#expect(result["standalone"] == "")
}
@Test("Parse empty input")
func testEmptyInput() {
let result = Utility.parseKeyValuePairs([])
#expect(result.isEmpty)
}
@Test("Parse mixed format")
func testMixedFormat() {
let result = Utility.parseKeyValuePairs(["key1=value1", "standalone", "key2=value2"])
#expect(result["key1"] == "value1")
#expect(result["standalone"] == "")
#expect(result["key2"] == "value2")
}
@Test("Valid MAC address with colons")
func testValidMACAddressWithColons() throws {
try Utility.validMACAddress("02:42:ac:11:00:02")
try Utility.validMACAddress("AA:BB:CC:DD:EE:FF")
try Utility.validMACAddress("00:00:00:00:00:00")
try Utility.validMACAddress("ff:ff:ff:ff:ff:ff")
}
@Test("Valid MAC address with hyphens")
func testValidMACAddressWithHyphens() throws {
try Utility.validMACAddress("02-42-ac-11-00-02")
try Utility.validMACAddress("AA-BB-CC-DD-EE-FF")
}
@Test("Invalid MAC address format")
func testInvalidMACAddressFormat() {
#expect(throws: Error.self) {
try Utility.validMACAddress("invalid")
}
#expect(throws: Error.self) {
try Utility.validMACAddress("02:42:ac:11:00") // Too short
}
#expect(throws: Error.self) {
try Utility.validMACAddress("02:42:ac:11:00:02:03") // Too long
}
#expect(throws: Error.self) {
try Utility.validMACAddress("ZZ:ZZ:ZZ:ZZ:ZZ:ZZ") // Invalid hex
}
#expect(throws: Error.self) {
try Utility.validMACAddress("02:42:ac:11:00:") // Incomplete
}
#expect(throws: Error.self) {
try Utility.validMACAddress("02.42.ac.11.00.02") // Wrong separator
}
}
@Test
func testPublishPortsNonOverlapping() throws {
let result = try Parser.publishPorts([
"8080-8179:9000-9099/tcp",
"8180-8279:9100-9199/tcp",
])
#expect(result.count == 2)
try Utility.validPublishPorts(result)
}
@Test
func testPublishPortsOverlapping() throws {
let result = try Parser.publishPorts([
"9000-9100:8080-8180/tcp",
"9100-9199:8180-8279/tcp",
])
#expect(result.count == 2)
#expect {
try Utility.validPublishPorts(result)
} throws: { error in
guard let error = error as? ContainerizationError else {
return false
}
return error.description.contains("port specs may not overlap")
}
}
@Test
func testPublishPortsSamePortDifferentProtocols() throws {
let result = try Parser.publishPorts([
"8080:8080/tcp",
"8080:8080/udp",
"1024-2048:1024-2048/tcp",
"1024-2048:1024-2048/udp",
"8081:8081",
"8081:8081/udp",
])
#expect(result.count == 6)
try Utility.validPublishPorts(result)
}
}