--- /dev/null
+# Tests for configuration parsing
+
+# Copyright (C) 2023 Jacob Bachmeyer
+#
+# This file is part of a testsuite for the GNU Secure Software Gatekeeper.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+proc spawn_configuration_test {args} {
+ upvar 1 spawn_id spawn_id
+ global GATEKEEPER_TOOL PERL CHECK_COVERAGE
+
+ set runcmd [list spawn]
+ if { $CHECK_COVERAGE } {
+ lappend runcmd $PERL -T -MDevel::Cover=-silent,1
+ }
+ lappend runcmd $GATEKEEPER_TOOL --check-config-parse
+ verbose -log "$runcmd $args"
+ eval $runcmd $args
+}
+
+proc analyze_output { test expected } {
+ upvar 1 spawn_id spawn_id
+
+ # collect output
+ set output ""
+ expect {
+ -re {.+} {
+ append output $expect_out(buffer)
+ exp_continue
+ }
+ eof
+ }
+ set res [wait]
+
+ set expected_ret [lindex $expected 0]
+
+ set result unresolved
+ if { [lindex $res 2] ne 0 } {
+ verbose -log "wait returned: $res"
+ set result unresolved
+ } elseif { [lindex $res 3] eq $expected_ret } {
+ set result pass
+ } elseif { [regexp {^!([[:digit:]]+)$} $expected_ret -> other_ret]
+ && [lindex $res 3] ne $other_ret } {
+ set result pass
+ } else {
+ verbose -log "unexpected return code from keymaster; \
+ want $expected_ret; have [lindex $res 3]"
+ set result fail
+ }
+
+ if { [llength $expected] > 1 } {
+ foreach pattern [lindex $expected 1] {
+ if { ![regexp -- $pattern $output] } {
+ verbose -log "expected re {$pattern} did not match output"
+ set result fail
+ }
+ }
+ }
+
+ $result $test
+}
+
+proc do_configuration_test { testname confname conftext arglist expected } {
+ set tenv [new_test_environment]
+
+ put_file [file join $tenv $confname] $conftext
+ eval [list spawn_configuration_test --conf [file join $tenv $confname]] \
+ $arglist
+ analyze_output $testname $expected
+
+ close_test_environment $tenv
+}
+
+# ----------------------------------------
+
+do_configuration_test "parse empty configuration" empty.conf {} {} {
+ !0
+ { "# gatekeeper configuration as parsed:"
+ {as parsed:[\r\n]+tag = upload}
+ {tag = upload[\r\n]+logtag = Upload[\r\n]+# END[\r\n]+}
+
+ {configuration parameter not set: pkgconfdir}
+ {configuration parameter not set: pkgstatedir}
+ {configuration parameter not set: inboxdir}
+ {configuration parameter not set: scratchdir}
+ {configuration parameter not set: stagedir}
+ {configuration parameter not set: publicdir}
+ {configuration parameter not set: archivedir}
+ {required configuration parameter\(s\) not set}
+ }
+}
+
+set configuration_file(basic) {# gatekeeper configuration parsing test
+
+tag = config_test
+logtag = ConfigTest
+
+pkgconfdir = /srv/gatetest/config
+pkgstatedir = /srv/gatetest/state
+inboxdir = /srv/gatetest/inbox
+scratchdir = /srv/gatetest/scratch
+stagedir = /srv/gatetest/stage
+publicdir = /srv/gatetest/pub
+archivedir = /srv/gatetest/archive
+}
+
+foreach missing {
+ pkgconfdir pkgstatedir inboxdir scratchdir
+ stagedir publicdir archivedir } {
+ do_configuration_test \
+ "parse configuration without $missing" "missing-${missing}.conf" \
+ [regsub -line "^$missing = .*\n" $configuration_file(basic) ""] {} \
+ [list !0 [list "configuration parameter not set: $missing" \
+ "required configuration parameter\\(s\\) not set" ] ]
+}
+
+do_configuration_test "parse basic configuration" basic.conf \
+ $configuration_file(basic) {} {
+ 0
+ { "# gatekeeper configuration as parsed:"
+ {as parsed:[\r\n]+tag = config_test}
+ {tag = config_test[\r\n]+logtag = ConfigTest[\r\n]+}
+ {pkgconfdir = /srv/gatetest/config[\r\n]+}
+ {pkgstatedir = /srv/gatetest/state[\r\n]+}
+ {inboxdir = /srv/gatetest/inbox[\r\n]+}
+ {scratchdir = /srv/gatetest/scratch[\r\n]+}
+ {stagedir = /srv/gatetest/stage[\r\n]+}
+ {publicdir = /srv/gatetest/pub[\r\n]+}
+ {archivedir = /srv/gatetest/archive[\r\n]+}
+ }
+ }
+
+# ----------------------------------------
+
+set configuration_file(basic-email) $configuration_file(basic)
+append configuration_file(basic-email) {
+[email]
+blacklist = /srv/gatetest/config/email.blacklist
+maintainermap = /srv/gatetest/config/maintainers.bypkg
+
+archivebox = public@example.org
+internalbox = internal@example.org
+}
+
+do_configuration_test "parse basic configuration with email" basic-email.conf \
+ $configuration_file(basic-email) {} {
+ 0
+ { "# gatekeeper configuration as parsed:"
+ {as parsed:[\r\n]+tag = config_test}
+ {tag = config_test[\r\n]+logtag = ConfigTest[\r\n]+}
+ {pkgconfdir = /srv/gatetest/config[\r\n]+}
+ {pkgstatedir = /srv/gatetest/state[\r\n]+}
+ {inboxdir = /srv/gatetest/inbox[\r\n]+}
+ {scratchdir = /srv/gatetest/scratch[\r\n]+}
+ {stagedir = /srv/gatetest/stage[\r\n]+}
+ {publicdir = /srv/gatetest/pub[\r\n]+}
+ {archivedir = /srv/gatetest/archive[\r\n]+}
+
+ {\[email\][\r\n]+blacklist =}
+ {blacklist = /srv/gatetest/config/email.blacklist}
+ {maintainermap = /srv/gatetest/config/maintainers.bypkg}
+ {archivebox = public@example.org}
+ {internalbox = internal@example.org}
+ }
+ }
+
+proc run_email_option_coverage_test {} {
+ global configuration_file
+
+ for { set i 0 } { $i <= 15 } { incr i } {
+ set cnf $configuration_file(basic-email)
+ if { $i & 1<<0 } { regsub -line {^blacklist = .*\n} $cnf "" cnf }
+ if { $i & 1<<1 } { regsub -line {^maintainermap = .*\n} $cnf "" cnf }
+ if { $i & 1<<2 } { regsub -line {^archivebox = .*\n} $cnf "" cnf }
+ if { $i & 1<<3 } { regsub -line {^internalbox = .*\n} $cnf "" cnf }
+ do_configuration_test \
+ "email configuration coverage $i" "email-$i.conf" $cnf {} {0 {}}
+ }
+}
+run_email_option_coverage_test
+
+# ----------------------------------------
+
+set configuration_file(zone-basic) {# gatekeeper configuration parsing test
+
+[zone.foo]
+tag = foo-test
+logtag = FooTest
+
+pkgconfdir = /srv/gatetest/config-foo
+pkgstatedir = /srv/gatetest/state-foo
+inboxdir = /srv/gatetest/inbox-foo
+scratchdir = /srv/gatetest/scratch-foo
+stagedir = /srv/gatetest/stage-foo
+publicdir = /srv/gatetest/pub-foo
+archivedir = /srv/gatetest/archive-foo
+
+[zone.bar]
+# tag defaults to zone name
+# logtag defaults to capitalized zone name
+pkgconfdir = /srv/gatetest/config-bar
+pkgstatedir = /srv/gatetest/state-bar
+inboxdir = /srv/gatetest/inbox-bar
+scratchdir = /srv/gatetest/scratch-bar
+stagedir = /srv/gatetest/stage-bar
+publicdir = /srv/gatetest/pub-bar
+archivedir = /srv/gatetest/archive-bar
+
+}
+
+do_configuration_test "parse zone configuration: foo" zone.conf \
+ $configuration_file(zone-basic) {-z foo} {
+ 0
+ { "# gatekeeper configuration as parsed for zone foo:"
+ {zone foo:[\r\n]+\[zone.foo\][\r\n]+tag = foo-test[\r\n]+}
+ {tag = foo-test[\r\n]+logtag = FooTest[\r\n]+}
+ {pkgconfdir = /srv/gatetest/config-foo}
+ {pkgstatedir = /srv/gatetest/state-foo}
+ {inboxdir = /srv/gatetest/inbox-foo}
+ {scratchdir = /srv/gatetest/scratch-foo}
+ {stagedir = /srv/gatetest/stage-foo}
+ {publicdir = /srv/gatetest/pub-foo}
+ {archivedir = /srv/gatetest/archive-foo}
+ }
+ }
+
+do_configuration_test "parse zone configuration: bar" zone.conf \
+ $configuration_file(zone-basic) {-z bar} {
+ 0
+ { "# gatekeeper configuration as parsed for zone bar:"
+ {zone bar:[\r\n]+\[zone.bar\][\r\n]+tag = bar[\r\n]+}
+ {tag = bar[\r\n]+logtag = Bar[\r\n]+}
+ {pkgconfdir = /srv/gatetest/config-bar}
+ {pkgstatedir = /srv/gatetest/state-bar}
+ {inboxdir = /srv/gatetest/inbox-bar}
+ {scratchdir = /srv/gatetest/scratch-bar}
+ {stagedir = /srv/gatetest/stage-bar}
+ {publicdir = /srv/gatetest/pub-bar}
+ {archivedir = /srv/gatetest/archive-bar}
+ }
+ }
+
+# ----------------------------------------
+
+# EOF