2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-07 10:06:39 +00:00

test(dhcptest): write "no boot file" as absent, which is what a reply carries

Four scenarios asserted `bootfile matches ^$` for the cases where the point
is that the client is handed nothing to fetch: OPAL-v3 and s390x, which get
a conf-file instead, a petitboot node, and the architecture whose loader was
taken off disk.

That assertion cannot pass. A server naming no boot file sends an empty
BOOTP file header and no option 67, and an empty value is absent -- so the
run reported "bootfile is not present in the reply" against both backends,
in every case, whatever the server had done. Four failures that said nothing
about either implementation.

`bootfile absent` is the assertion those scenarios wanted. A unit test pins
it, so the unsatisfiable form cannot come back unnoticed.
This commit is contained in:
Daniel Hilst
2026-09-10 13:16:13 -03:00
parent 2abcec617b
commit 72bae42096
5 changed files with 19 additions and 4 deletions
+4
View File
@@ -140,6 +140,10 @@ One per line under a single multi-line `assert` key, as `target op value`.
| `matches` `contains` `starts-with` `ends-with` | text |
| `<` `<=` `>` `>=` | numeric |
"Nothing to fetch" is `bootfile absent`, not a match against an empty string:
a server that names no boot file sends an empty `file` header and no option 67,
which is an absent value, and `matches ^$` can never hold against it.
Assert on `bootfile`, not on `file`, unless the header itself is the point.
Servers genuinely differ — ISC dhcpd fills the BOOTP header, dnsmasq answers in
option 67 once the client has asked for it — and firmware reads whichever
+1 -1
View File
@@ -33,7 +33,7 @@ client_arch = 0x0000
assert =
msgtype == OFFER
yiaddr in %(pool)s
bootfile matches ^$
bootfile absent
[scenario present-loader-is-still-named]
description = S-12: An architecture whose loader is still there is unaffected
+1 -1
View File
@@ -160,7 +160,7 @@ client_arch = 0x000e
assert =
msgtype == OFFER
option:209 == %(petitboot_conf)s
bootfile matches ^$
bootfile absent
[scenario noip-interface-is-denied]
description = S-07: An interface marked *NOIP* is not answered at all
+2 -2
View File
@@ -177,7 +177,7 @@ client_arch = 0x000e
assert =
msgtype == OFFER
option:209 == %(opal_conf)s
bootfile matches ^$
bootfile absent
[scenario s390x-qemu]
description = S-16: A QEMU s390x client is given a conf-file and no loader
@@ -188,7 +188,7 @@ client_arch = 0x001f
assert =
msgtype == OFFER
option:209 == %(s390x_conf)s
bootfile matches ^$
bootfile absent
[scenario vendor-class-etherboot]
description = S-18: A client that identifies itself by vendor class alone still boots
@@ -72,6 +72,17 @@ class Evaluation(unittest.TestCase):
self.assertTrue(self.check("siaddr == 10.0.0.1").ok)
self.assertFalse(self.check("siaddr == 10.0.0.2").ok)
def test_a_reply_naming_no_boot_file_is_absent_not_empty(self):
# A server that hands out no boot file sends an empty `file` header and
# no option 67. "Nothing to fetch" is therefore written `bootfile
# absent`: a regex against an empty string can never hold, so a
# scenario written that way would fail whatever the server did.
nothing = offer(file="", options={54: "10.0.0.1"})
self.assertTrue(self.check("bootfile absent", nothing).ok)
self.assertFalse(self.check("bootfile present", nothing).ok)
self.assertFalse(self.check("bootfile matches ^$", nothing).ok)
self.assertTrue(self.check("bootfile present").ok)
def test_options_by_number_and_name(self):
self.assertTrue(self.check("option:54 == 10.0.0.1").ok)
self.assertTrue(self.check("option:server_id == 10.0.0.1").ok)