github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/discv5/sim_run_test.go (about)

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