github.com/glycerine/xcryptossh@v7.0.4+incompatible/util.go (about)

     1  package ssh
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"runtime"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  )
    11  
    12  // utilities, error types, and debugging machinery.
    13  
    14  // xtestLeakCheckOn controls leak checking.
    15  //
    16  // change this to true to check for goroutine leaks
    17  // in the tests. Turn to off (false) when not in
    18  // use because it slows down each test by
    19  // 1 second to let the final goroutine
    20  // count stabilize after the test.
    21  const xtestLeakCheckOn = false
    22  
    23  // errWhere satisfies net.Error
    24  type errWhere struct {
    25  	msg   string
    26  	who   *IdleTimer
    27  	when  time.Time
    28  	where string
    29  }
    30  
    31  func newErrTimeout(msg string, who *IdleTimer) *errWhere {
    32  	return newErrWhere("timeout:"+msg, who)
    33  }
    34  
    35  var regexTestname = regexp.MustCompile(`Test[^\s\(]+`)
    36  
    37  type xtraTestState struct {
    38  	name                  string
    39  	numStartingGoroutines int
    40  }
    41  
    42  // Testbegin example:
    43  //
    44  // At the top of each test put this line:
    45  //
    46  //    defer xtestend(xtestbegin(t))
    47  //
    48  func xtestbegin(t *testing.T) *xtraTestState {
    49  	if xtestLeakCheckOn {
    50  		ct := testname()
    51  		return &xtraTestState{
    52  			name: ct,
    53  			numStartingGoroutines: runtime.NumGoroutine(),
    54  		}
    55  	}
    56  	return nil
    57  }
    58  
    59  func xtestend(x *xtraTestState) {
    60  	if xtestLeakCheckOn {
    61  		time.Sleep(time.Second)
    62  		endCount := runtime.NumGoroutine()
    63  		if endCount != x.numStartingGoroutines {
    64  			panic(fmt.Sprintf("test leaks goroutines: '%s': ended with %v >= started with %v",
    65  				x.name, endCount, x.numStartingGoroutines))
    66  		}
    67  	}
    68  }
    69  
    70  func testname() string {
    71  	s := stacktrace()
    72  	slc := regexTestname.FindAllString(s, -1)
    73  	n := len(slc)
    74  	if n == 0 {
    75  		return ""
    76  	}
    77  	return slc[n-1]
    78  }
    79  
    80  func stacktrace() string {
    81  	sz := 512
    82  	var stack []byte
    83  	for {
    84  		stack = make([]byte, sz)
    85  		nw := runtime.Stack(stack, false)
    86  		if nw >= sz {
    87  			sz = sz * 2
    88  		} else {
    89  			stack = stack[:nw]
    90  			break
    91  		}
    92  	}
    93  	return string(stack)
    94  }
    95  
    96  func newErrWhere(msg string, who *IdleTimer) *errWhere {
    97  	return &errWhere{msg: msg, who: who, when: time.Now()}
    98  }
    99  
   100  func newErrWhereWithStack(msg string, who *IdleTimer) *errWhere {
   101  	return &errWhere{msg: msg, who: who, when: time.Now(), where: stacktrace()}
   102  }
   103  
   104  func (e errWhere) Error() string {
   105  	return fmt.Sprintf("%s, from IdleTimer %p, generated at '%v'. stack='\n%v\n'",
   106  		e.msg, e.who, e.when, string(e.where))
   107  }
   108  
   109  func (e errWhere) Timeout() bool {
   110  	return strings.HasPrefix(e.msg, "timeout:")
   111  }
   112  
   113  func (e errWhere) Temporary() bool {
   114  	// Is the error temporary?
   115  	return true
   116  }