# Test python2 probe support. set test "python2" global env set PYTHON $env(PYTHON) if {! [installtest_p]} then { untested $test; return } if {! [python2_p]} then { untested $test; return } if {! [file exists "$PYTHON"]} then { untested $test; return } # To make sure the custom python module is in python's path, we'll # modify PYTHONPATH. set env(PYTHONPATH) $env(PYEXECDIR) # # In python 2.6, you have to specify the package name to run, like # 'python -m HelperSDT.__main__'. In python 2.7, using '__main__' is # automatic. Figure out what we need to do. if {! [catch {exec sh -c "$PYTHON -V 2>&1 | fgrep -q 2.6"} dummy]} { set module_name "HelperSDT.__main__" } else { set module_name "HelperSDT" } # # Test python backtraces. # # Notice we are using the tcl 'exec' command redirection of '2>@1', # which is equivalent to the shell's '2>&1'. if {[catch {exec cp $srcdir/$subdir/celsius.py . 2>@1} out]} { verbose -log "python cp failure: $out" } # This test won't work if we don't have python's debuginfo # installed. So, try to compile celsius-bt.stp first to see if we've # got debuginfo. spawn stap -p4 $srcdir/$subdir/celsius-bt.stp python2 set compile_errors 0 expect { -timeout 60 -re {^parse error[^\r\n]*\r\n} { incr compile_errors 1; exp_continue } -re {^[^\r\n]*compilation failed[^\r\n]*\r\n} { incr compile_errors 1; exp_continue } -re {^semantic error[^\r\n]*\r\n} { incr compile_errors 1; exp_continue } timeout { fail "$test (timeout)" } eof { } } catch { close } set res [wait -i $spawn_id] set res [lindex $res 3] if { $res != 0 || $compile_errors > 0 } { fail "$test: debuginfo check" untested $test catch {exec rm -f celsius.py} return } pass "$test: debuginfo check" set traceback_lines 0 set error_seen 0 set returning_seen 0 spawn stap $srcdir/$subdir/celsius-bt.stp -c "$PYTHON -m $module_name celsius.py 30" python2 expect { -timeout 120 -re {^30 Celsius is 86 Farenheit\r\n} { exp_continue } -re {^Traceback[^:]+:\r\n} { exp_continue } -re {^[ ]+File "celsius.py", line [0-9]+, in [^\r\n]+\r\n} { incr traceback_lines; exp_continue } -re {^celsius_to_farenheit returning\r\n} { incr returning_seen 1; exp_continue } -re {^semantic error:.+\r\n} { incr error_seen; exp_continue } timeout { incr error_seen; kill -INT -[exp_pid]; fail "$test (timeout)" } } catch {close}; catch {wait} if {$traceback_lines == 3} { pass "$test: backtrace" } else { if {$error_seen} { fail "$test: backtrace (errors)" } else { fail "$test: backtrace ($traceback_lines vs. 3)" } } if {$returning_seen == 1} { pass "$test: return probe seen" } else { if {$error_seen} { fail "$test: return probe seen" } else { fail "$test: return probe seen ($returning_seen vs. 1)" } } # # Test getting the value of python variables. # # Notice we are using the tcl 'exec' command redirection of '2>@1', # which is equivalent to the shell's '2>&1'. if {[catch {exec cp $srcdir/$subdir/python-var.py . 2>@1} out]} { verbose -log "python cp failure: $out" } set error_seen 0 # Note that we're incrementing MAXACTION, since we're doing lots of # actions in each probe. spawn stap -DMAXACTION=4000 $srcdir/$subdir/python-var.stp -c "$PYTHON -m $module_name python-var.py" python2 set types {"none" "type" "bool" "int" "long" "float" "complex" \ "string" "unicode" "tuple" "list" "xrange" "dictionary" \ "function" "class" "unbound" "instance" "method" "zip" \ "file" "ellipsis"} # Note that several types aren't handled well (or at all) yet: dict set kfails "none" 1 dict set kfails "type" 1 dict set kfails "bool" 1 dict set kfails "float" 1 dict set kfails "complex" 1 dict set kfails "xrange" 1 dict set kfails "function" 1 dict set kfails "unbound" 1 dict set kfails "method" 1 dict set kfails "file" 1 dict set kfails "ellipsis" 1 set globals [dict create] set locals [dict create] # Note that the order of dictionary items isn't important, so we have # to expect the items in any order. expect { -timeout 120 -re {^g_none = \r\n} { dict set globals "none" 1; exp_continue } -re {^g_type = \r\n} { dict set globals "type" 1; exp_continue } -re {^g_bool = 0x1\r\n} { dict set globals "bool" 1; exp_continue } -re {^g_int = 0x9\r\n} { dict set globals "int" 1; exp_continue } -re {^g_long = 0x7eadbeeffeedbabe\r\n} { dict set globals "long" 1; exp_continue } -re {^g_float = \r\n} { dict set globals "float" 1; exp_continue } -re {^g_complex = \r\n} { dict set globals "complex" 1; exp_continue } -re {^g_string = "regular string"\r\n} { dict set globals "string" 1; exp_continue } -re {^g_unicode = "unicode string"\r\n} { dict set globals "unicode" 1; exp_continue } -re {^g_tuple = \(0x0 "abc" 0x2\)\r\n} { dict set globals "tuple" 1; exp_continue } -re {^g_list = \[0x0 0x1 0x2 0x3\]\r\n} { dict set globals "list" 1; exp_continue } -re {^g_xrange = \r\n} { dict set globals "xrange" 1; exp_continue } -re {^g_dictionary = \{"Ribs":0x2 "Bacon":0x1 "Ham":0x0\}\r\n} { dict set globals "dictionary" 1; exp_continue } -re {^g_dictionary = \{"Ribs":0x2 "Ham":0x0 "Bacon":0x1\}\r\n} { dict set globals "dictionary" 1; exp_continue } -re {^g_dictionary = \{"Bacon":0x1 "Ham":0x0 "Ribs":0x2\}\r\n} { dict set globals "dictionary" 1; exp_continue } -re {^g_dictionary = \{"Bacon":0x1 "Ribs":0x2 "Ham":0x0\}\r\n} { dict set globals "dictionary" 1; exp_continue } -re {^g_dictionary = \{"Ham":0x0 "Ribs":0x2 "Bacon":0x1\}\r\n} { dict set globals "dictionary" 1; exp_continue } -re {^g_dictionary = \{"Ham":0x0 "Bacon":0x1 "Ribs":0x2\}\r\n} { dict set globals "dictionary" 1; exp_continue } -re {^g_func = \r\n} { dict set globals "function" 1; exp_continue } -re {^g_class = \r\n} { dict set globals "class" 1; exp_continue } -re {^g_unbound_method = \r\n} { dict set globals "unbound" 1; exp_continue } -re {^g_instance = <__main__.xqueue instance at 0x[0-9a-f]+>\r\n} { dict set globals "instance" 1; exp_continue } -re {^g_method = \r\n} { dict set globals "method" 1; exp_continue } -re {^g_zip = \[\(0x0 0x4\) \(0x1 0x5\) \(0x2 0x6\)\]\r\n} { dict set globals "zip" 1; exp_continue } -re {^g_file = \r\n} { dict set globals "file" 1; exp_continue } -re {^g_ellipsis = \r\n} { dict set globals "ellipsis" 1; exp_continue } -re {^l_none = \r\n} { dict set locals "none" 1; exp_continue } -re {^l_type = \r\n} { dict set locals "type" 1; exp_continue } -re {^l_bool = 0x0\r\n} { dict set locals "bool" 1; exp_continue } -re {^l_int = 0xf\r\n} { dict set locals "int" 1; exp_continue } -re {^l_long = 0x7eedfacecafebeef\r\n} { dict set locals "long" 1; exp_continue } -re {^l_float = \r\n} { dict set locals "float" 1; exp_continue } -re {^l_complex = \r\n} { dict set locals "complex" 1; exp_continue } -re {^l_string = "another regular string"\r\n} { dict set locals "string" 1; exp_continue } -re {^l_unicode = "another unicode string"\r\n} { dict set locals "unicode" 1; exp_continue } -re {^l_tuple = \("hello" 0x63 "there" 0xbeef\)\r\n} { dict set locals "tuple" 1; exp_continue } -re {^l_list = \[0x4 0x5 0x6 0x7 0x8 0x9 0xa\]\r\n} { dict set locals "list" 1; exp_continue } -re {^l_xrange = \r\n} { dict set locals "xrange" 1; exp_continue } -re {^l_dictionary = \{0x1:"numeric index" "abc":0x3\}\r\n} { dict set locals "dictionary" 1; exp_continue } -re {^l_dictionary = \{"abc":0x3 0x1:"numeric index"\}\r\n} { dict set locals "dictionary" 1; exp_continue } -re {^l_func = \r\n} { dict set locals "function" 1; exp_continue } -re {^l_class = \r\n} { dict set locals "class" 1; exp_continue } -re {^l_unbound_method = \r\n} { dict set locals "unbound" 1; exp_continue } -re {^l_instance = <__main__.xqueue instance at 0x[0-9a-f]+>\r\n} { dict set locals "instance" 1; exp_continue } -re {^l_method = \r\n} { dict set locals "method" 1; exp_continue } -re {^l_zip = \[\(0x4 0x0 0xb\) \(0x5 0x1 0xc\) \(0x6 0x2 0xd\) \(0x7 0x3 0xe\)\]\r\n} { dict set locals "zip" 1; exp_continue } -re {^l_file = \r\n} { dict set locals "file" 1; exp_continue } -re {^l_ellipsis = \r\n} { dict set locals "ellipsis" 1; exp_continue } -re {[^\r\n]*\r\n} { exp_continue } -re {^semantic error:.+\r\n} { incr error_seen; exp_continue } timeout { incr error_seen; kill -INT -[exp_pid]; fail "$test (timeout)" } } catch {close}; catch {wait} foreach type $types { if {[dict exists $globals $type]} { if {[dict exists $kfails $type]} { kfail "${test}_${type}_support" "$test: global $type" } else { pass "$test: global $type" } } else { fail "$test: global $type" } } foreach type $types { if {[dict exists $locals $type]} { if {[dict exists $kfails $type]} { kfail "${test}_${type}_support" "$test: local $type" } else { pass "$test: local $type" } } else { fail "$test: local $type" } } # # Test python backtraces when we're in a class instance. if {[catch {exec cp $srcdir/$subdir/class.py . 2>@1} out]} { verbose -log "python cp failure: $out" } set traceback_lines 0 set error_seen 0 set balance1_seen 0 set balance2_seen 0 spawn stap $srcdir/$subdir/class.stp -c "$PYTHON -m $module_name class.py" python2 expect { -timeout 120 -re {^Checkings current balance is: 10\r\n} { exp_continue } -re {^Savings current balance is: 33\r\n} { exp_continue } -re {^Traceback[^:]+:\r\n} { exp_continue } -re {^[ ]+File "class.py", line [0-9]+, in [^\r\n]+\r\n} { incr traceback_lines; exp_continue } -re {^balance is 0xa\r\n} { incr balance1_seen; exp_continue } -re {^balance is 0x21\r\n} { incr balance2_seen; exp_continue } -re {^semantic error:.+\r\n} { incr error_seen; exp_continue } timeout { incr error_seen; kill -INT -[exp_pid]; fail "$test (timeout)" } } catch {close}; catch {wait} if {$traceback_lines == 4} { pass "$test: backtrace" } else { if {$error_seen} { fail "$test: backtrace (errors)" } else { fail "$test: backtrace ($traceback_lines vs. 4)" } } if {$balance1_seen == 1 && $balance2_seen == 1} { pass "$test: instance variable" } else { if {$error_seen} { fail "$test: instance variable (errors)" } else { fail "$test: instance variable ($balance1_seen $balance2_seen)" } } if { $verbose == 0 } { catch {exec rm -rf celsius.py python-var.py class.py} }