Nucleic: Gitea Runner macOS VM Support
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
|
||||
@testable import RunnerCore
|
||||
|
||||
/// Tests for parsing `/var/db/dhcpd_leases`, including the `1,` hardware-type
|
||||
/// prefix, non-zero-padded octets, and newest-lease-wins on duplicate MACs.
|
||||
@Suite("DHCP leases")
|
||||
struct DHCPLeasesTests {
|
||||
/// A file shaped like the real thing: a `1,` prefix on every `hw_address`,
|
||||
/// octets that lack zero padding, one block that is missing its MAC, a
|
||||
/// decimal `lease=` alongside the usual hex ones, a MAC that appears three
|
||||
/// times with different expiries, and a truncated trailing block of the kind
|
||||
/// a mid-write read produces.
|
||||
static let fixture = """
|
||||
{
|
||||
\tname=macos-vm-a
|
||||
\tip_address=192.168.64.2
|
||||
\thw_address=1,aa:bb:c:d:ee:ff
|
||||
\tidentifier=1,aa:bb:c:d:ee:ff
|
||||
\tlease=0x66b2c0de
|
||||
}
|
||||
{
|
||||
\tname=macos-vm-b
|
||||
\tip_address=192.168.64.3
|
||||
\thw_address=1,DE:AD:BE:EF:00:01
|
||||
\tidentifier=1,de:ad:be:ef:00:01
|
||||
\tlease=1723000000
|
||||
}
|
||||
{
|
||||
\tname=no-hardware-address
|
||||
\tip_address=192.168.64.4
|
||||
\tlease=0x66b2c0de
|
||||
}
|
||||
{
|
||||
\tname=macos-vm-a
|
||||
\tip_address=192.168.64.9
|
||||
\thw_address=1,aa:bb:0c:0d:ee:ff
|
||||
\tlease=0x66b2ffff
|
||||
}
|
||||
{
|
||||
\tname=macos-vm-a
|
||||
\tip_address=192.168.64.5
|
||||
\thw_address=1,aa:bb:0c:0d:ee:ff
|
||||
\tlease=0x66b20000
|
||||
}
|
||||
{
|
||||
\tname=truncated-mid-write
|
||||
\tip_address=192.168.64.6
|
||||
"""
|
||||
|
||||
@Test("a lease carries the fields it was constructed with")
|
||||
func leaseIsConstructible() {
|
||||
let lease = DHCPLease(
|
||||
name: "guest",
|
||||
ipAddress: "192.168.64.7",
|
||||
hwAddress: "aa:bb:0c:dd:ee:ff",
|
||||
leaseExpiry: nil
|
||||
)
|
||||
#expect(lease.ipAddress == "192.168.64.7")
|
||||
}
|
||||
|
||||
@Test("well-formed blocks parse and malformed ones are skipped")
|
||||
func parsesWellFormedBlocksOnly() {
|
||||
let leases = DHCPLeaseParser.parse(Self.fixture)
|
||||
|
||||
// Six blocks in the fixture: one has no hw_address and one is truncated.
|
||||
#expect(leases.count == 4)
|
||||
#expect(leases.map(\.ipAddress) == ["192.168.64.2", "192.168.64.3", "192.168.64.9", "192.168.64.5"])
|
||||
#expect(!leases.contains { $0.ipAddress == "192.168.64.4" })
|
||||
#expect(!leases.contains { $0.ipAddress == "192.168.64.6" })
|
||||
#expect(leases[0].name == "macos-vm-a")
|
||||
}
|
||||
|
||||
@Test("the 1, prefix is stripped and octets are zero-padded")
|
||||
func normalizesHardwareAddresses() {
|
||||
let leases = DHCPLeaseParser.parse(Self.fixture)
|
||||
#expect(leases[0].hwAddress == "aa:bb:0c:0d:ee:ff")
|
||||
#expect(leases[1].hwAddress == "de:ad:be:ef:00:01")
|
||||
}
|
||||
|
||||
@Test("lease expiry parses from hex and from decimal")
|
||||
func parsesHexAndDecimalLeaseTimes() {
|
||||
let leases = DHCPLeaseParser.parse(Self.fixture)
|
||||
#expect(leases[0].leaseExpiry == Date(timeIntervalSince1970: TimeInterval(0x66b2_c0de)))
|
||||
#expect(leases[1].leaseExpiry == Date(timeIntervalSince1970: 1_723_000_000))
|
||||
}
|
||||
|
||||
@Test("a duplicate MAC resolves to the newest lease, whatever the file order")
|
||||
func newestLeaseWinsForDuplicateMACs() {
|
||||
let leases = DHCPLeaseParser.parse(Self.fixture)
|
||||
// Three blocks share this MAC: 0x66b2c0de, 0x66b2ffff, then 0x66b20000.
|
||||
// The newest expiry wins even though it is not the last block.
|
||||
#expect(DHCPLeaseParser.ipAddress(forMAC: "aa:bb:0c:0d:ee:ff", in: leases) == "192.168.64.9")
|
||||
}
|
||||
|
||||
@Test("the query MAC is normalized the same way as the file's")
|
||||
func lookupNormalizesTheQuery() {
|
||||
let leases = DHCPLeaseParser.parse(Self.fixture)
|
||||
// Every rendering of the same address must find the same lease.
|
||||
for query in ["aa:bb:c:d:ee:ff", "AA:BB:0C:0D:EE:FF", "aa-bb-0c-0d-ee-ff", "1,aa:bb:c:d:ee:ff"] {
|
||||
#expect(DHCPLeaseParser.ipAddress(forMAC: query, in: leases) == "192.168.64.9")
|
||||
}
|
||||
#expect(DHCPLeaseParser.ipAddress(forMAC: "de:ad:be:ef:00:01", in: leases) == "192.168.64.3")
|
||||
}
|
||||
|
||||
@Test("an unknown or unparseable MAC has no address")
|
||||
func unknownMACHasNoAddress() {
|
||||
let leases = DHCPLeaseParser.parse(Self.fixture)
|
||||
#expect(DHCPLeaseParser.ipAddress(forMAC: "00:11:22:33:44:55", in: leases) == nil)
|
||||
#expect(DHCPLeaseParser.ipAddress(forMAC: "not-a-mac", in: leases) == nil)
|
||||
}
|
||||
|
||||
@Test("a lease is only newer when bootpd actually rewrote it")
|
||||
func leaseFreshnessGate() {
|
||||
// Slot MACs are persistent and leases live 24 h, so the previous guest's
|
||||
// entry is normally still there when the next clone boots. Only a later
|
||||
// expiry (or a different address) proves the new guest has leased.
|
||||
let previous = DHCPLease(
|
||||
name: nil,
|
||||
ipAddress: "192.168.64.7",
|
||||
hwAddress: "aa:bb:0c:dd:ee:ff",
|
||||
leaseExpiry: Date(timeIntervalSince1970: 1_000)
|
||||
)
|
||||
let same = previous
|
||||
let renewed = DHCPLease(
|
||||
name: nil,
|
||||
ipAddress: "192.168.64.7",
|
||||
hwAddress: "aa:bb:0c:dd:ee:ff",
|
||||
leaseExpiry: Date(timeIntervalSince1970: 2_000)
|
||||
)
|
||||
let reassigned = DHCPLease(
|
||||
name: nil,
|
||||
ipAddress: "192.168.64.9",
|
||||
hwAddress: "aa:bb:0c:dd:ee:ff",
|
||||
leaseExpiry: Date(timeIntervalSince1970: 1_000)
|
||||
)
|
||||
|
||||
#expect(!DHCPLeaseParser.isNewer(same, than: previous))
|
||||
#expect(DHCPLeaseParser.isNewer(renewed, than: previous))
|
||||
#expect(DHCPLeaseParser.isNewer(reassigned, than: previous))
|
||||
// First boot on this MAC: there is nothing to be stale against.
|
||||
#expect(DHCPLeaseParser.isNewer(same, than: nil))
|
||||
}
|
||||
|
||||
@Test("lease(forMAC:) returns the same record the address lookup uses")
|
||||
func leaseLookupAgreesWithAddressLookup() {
|
||||
let leases = DHCPLeaseParser.parse(Self.fixture)
|
||||
let lease = DHCPLeaseParser.lease(forMAC: "aa:bb:0c:0d:ee:ff", in: leases)
|
||||
#expect(lease?.ipAddress == "192.168.64.9")
|
||||
#expect(lease?.ipAddress == DHCPLeaseParser.ipAddress(forMAC: "aa:bb:0c:0d:ee:ff", in: leases))
|
||||
#expect(DHCPLeaseParser.lease(forMAC: "00:11:22:33:44:55", in: leases) == nil)
|
||||
}
|
||||
|
||||
@Test("normalizeMAC accepts the renderings bootpd and VZMACAddress produce")
|
||||
func normalizeMACAcceptsCommonForms() {
|
||||
#expect(DHCPLeaseParser.normalizeMAC("1,aa:bb:c:dd:ee:ff") == "aa:bb:0c:dd:ee:ff")
|
||||
#expect(DHCPLeaseParser.normalizeMAC("aa:bb:0c:dd:ee:ff") == "aa:bb:0c:dd:ee:ff")
|
||||
#expect(DHCPLeaseParser.normalizeMAC("AA-BB-0C-DD-EE-FF") == "aa:bb:0c:dd:ee:ff")
|
||||
#expect(DHCPLeaseParser.normalizeMAC(" 1,0:0:0:0:0:1 ") == "00:00:00:00:00:01")
|
||||
}
|
||||
|
||||
@Test("normalizeMAC rejects anything that is not six hex octets")
|
||||
func normalizeMACRejectsGarbage() {
|
||||
#expect(DHCPLeaseParser.normalizeMAC("") == nil)
|
||||
#expect(DHCPLeaseParser.normalizeMAC("aa:bb:cc:dd:ee") == nil)
|
||||
#expect(DHCPLeaseParser.normalizeMAC("aa:bb:cc:dd:ee:ff:00") == nil)
|
||||
#expect(DHCPLeaseParser.normalizeMAC("aa:bb:cc:dd:ee:gg") == nil)
|
||||
#expect(DHCPLeaseParser.normalizeMAC("aa:bb:cc:dd:ee:fff") == nil)
|
||||
#expect(DHCPLeaseParser.normalizeMAC("192.168.64.2") == nil)
|
||||
}
|
||||
|
||||
@Test("parsing never throws on hostile input")
|
||||
func parsingIsTotal() {
|
||||
#expect(DHCPLeaseParser.parse("").isEmpty)
|
||||
#expect(DHCPLeaseParser.parse("}}}{{{\n=\nname=\n").isEmpty)
|
||||
#expect(DHCPLeaseParser.parse("{\nip_address=1.2.3.4\n").isEmpty)
|
||||
// A block interrupted by the start of the next one is dropped, not merged.
|
||||
let interrupted = """
|
||||
{
|
||||
ip_address=192.168.64.20
|
||||
{
|
||||
ip_address=192.168.64.21
|
||||
hw_address=1,2:2:2:2:2:2
|
||||
}
|
||||
"""
|
||||
let leases = DHCPLeaseParser.parse(interrupted)
|
||||
#expect(leases.count == 1)
|
||||
#expect(leases[0].ipAddress == "192.168.64.21")
|
||||
#expect(leases[0].leaseExpiry == nil)
|
||||
}
|
||||
|
||||
@Test("a missing lease database reads as no leases")
|
||||
func missingFileIsEmpty() {
|
||||
#expect(DHCPLeaseParser.parseFile(at: "/var/db/definitely-not-a-lease-file").isEmpty)
|
||||
}
|
||||
|
||||
@Test("a lease database on disk round-trips through parseFile")
|
||||
func parsesFromDisk() throws {
|
||||
let path = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("dhcpd_leases_test_\(UUID().uuidString)")
|
||||
try Self.fixture.write(to: path, atomically: true, encoding: .utf8)
|
||||
defer { try? FileManager.default.removeItem(at: path) }
|
||||
|
||||
let leases = DHCPLeaseParser.parseFile(at: path.path)
|
||||
#expect(DHCPLeaseParser.ipAddress(forMAC: "aa:bb:c:d:ee:ff", in: leases) == "192.168.64.9")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user