# bpf.exp
#
# To restrict scripts to test, set the CHECK_ONLY environment variable.
# For example, to only test the printf and uprobes scripts, run:
#
#    make installcheck RUNTESTFLAGS="nonbpf.exp" CHECK_ONLY="printf uprobes"

set testdir "$srcdir/$subdir/bpf_tests"

# All tests should start by printing "BEGIN". If OUTPUT_STR is "", then 
# the test passes if "END PASS" is read and fails if "END FAIL" is read. Otherwise
# the test passes when "${OUTPUT_STR}END" is read and fails if END is read without
# OUTPUT_STR preceeding it.
proc stapnonbpf_run { TEST_NAME OUTPUT_STR args } { 
    global rc
    set rc -1
    set begin_str "BEGIN"
    set pass_str [expr { $OUTPUT_STR == "" ? "END PASS" : "${OUTPUT_STR}END" }]
    set fail_str [expr { $OUTPUT_STR == "" ? "END FAIL" : "END" }]

    # return codes
    set pass 0
    set fail 1
    set bad_output 2
    set eof_start 3
    set eof_end 4
    set timeout_start 5
    set timeout_end 6
    set invalid_prog 7
    set comp_err 8
    
    set cmd [concat stap -v $args]
    # don't the following: ... $test_file_name could be some transient or leftover file
    # if [file readable $test_file_name] { lappend cmd $test_file_name }

    send_log "executing: $cmd\n"
    eval spawn $cmd
    set mypid [exp_pid -i $spawn_id]
    expect {
        -timeout 30 
        -re {^WARNING: cannot find module [^\r]*DWARF[^\r]*\r\n} {exp_continue}
        -re {^WARNING: No unwind data for /.+\r\n} {exp_continue}
        -re {^Pass\ ([1234]):[^\r]*\ in\ ([0-9]+)usr/([0-9]+)sys/([0-9]+)real\ ms\.\r\n}
        {set pass$expect_out(1,string) "\t$expect_out(2,string)\t$expect_out(3,string)\t$expect_out(4,string)"; exp_continue}
        -re {^Pass\ ([34]): using cached [^\r]+\r\n}
        {set pass$expect_out(1,string) "\t0\t0\t0"; exp_continue}
        -re {^Passes: via server [^\r]* using [^\r]* in [0-9]+usr/[0-9]+sys/[0-9]+real ms\.\r\n} {exp_continue}
        -re {^Pass 5: starting run.\r\n} {exp_continue}
        -re $begin_str {
            # By default, "expect -re" will match up to 2000 chars.
            # Increase this to 8K worth of data.
            exp_match_max 8192

            # Avoid PR17274 to propagate
            set origexpinternal 1
            if {"[exp_internal -info]" == "0"} {set origexpinternal 0}
            #exp_internal 0

            expect {
                -timeout 20
                -re $pass_str  {
                    set rc $pass
                }
                -re $fail_str {
                    set rc $fail
                }
                default {
                    set rc $bad_output
                }
                timeout {
                    set rc $timeout_end
                    kill -INT -$mypid
                }
                eof { set rc $eof_end }
            }
            exp_internal $origexpinternal
        }
        -re "semantic error:" { set rc $comp_err }
        timeout {
            set rc $timeout_start
            kill -INT -$mypid
        }
        eof { set rc $eof_start  }
    }
  # again for good measure with KILL after 3s
  kill -INT -$mypid 3
  catch close
  wait
  return $rc
}

proc get_output_str { test } {
    global res
    switch -glob $test {
        printf.stp { set res [string repeat "abcd123456" 3] }
        sprintf.stp { set res [string repeat "0123456789" 2] }
        string1.stp { set res {begin\[str0str1str2str3\]probe\[str0str1str2str3\]end\[str0str1str2str3\]} }
        string*.stp { set res {probe0\[str0str1str2str3\]probe1\[str0str1str2str3\]end\[str0str1str2str3\]} }
        default { set res "" }
    }
    return $res
}

if {[info exists env(CHECK_ONLY)]} {
    set all_files [lsort [glob -nocomplain $testdir/*.stp]]
    set stap_files ""
    foreach file $env(CHECK_ONLY) {
        if {[lsearch $all_files $testdir/$file.stp] >= 0} {
            set stap_files "$stap_files $testdir/$file.stp"
        }
    }
} else {
    set stap_files [lsort [glob -nocomplain $testdir/*.stp]]
}

foreach file $stap_files {
    global mypid
    set mypid 0
    set test [file tail $file]
    if {! [installtest_p]} { untested $test; continue }

    # create a process for the tests that require one
    switch $test {
        uprobes.stp {
            eval spawn /usr/bin/sleep 20
            set mypid [exp_pid -i $spawn_id]
        }
    }

    set output_str [get_output_str $test]
    verbose -log "Running $file"
    set rc [stapnonbpf_run $test $output_str $file]
    if {$rc != 0} {
        # Known failures
        switch $test {
            bigmap1.stp { _setup_kfail NONBPF x86_64,s390x,aarch64 rhel }
            cast_op_tracepoint.stp {
                _setup_kfail NONBPF x86_64,s390x rhel
                _setup_kfail NONBPF x86_64 fedora
            }
            context_vars1.stp -
            context_vars2.stp -
            context_vars3.stp -
            kprobes.stp { _setup_kfail NONBPF ppc64le rhel }
            logging1.stp { _setup_kfail NONBPF - rhel,fedora }
            perf1.stp { _setup_kfail NONBPF x86_64,ppc64le,s390x,aarch64 rhel }
            perf2.stp { _setup_kfail NONBPF ppc64le,s390x,aarch64 rhel }
            reg_alloc3.stp -
            tracepoint1.stp -
            timer2.stp { _setup_kfail NONBPF - rhel,fedora }
            timer1.stp { _setup_kfail NONBPF x86_64 rhel,fedora }
        }
    }
    switch $rc {
        0 { pass $test }
        1 { fail "$test incorrect result" }
        2 { fail "$test unexpected output" }
        3 { fail "$test eof (startup)" }
        4 { fail "$test eof (shutdown)" }
        5 { fail "$test timeout (startup)" }
        6 { fail "$test timeout (startup)" }
        7 { fail "$test invalid bpf program" }
        8 { fail "$test compilation" }
        default { fail "$test unknown return value" }
    }

    if { $mypid > 0 } {
        kill -INT -$mypid 3
        catch close
        wait
    }
}


