github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/p2p/discv5/sim_run_test.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package discv5
    13  
    14  import (
    15  	"bufio"
    16  	"bytes"
    17  	"encoding/binary"
    18  	"errors"
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"os/exec"
    23  	"runtime"
    24  	"strings"
    25  	"testing"
    26  )
    27  
    28  func getnacl() (string, error) {
    29  	switch runtime.GOARCH {
    30  	case "amd64":
    31  		_, err := exec.LookPath("sel_ldr_x86_64")
    32  		return "amd64p32", err
    33  	case "i386":
    34  		_, err := exec.LookPath("sel_ldr_i386")
    35  		return "i386", err
    36  	default:
    37  		return "", errors.New("nacl is not supported on " + runtime.GOARCH)
    38  	}
    39  }
    40  
    41  // runWithPlaygroundTime executes the caller
    42  // in the NaCl sandbox with faketime enabled.
    43  //
    44  // This function must be called from a Test* function
    45  // and the caller must skip the actual test when isHost is true.
    46  func runWithPlaygroundTime(t *testing.T) (isHost bool) {
    47  	if runtime.GOOS == "nacl" {
    48  		return false
    49  	}
    50  
    51  	// Get the caller.
    52  	callerPC, _, _, ok := runtime.Caller(1)
    53  	if !ok {
    54  		panic("can't get caller")
    55  	}
    56  	callerFunc := runtime.FuncForPC(callerPC)
    57  	if callerFunc == nil {
    58  		panic("can't get caller")
    59  	}
    60  	callerName := callerFunc.Name()[strings.LastIndexByte(callerFunc.Name(), '.')+1:]
    61  	if !strings.HasPrefix(callerName, "Test") {
    62  		panic("must be called from witin a Test* function")
    63  	}
    64  	testPattern := "^" + callerName + "$"
    65  
    66  	// Unfortunately runtime.faketime (playground time mode) only works on NaCl. The NaCl
    67  	// SDK must be installed and linked into PATH for this to work.
    68  	arch, err := getnacl()
    69  	if err != nil {
    70  		t.Skip(err)
    71  	}
    72  
    73  	// Compile and run the calling test using NaCl.
    74  	// The extra tag ensures that the TestMain function in sim_main_test.go is used.
    75  	cmd := exec.Command("go", "test", "-v", "-tags", "faketime_simulation", "-timeout", "100h", "-run", testPattern, ".")
    76  	cmd.Env = append([]string{"GOOS=nacl", "GOARCH=" + arch}, os.Environ()...)
    77  	stdout, _ := cmd.StdoutPipe()
    78  	stderr, _ := cmd.StderrPipe()
    79  	go skipPlaygroundOutputHeaders(os.Stdout, stdout)
    80  	go skipPlaygroundOutputHeaders(os.Stderr, stderr)
    81  	if err := cmd.Run(); err != nil {
    82  		t.Error(err)
    83  	}
    84  
    85  	// Ensure that the test function doesn't run in the (non-NaCl) host process.
    86  	return true
    87  }
    88  
    89  func skipPlaygroundOutputHeaders(out io.Writer, in io.Reader) {
    90  	// Additional output can be printed without the headers
    91  	// before the NaCl binary starts running (e.g. compiler error messages).
    92  	bufin := bufio.NewReader(in)
    93  	output, err := bufin.ReadBytes(0)
    94  	output = bytes.TrimSuffix(output, []byte{0})
    95  	if len(output) > 0 {
    96  		out.Write(output)
    97  	}
    98  	if err != nil {
    99  		return
   100  	}
   101  	bufin.UnreadByte()
   102  
   103  	// Playback header: 0 0 P B <8-byte time> <4-byte data length>
   104  	head := make([]byte, 4+8+4)
   105  	for {
   106  		if _, err := io.ReadFull(bufin, head); err != nil {
   107  			if err != io.EOF {
   108  				fmt.Fprintln(out, "read error:", err)
   109  			}
   110  			return
   111  		}
   112  		if !bytes.HasPrefix(head, []byte{0x00, 0x00, 'P', 'B'}) {
   113  			fmt.Fprintf(out, "expected playback header, got %q\n", head)
   114  			io.Copy(out, bufin)
   115  			return
   116  		}
   117  		// Copy data until next header.
   118  		size := binary.BigEndian.Uint32(head[12:])
   119  		io.CopyN(out, bufin, int64(size))
   120  	}
   121  }