2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-07 10:06:39 +00:00
Files
xcat-core/xCAT-test/unit
Daniel Hilst e7f7717627 fix(dhcp): give both backends the same answer for eight kinds of client
Eight of the parity decisions in the spec's Appendix A, where ISC dhcpd and
Kea answered the same frame differently and the operator never chose which
backend they got.

ISC gains two branches its if/else chain never had, so the client falls
through to /yaboot no longer:

  - 0x000c ppc64 is given /boot/grub2/grub2.ppc.  yaboot is not a UEFI
    loader and cannot boot one of these machines (decision 2).
  - 0x0010 is the same x86-64 UEFI firmware and the same loader as 0x0007,
    announced by a machine set to fetch it over HTTP (decision 3).

Kea gains what ISC has always had:

  - Etherboot, which predates option 93 and says what it is in option 60
    alone, is recognised and given the BIOS loader (decision 10).
  - onie_vendor is answered per subnet, not only per node: a switch
    announces it on its first boot, before anyone has defined it as a node
    (decision 11).
  - A client nothing else recognises is given /yaboot.  Kea has no else, so
    the condition is the negation of every architecture and vendor class
    another rule answers, rather than a dependence on class ordering
    (decision 7).
  - netboot=nimol is given /vios/nodes/<node> (decision 6).

and drops two answers ISC never gave:

  - No BIOS loader on disk no longer means pxelinux.0 in its place.  Naming
    a file that is not there costs the client a timeout it cannot diagnose,
    and a different loader boots something nobody asked for; the class is
    simply not written (decision 8).
  - netboot=petitboot sends the conf-file and nothing else.  petitboot acts
    on a boot file name when it sees one, so naming one as well sent the
    machine after a TFTP fetch that never happens on ISC (decision 12).
2026-09-10 13:27:58 -03:00
..

xCAT-test/unit

Unit tests. These run against the source tree only -- no xCAT installation, no running daemons, no management node.

They are executed on every pull request by the xcat_test GitHub Actions workflow, which calls run_unit_tests() in github_action_xcat_test.pl:

prove -r xCAT-test/unit

You can run exactly the same thing from a clean checkout:

cd <xcat-core checkout>
prove -r xCAT-test/unit

What belongs here

A test belongs in unit/ when everything it needs is in the checkout: plugin and library sources, kickstart/preseed/subiquity templates, postscripts, packaging metadata. Such a test asserts on rendered output or module logic and reaches the repository root through FindBin:

use FindBin;
use lib "$FindBin::Bin/../../perl-xCAT";
use lib "$FindBin::Bin/../../xCAT-server/lib/perl";

Because of those FindBin paths the tests only work from a source tree. The copy installed under /opt/xcat/share/xcat/tools/autotest/unit is not a substitute -- ../.. resolves to /opt/xcat/share/xcat/tools there and the tests die or silently skip. The CI takes a copy of the checkout before the build for this reason; see preserve_source_tree().

What does not belong here

Anything that needs an installed xCAT, a populated /install, a real service binary or a live daemon. Those go in ../integration and run on a management node through xcattest. Both suites run on every pull request -- the workflow installs xCAT on the runner and then runs the ci_test cases against it -- so putting a test in integration/ does not cost it CI coverage. What differs is what each suite is allowed to depend on, and that unit tests also run standalone from a bare checkout with no xCAT at all.

Shell-script unit tests belong in ../bats and run with BATS. Do not add Perl .t tests that grep shell source when the behavior can be exercised by sourcing a shell library or script and shadowing the external commands it calls.

The distinction matters because a test that needs an absent environment does not fail -- it calls plan skip_all and reports as skipped. A handful of those in a suite of several hundred assertions is easy to stop reading. Keeping the two kinds in separate directories means a skip in unit/ is a real signal rather than routine noise.

Guarding on a source file, on the other hand, is fine and common here:

plan skip_all => "compute.subiquity.tmpl not found" unless -f $tmpl_path;

That guard never fires when the tree is intact.