Browse Source
make.tcl libfetch gains env-only isolation seams - PUNK_LIBFETCH_CONFIG (alternate declarations file) and PUNK_LIBFETCH_PACKAGES (alternate tier root), the PUNK_RUNTIME_PLATFORM idiom - so fixture/mirror runs never read the real declarations or write the real bin/packages tier. Neither seam bypasses the -trust-server consent gate. New shell/testsuites/punkexe/maketcllibfetch.test (piped maketcl* harness + testsupport/httpfixture.tcl + a file:// mirror; the canonical origin is never contacted) pins the G-139 behaviours that previously had only manual session evidence: the server-trust gate refusing non-canonical origins with exit 3 before any network access or tier write, -serverurl-over-PUNKBIN_URL precedence, consented fetch/verify/materialize (sha1sums + zip + sidecar + installed-shape tree with embedded record), idempotent re-run vs -force, declared-revision-change re-materialization keyed to the tree record (with the sidecar-not-listed note lane), sha1-MISMATCH rejection without residue, missing-from-server-sha1sums failure, and the no-config no-op. 8/8 pass in both runner modes (singleproc + -jobs); full punkexe subtree green (93 runnable, 0 failed); the real bin/packages tier verified untouched. Also refreshes the stale src/runtime/libpackages.toml header (r1 IS published as of 2026-07-30; the G-139 reference now points at the archive) and documents the seams there and in the libfetch help text. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.commaster
6 changed files with 512 additions and 12 deletions
@ -1,4 +1,4 @@
|
||||
[project] |
||||
name = "punkshell" |
||||
version = "0.32.0" |
||||
version = "0.32.1" |
||||
license = "BSD-2-Clause" |
||||
|
||||
@ -0,0 +1,457 @@
|
||||
package require tcltest |
||||
package require punk::zip |
||||
package require sha1 |
||||
|
||||
#Piped characterization of 'make.tcl libfetch' (G-139): the punkbin lib-tier |
||||
#fetch/verify/materialize entrypoint, driven ONLY against fixture origins - a |
||||
#child-process http server (testsupport/httpfixture.tcl) serving a crafted |
||||
#punkbin lib/<target> layout, plus a file:// mirror of the same layout and |
||||
#deliberately-unreachable urls. The real canonical origin is never contacted. |
||||
#Runs the WORKING TREE's src/make.tcl under the built punk executable's |
||||
#'script' subcommand with output captured through a pipe (the maketcl* family |
||||
#harness), and pins: |
||||
# - the server-trust consent gate: any NON-canonical origin (PUNKBIN_URL env |
||||
# or -serverurl flag) without -trust-server refuses with exit 3 BEFORE any |
||||
# network access or tier write (proven with an unreachable origin), naming |
||||
# the offending origin and the canonical one |
||||
# - -serverurl beats PUNKBIN_URL (documented precedence): a consented fetch |
||||
# succeeds against the fixture while the env var points at a dead address |
||||
# - consented fetch: per-target sha1sums + artifact zip + .toml sidecar |
||||
# fetched and sha1-verified into the tier, installed-shape tree |
||||
# materialized under <packagesroot>/<target>/tcl<N>/<pkg> with pkgIndex.tcl |
||||
# and the embedded punkbin-artifact.toml record, exit 0, ESC-free output |
||||
# (G-113 piped policy) |
||||
# - idempotent re-run: verified-present + tree-current, no re-fetch, no |
||||
# re-materialization; -force re-fetches and re-materializes |
||||
# - editing the declared name to a new revision re-materializes WITHOUT |
||||
# -force (tree currency is keyed to the tree's embedded record name), with |
||||
# immutable revisions side-by-side in the tier; a sidecar missing from the |
||||
# server sha1sums is noted and skipped without failing the artifact |
||||
# - sha1 MISMATCH against the server sha1sums: artifact rejected (no .part |
||||
# residue, no zip, no tree), run FAILED with exit 3 |
||||
# - an artifact missing from the server sha1sums fails the run (exit 3) |
||||
# - no config at the declarations path: 'nothing declared' no-op, exit 0 |
||||
# - a file:// origin works end-to-end via the native copy transport (and |
||||
# still needs -trust-server like any non-canonical origin) |
||||
#The canonical-origin url asserted in the gate output is characterization of |
||||
#the constant in src/make.tcl - a deliberate canonical-origin change |
||||
#legitimately updates it. |
||||
#Isolation: the env seams PUNK_LIBFETCH_CONFIG + PUNK_LIBFETCH_PACKAGES point |
||||
#every run at tcltest-tempdir fixture state - the real |
||||
#src/runtime/libpackages.toml and bin/packages tier are never touched. |
||||
# |
||||
#Target executable resolved from env(PUNK_SHELL_TEST_EXE), else <projectroot>/bin/punk902z.exe |
||||
#then <projectroot>/bin/punkshell902. Skipped (constraint punkexeavailable) if none found. |
||||
|
||||
namespace eval ::testspace { |
||||
namespace import ::tcltest::* |
||||
|
||||
variable testdir [file dirname [file normalize [info script]]] |
||||
#<projectroot>/src/tests/shell/testsuites/punkexe -> 5 levels up to <projectroot> |
||||
variable projectroot [file normalize [file join $testdir .. .. .. .. ..]] |
||||
variable testsroot [file normalize [file join $testdir .. .. ..]] |
||||
variable maketcl [file join $projectroot src make.tcl] |
||||
|
||||
variable punkexe "" |
||||
if {[info exists ::env(PUNK_SHELL_TEST_EXE)] && $::env(PUNK_SHELL_TEST_EXE) ne ""} { |
||||
set punkexe [file normalize $::env(PUNK_SHELL_TEST_EXE)] |
||||
} else { |
||||
foreach candidate [list [file join $projectroot bin punk902z.exe] [file join $projectroot bin punkshell902]] { |
||||
if {[file exists $candidate]} { |
||||
set punkexe $candidate |
||||
break |
||||
} |
||||
} |
||||
} |
||||
testConstraint punkexeavailable [expr {$punkexe ne "" && [file exists $punkexe]}] |
||||
|
||||
variable maketcl_run_timeout_ms 60000 |
||||
|
||||
variable runstate |
||||
array set runstate {} |
||||
|
||||
proc maketcl_run_read {chan} { |
||||
variable runstate |
||||
append runstate(output) [read $chan] |
||||
if {[chan eof $chan]} { |
||||
chan event $chan readable {} |
||||
set runstate(done) eof |
||||
} |
||||
} |
||||
|
||||
#Run <punkexe> script src/make.tcl <subcommand...> with output captured through a |
||||
#pipe (stdin half-closed for immediate EOF - make.tcl must never wait on stdin for |
||||
#these subcommands; the child inherits ::env, which carries the seams and the |
||||
#per-case PUNKBIN_URL state). Returns dict: timedout 0|1, exitcode <int|"">, |
||||
#output <combined stdout+stderr>. |
||||
proc maketcl_run {cmdargs} { |
||||
variable runstate |
||||
variable maketcl_run_timeout_ms |
||||
variable punkexe |
||||
variable maketcl |
||||
array unset runstate |
||||
set runstate(output) "" |
||||
set runstate(done) "" |
||||
|
||||
set chan [open |[list $punkexe script $maketcl {*}$cmdargs 2>@1] r+] |
||||
chan configure $chan -blocking 0 -translation binary |
||||
catch {chan close $chan write} ;#no stdin for the child - immediate EOF |
||||
set timerid [after $maketcl_run_timeout_ms [list set [namespace current]::runstate(done) timeout]] |
||||
chan event $chan readable [list [namespace current]::maketcl_run_read $chan] |
||||
while {$runstate(done) eq ""} { |
||||
vwait [namespace current]::runstate(done) |
||||
} |
||||
after cancel $timerid |
||||
set timedout [expr {$runstate(done) eq "timeout"}] |
||||
set exitcode "" |
||||
if {$timedout} { |
||||
catch {exec {*}[auto_execok taskkill] /F /T /PID [lindex [pid $chan] 0]} |
||||
catch {chan close $chan} |
||||
} else { |
||||
chan configure $chan -blocking 1 |
||||
if {[catch {chan close $chan} errdata errdict]} { |
||||
set exitcode [lindex [dict get $errdict -errorcode] end] |
||||
} else { |
||||
set exitcode 0 |
||||
} |
||||
} |
||||
return [dict create timedout $timedout exitcode $exitcode output $runstate(output)] |
||||
} |
||||
|
||||
proc esc_count {text} { |
||||
return [regexp -all {\x1b} $text] |
||||
} |
||||
|
||||
proc writefile_raw {path content} { |
||||
set fd [open $path w] |
||||
fconfigure $fd -translation binary |
||||
puts -nonewline $fd $content |
||||
close $fd |
||||
} |
||||
proc readfile {path} { |
||||
set fd [open $path r] |
||||
set data [read $fd] |
||||
close $fd |
||||
return $data |
||||
} |
||||
|
||||
#--- fixture punkbin lib-tier layout (server side) ----------------------------- |
||||
variable plat testplat-x86_64 |
||||
variable serverroot "" |
||||
variable configdir "" |
||||
variable configfile "" |
||||
variable packagesroot "" |
||||
variable serverchan "" |
||||
variable baseurl "" |
||||
variable saved_env [dict create] |
||||
variable fixtureok 0 |
||||
|
||||
#a minimal installed-shape package folder: pkgIndex.tcl + one script + the |
||||
#embedded punkbin-artifact.toml record whose name line keys tree currency |
||||
proc fixture_record {artifactname} { |
||||
set l {} |
||||
lappend l "# punkbin artifact record (test fixture)" |
||||
lappend l "schema = \"2\"" |
||||
lappend l "name = \"$artifactname\"" |
||||
lappend l "class = \"library\"" |
||||
return "[join $l \n]\n" |
||||
} |
||||
proc build_fixture_zip {stageparent pkgfolder artifactname payload zipfile} { |
||||
set pdir [file join $stageparent $pkgfolder] |
||||
file mkdir $pdir |
||||
writefile_raw [file join $pdir pkgIndex.tcl] "package ifneeded fixturepkg 1.0 \[list source \[file join \$dir fixturepkg.tcl\]\]\n" |
||||
writefile_raw [file join $pdir fixturepkg.tcl] $payload |
||||
writefile_raw [file join $pdir punkbin-artifact.toml] [fixture_record $artifactname] |
||||
punk::zip::mkzip -directory $stageparent $zipfile |
||||
file delete -force $pdir |
||||
} |
||||
|
||||
proc write_config {entries} { |
||||
variable configfile |
||||
set lines [list "# maketcllibfetch.test fixture declarations"] |
||||
foreach e $entries { |
||||
lassign $e key name target |
||||
lappend lines "\[artifact.$key\]" "name = \"$name\"" "target = \"$target\"" "" |
||||
} |
||||
writefile_raw $configfile "[join $lines \n]\n" |
||||
} |
||||
|
||||
proc reset_packages {} { |
||||
variable packagesroot |
||||
file delete -force $packagesroot |
||||
file mkdir $packagesroot |
||||
} |
||||
|
||||
proc server_start {} { |
||||
variable serverroot |
||||
variable serverchan |
||||
variable baseurl |
||||
variable testsroot |
||||
set helper [file join $testsroot testsupport httpfixture.tcl] |
||||
if {![file exists $helper]} { return 0 } |
||||
if {[catch {open |[list [info nameofexecutable] $helper $serverroot] r+} chan]} { |
||||
return 0 |
||||
} |
||||
chan configure $chan -blocking 1 -buffering line |
||||
set line [gets $chan] |
||||
if {[regexp {^PORT (\d+)$} $line -> p]} { |
||||
set serverchan $chan |
||||
set baseurl "http://127.0.0.1:$p" |
||||
return 1 |
||||
} |
||||
catch {close $chan} |
||||
return 0 |
||||
} |
||||
proc server_stop {} { |
||||
variable serverchan |
||||
if {$serverchan ne ""} { |
||||
#closing the pipe EOFs the child's stdin - it exits on that |
||||
catch {close $serverchan} |
||||
set serverchan "" |
||||
} |
||||
} |
||||
|
||||
#--- one-time fixture build + server launch ------------------------------------ |
||||
if {[testConstraint punkexeavailable]} { |
||||
variable serverroot [file normalize [makeDirectory lf_server]] |
||||
variable configdir [file normalize [makeDirectory lf_config]] |
||||
variable packagesroot [file normalize [makeDirectory lf_packages]] |
||||
variable configfile [file join $configdir libpackages.toml] |
||||
set tplat [file join $serverroot lib $plat] |
||||
file mkdir $tplat |
||||
set zipstage [file normalize [makeDirectory lf_zipstage]] |
||||
#two immutable revisions of the same package folder (r2 = new bytes, new |
||||
#embedded record) + a corrupt-served artifact for the mismatch case |
||||
build_fixture_zip $zipstage fixturepkg fixturepkg-tcl9-r1.zip \ |
||||
"proc fixturepkg::rev {} {return r1}\n" [file join $tplat fixturepkg-tcl9-r1.zip] |
||||
build_fixture_zip $zipstage fixturepkg fixturepkg-tcl9-r2.zip \ |
||||
"proc fixturepkg::rev {} {return r2}\n" [file join $tplat fixturepkg-tcl9-r2.zip] |
||||
writefile_raw [file join $tplat fixturepkg-tcl9-r1.toml] [fixture_record fixturepkg-tcl9-r1.zip] |
||||
writefile_raw [file join $tplat badpkg-tcl9-r1.zip] "these served bytes do not match the sha1 the server sha1sums promises\n" |
||||
#server sha1sums: r1 zip + r1 sidecar listed with true hashes; r2 zip |
||||
#listed with a true hash but its sidecar deliberately NOT listed (the |
||||
#sidecar-skipped note lane); badpkg listed with a WRONG hash (mismatch |
||||
#lane). ghostpkg-tcl9-r1.zip is declared by a config but never listed. |
||||
set sums [list] |
||||
foreach fname [list fixturepkg-tcl9-r1.zip fixturepkg-tcl9-r1.toml fixturepkg-tcl9-r2.zip] { |
||||
lappend sums "[string tolower [sha1::sha1 -hex -file [file join $tplat $fname]]] *$fname" |
||||
} |
||||
lappend sums "[string repeat 0 40] *badpkg-tcl9-r1.zip" |
||||
writefile_raw [file join $tplat sha1sums.txt] "[join $sums \n]\n" |
||||
|
||||
variable fixtureok [server_start] |
||||
#shield the runs from ambient state, then point the seams at the fixture |
||||
#config + packages tier (restored at end of file) |
||||
foreach v {PUNKBIN_URL PUNK_LIBFETCH_CONFIG PUNK_LIBFETCH_PACKAGES} { |
||||
if {[info exists ::env($v)]} { |
||||
dict set saved_env $v $::env($v) |
||||
unset ::env($v) |
||||
} |
||||
} |
||||
set ::env(PUNK_LIBFETCH_CONFIG) $configfile |
||||
set ::env(PUNK_LIBFETCH_PACKAGES) $packagesroot |
||||
} |
||||
testConstraint fixtureserver $fixtureok |
||||
variable deadurl "http://127.0.0.1:1" |
||||
|
||||
#added 2026-07-30 (agent, G-139) - post-achievement follow-up: fixture-driven |
||||
#characterization of the libfetch consent gate, verification and idempotency |
||||
#behaviours (the goal's live verification was manual session evidence) |
||||
|
||||
test maketcl_libfetch_trustgate_env {a non-canonical PUNKBIN_URL without -trust-server refuses with exit 3 before any network access or tier write - proven against an unreachable origin} -constraints {punkexeavailable} -setup { |
||||
reset_packages |
||||
set ::env(PUNKBIN_URL) $::testspace::deadurl |
||||
} -body { |
||||
variable deadurl |
||||
variable packagesroot |
||||
set r [maketcl_run {libfetch}] |
||||
set out [dict get $r output] |
||||
set result [list] |
||||
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||
lappend result esc [esc_count $out] |
||||
lappend result origin_named [string match "*LIBFETCH: origin '$deadurl' is not the canonical punkbin origin*" $out] |
||||
lappend result canonical_named [string match "*LIBFETCH: canonical: https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master*" $out] |
||||
lappend result consent_stated [string match "*requires the explicit -trust-server flag*Nothing was fetched.*" $out] |
||||
lappend result tier_untouched [expr {[llength [glob -nocomplain -directory $packagesroot *]] == 0}] |
||||
set result |
||||
} -cleanup { |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
} -result {timedout 0 exitcode 3 esc 0 origin_named 1 canonical_named 1 consent_stated 1 tier_untouched 1} |
||||
|
||||
test maketcl_libfetch_trustgate_flag {a non-canonical -serverurl without -trust-server refuses naming that origin} -constraints {punkexeavailable fixtureserver} -setup { |
||||
reset_packages |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
} -body { |
||||
variable baseurl |
||||
variable packagesroot |
||||
set r [maketcl_run [list libfetch -serverurl $baseurl]] |
||||
set out [dict get $r output] |
||||
set result [list] |
||||
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||
lappend result origin_named [string match "*LIBFETCH: origin '$baseurl' is not the canonical punkbin origin*" $out] |
||||
lappend result tier_untouched [expr {[llength [glob -nocomplain -directory $packagesroot *]] == 0}] |
||||
set result |
||||
} -cleanup { |
||||
} -result {timedout 0 exitcode 3 origin_named 1 tier_untouched 1} |
||||
|
||||
test maketcl_libfetch_fetch_idempotent_force {consented http fetch materializes the declared artifact (with -serverurl beating a dead PUNKBIN_URL); a re-run is idempotent; -force re-fetches and re-materializes} -constraints {punkexeavailable fixtureserver} -setup { |
||||
reset_packages |
||||
write_config {{fixture fixturepkg-tcl9-r1.zip testplat-x86_64}} |
||||
#the dead env origin proves flag-over-env precedence: only -serverurl |
||||
#reaching the fixture lets this succeed |
||||
set ::env(PUNKBIN_URL) $::testspace::deadurl |
||||
} -body { |
||||
variable baseurl |
||||
variable packagesroot |
||||
variable plat |
||||
set tier [file join $packagesroot $plat] |
||||
set result [list] |
||||
|
||||
set r [maketcl_run [list libfetch -serverurl $baseurl -trust-server]] |
||||
set out [dict get $r output] |
||||
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||
lappend result esc [esc_count $out] |
||||
lappend result fetched [string match "*LIBFETCH: fetched lib/$plat/fixturepkg-tcl9-r1.zip*" $out] |
||||
lappend result materialized [string match "*LIBFETCH: materialized $plat/tcl9/fixturepkg*" $out] |
||||
lappend result done_line [string match "*LIBFETCH: done (2 action(s)) -> $packagesroot*" $out] |
||||
lappend result tier_zip [file isfile [file join $tier fixturepkg-tcl9-r1.zip]] |
||||
lappend result tier_sidecar [file isfile [file join $tier fixturepkg-tcl9-r1.toml]] |
||||
lappend result tier_sums [file isfile [file join $tier sha1sums.txt]] |
||||
lappend result tree_pkgindex [file isfile [file join $tier tcl9 fixturepkg pkgIndex.tcl]] |
||||
lappend result tree_record [regexp -line {^name = "fixturepkg-tcl9-r1\.zip"$} [readfile [file join $tier tcl9 fixturepkg punkbin-artifact.toml]]] |
||||
lappend result no_part [expr {[llength [glob -nocomplain -directory $tier *.part]] == 0}] |
||||
|
||||
set r2 [maketcl_run [list libfetch -serverurl $baseurl -trust-server]] |
||||
set out2 [dict get $r2 output] |
||||
lappend result rerun_exitcode [dict get $r2 exitcode] |
||||
lappend result rerun_verified [string match "*LIBFETCH: verified-present lib/$plat/fixturepkg-tcl9-r1.zip*" $out2] |
||||
lappend result rerun_treecurrent [string match "*LIBFETCH: tree-current $plat/tcl9/fixturepkg*" $out2] |
||||
lappend result rerun_no_refetch [expr {![string match "*LIBFETCH: fetched *" $out2] && ![string match "*LIBFETCH: materialized *" $out2]}] |
||||
|
||||
set r3 [maketcl_run [list libfetch -serverurl $baseurl -trust-server -force]] |
||||
set out3 [dict get $r3 output] |
||||
lappend result force_exitcode [dict get $r3 exitcode] |
||||
lappend result force_refetched [string match "*LIBFETCH: fetched lib/$plat/fixturepkg-tcl9-r1.zip*" $out3] |
||||
lappend result force_rematerialized [string match "*LIBFETCH: materialized $plat/tcl9/fixturepkg*" $out3] |
||||
set result |
||||
} -cleanup { |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
} -result {timedout 0 exitcode 0 esc 0 fetched 1 materialized 1 done_line 1 tier_zip 1 tier_sidecar 1 tier_sums 1 tree_pkgindex 1 tree_record 1 no_part 1 rerun_exitcode 0 rerun_verified 1 rerun_treecurrent 1 rerun_no_refetch 1 force_exitcode 0 force_refetched 1 force_rematerialized 1} |
||||
|
||||
test maketcl_libfetch_declared_revision_change {editing the declared name to a new revision re-materializes without -force (tree currency keys off the embedded record); revisions sit side-by-side in the tier; a sidecar absent from the server sha1sums is noted and skipped without failing} -constraints {punkexeavailable fixtureserver} -setup { |
||||
reset_packages |
||||
write_config {{fixture fixturepkg-tcl9-r1.zip testplat-x86_64}} |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
} -body { |
||||
variable baseurl |
||||
variable packagesroot |
||||
variable plat |
||||
set tier [file join $packagesroot $plat] |
||||
set result [list] |
||||
set r [maketcl_run [list libfetch -serverurl $baseurl -trust-server]] |
||||
lappend result prime_exitcode [dict get $r exitcode] |
||||
write_config {{fixture fixturepkg-tcl9-r2.zip testplat-x86_64}} |
||||
set r2 [maketcl_run [list libfetch -serverurl $baseurl -trust-server]] |
||||
set out2 [dict get $r2 output] |
||||
lappend result exitcode [dict get $r2 exitcode] |
||||
lappend result fetched_r2 [string match "*LIBFETCH: fetched lib/$plat/fixturepkg-tcl9-r2.zip*" $out2] |
||||
lappend result rematerialized [string match "*LIBFETCH: materialized $plat/tcl9/fixturepkg*" $out2] |
||||
lappend result sidecar_noted [string match "*LIBFETCH: note - fixturepkg-tcl9-r2.toml not listed in server sha1sums (artifact accepted; sidecar skipped)*" $out2] |
||||
lappend result tree_record_r2 [regexp -line {^name = "fixturepkg-tcl9-r2\.zip"$} [readfile [file join $tier tcl9 fixturepkg punkbin-artifact.toml]]] |
||||
lappend result r1_still_present [file isfile [file join $tier fixturepkg-tcl9-r1.zip]] |
||||
lappend result r2_present [file isfile [file join $tier fixturepkg-tcl9-r2.zip]] |
||||
lappend result no_r2_sidecar [expr {![file exists [file join $tier fixturepkg-tcl9-r2.toml]]}] |
||||
set result |
||||
} -cleanup { |
||||
} -result {prime_exitcode 0 exitcode 0 fetched_r2 1 rematerialized 1 sidecar_noted 1 tree_record_r2 1 r1_still_present 1 r2_present 1 no_r2_sidecar 1} |
||||
|
||||
test maketcl_libfetch_sha1_mismatch {an artifact whose served bytes do not match the server sha1sums is rejected: no zip, no .part residue, no tree, run FAILED exit 3} -constraints {punkexeavailable fixtureserver} -setup { |
||||
reset_packages |
||||
write_config {{bad badpkg-tcl9-r1.zip testplat-x86_64}} |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
} -body { |
||||
variable baseurl |
||||
variable packagesroot |
||||
variable plat |
||||
set tier [file join $packagesroot $plat] |
||||
set result [list] |
||||
set r [maketcl_run [list libfetch -serverurl $baseurl -trust-server]] |
||||
set out [dict get $r output] |
||||
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||
lappend result mismatch_named [string match "*sha1 MISMATCH for badpkg-tcl9-r1.zip*- deleted*" $out] |
||||
lappend result failed_stated [string match "*LIBFETCH: FAILED - one or more declared artifacts*" $out] |
||||
lappend result no_zip [expr {![file exists [file join $tier badpkg-tcl9-r1.zip]]}] |
||||
lappend result no_part [expr {[llength [glob -nocomplain -directory $tier *.part]] == 0}] |
||||
lappend result no_tree [expr {![file exists [file join $tier tcl9 badpkg]]}] |
||||
set result |
||||
} -cleanup { |
||||
} -result {timedout 0 exitcode 3 mismatch_named 1 failed_stated 1 no_zip 1 no_part 1 no_tree 1} |
||||
|
||||
test maketcl_libfetch_not_in_server_sums {a declared artifact absent from the server sha1sums fails the run} -constraints {punkexeavailable fixtureserver} -setup { |
||||
reset_packages |
||||
write_config {{ghost ghostpkg-tcl9-r1.zip testplat-x86_64}} |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
} -body { |
||||
variable baseurl |
||||
variable plat |
||||
set result [list] |
||||
set r [maketcl_run [list libfetch -serverurl $baseurl -trust-server]] |
||||
set out [dict get $r output] |
||||
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||
lappend result not_listed [string match "*'ghostpkg-tcl9-r1.zip' is not listed in the server's lib/$plat/sha1sums.txt*" $out] |
||||
lappend result failed_stated [string match "*LIBFETCH: FAILED - one or more declared artifacts*" $out] |
||||
set result |
||||
} -cleanup { |
||||
} -result {timedout 0 exitcode 3 not_listed 1 failed_stated 1} |
||||
|
||||
test maketcl_libfetch_no_config {a missing declarations file is a stated no-op with exit 0 (canonical origin, no network involved)} -constraints {punkexeavailable} -setup { |
||||
reset_packages |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
set ::env(PUNK_LIBFETCH_CONFIG) [file join $::testspace::configdir absent_declarations.toml] |
||||
} -body { |
||||
set result [list] |
||||
set r [maketcl_run {libfetch}] |
||||
set out [dict get $r output] |
||||
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||
lappend result noop_stated [string match "*LIBFETCH: no config at *absent_declarations.toml - nothing declared, nothing to fetch*" $out] |
||||
set result |
||||
} -cleanup { |
||||
set ::env(PUNK_LIBFETCH_CONFIG) $::testspace::configfile |
||||
} -result {timedout 0 exitcode 0 noop_stated 1} |
||||
|
||||
test maketcl_libfetch_file_origin {a consented file:// mirror origin fetches and materializes via the native copy transport (no server process involved)} -constraints {punkexeavailable} -setup { |
||||
reset_packages |
||||
write_config {{fixture fixturepkg-tcl9-r1.zip testplat-x86_64}} |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
} -body { |
||||
variable serverroot |
||||
variable packagesroot |
||||
variable plat |
||||
set tier [file join $packagesroot $plat] |
||||
set result [list] |
||||
set r [maketcl_run [list libfetch -serverurl "file://$serverroot" -trust-server]] |
||||
set out [dict get $r output] |
||||
lappend result timedout [dict get $r timedout] exitcode [dict get $r exitcode] |
||||
lappend result fetched [string match "*LIBFETCH: fetched lib/$plat/fixturepkg-tcl9-r1.zip*" $out] |
||||
lappend result materialized [string match "*LIBFETCH: materialized $plat/tcl9/fixturepkg*" $out] |
||||
lappend result tree_pkgindex [file isfile [file join $tier tcl9 fixturepkg pkgIndex.tcl]] |
||||
lappend result tree_record [regexp -line {^name = "fixturepkg-tcl9-r1\.zip"$} [readfile [file join $tier tcl9 fixturepkg punkbin-artifact.toml]]] |
||||
set result |
||||
} -cleanup { |
||||
} -result {timedout 0 exitcode 0 fetched 1 materialized 1 tree_pkgindex 1 tree_record 1} |
||||
|
||||
#whole-file teardown: stop the fixture server, restore shielded env state |
||||
server_stop |
||||
if {[testConstraint punkexeavailable]} { |
||||
unset -nocomplain ::env(PUNKBIN_URL) |
||||
unset -nocomplain ::env(PUNK_LIBFETCH_CONFIG) |
||||
unset -nocomplain ::env(PUNK_LIBFETCH_PACKAGES) |
||||
variable saved_env |
||||
dict for {v val} $saved_env { |
||||
set ::env($v) $val |
||||
} |
||||
} |
||||
|
||||
cleanupTests |
||||
} |
||||
namespace delete ::testspace |
||||
Loading…
Reference in new issue