github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discv5/sim_run_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:43</date>
    10  //</624342657300172800>
    11  
    12  
    13  package discv5
    14  
    15  import (
    16  	"bufio"
    17  	"bytes"
    18  	"encoding/binary"
    19  	"errors"
    20  	"fmt"
    21  	"io"
    22  	"os"
    23  	"os/exec"
    24  	"runtime"
    25  	"strings"
    26  	"testing"
    27  )
    28  
    29  func getnacl() (string, error) {
    30  	switch runtime.GOARCH {
    31  	case "amd64":
    32  		_, err := exec.LookPath("sel_ldr_x86_64")
    33  		return "amd64p32", err
    34  	case "i386":
    35  		_, err := exec.LookPath("sel_ldr_i386")
    36  		return "i386", err
    37  	default:
    38  		return "", errors.New("nacl is not supported on " + runtime.GOARCH)
    39  	}
    40  }
    41  
    42  //runwithplaygroundtime执行调用方
    43  //在启用faketime的nacl沙盒中。
    44  //
    45  //必须从test*函数调用此函数
    46  //当ishost为true时,调用方必须跳过实际测试。
    47  func runWithPlaygroundTime(t *testing.T) (isHost bool) {
    48  	if runtime.GOOS == "nacl" {
    49  		return false
    50  	}
    51  
    52  //打电话给对方。
    53  	callerPC, _, _, ok := runtime.Caller(1)
    54  	if !ok {
    55  		panic("can't get caller")
    56  	}
    57  	callerFunc := runtime.FuncForPC(callerPC)
    58  	if callerFunc == nil {
    59  		panic("can't get caller")
    60  	}
    61  	callerName := callerFunc.Name()[strings.LastIndexByte(callerFunc.Name(), '.')+1:]
    62  	if !strings.HasPrefix(callerName, "Test") {
    63  		panic("must be called from witin a Test* function")
    64  	}
    65  	testPattern := "^" + callerName + "$"
    66  
    67  //不幸的是,runtime.faketime(操场时间模式)只在nacl上工作。氯化钠
    68  //必须安装sdk并将其链接到路径才能使其工作。
    69  	arch, err := getnacl()
    70  	if err != nil {
    71  		t.Skip(err)
    72  	}
    73  
    74  //使用nacl编译并运行调用测试。
    75  //额外的标签确保使用了sim_main_test.go中的test main功能。
    76  	cmd := exec.Command("go", "test", "-v", "-tags", "faketime_simulation", "-timeout", "100h", "-run", testPattern, ".")
    77  	cmd.Env = append([]string{"GOOS=nacl", "GOARCH=" + arch}, os.Environ()...)
    78  	stdout, _ := cmd.StdoutPipe()
    79  	stderr, _ := cmd.StderrPipe()
    80  	go skipPlaygroundOutputHeaders(os.Stdout, stdout)
    81  	go skipPlaygroundOutputHeaders(os.Stderr, stderr)
    82  	if err := cmd.Run(); err != nil {
    83  		t.Error(err)
    84  	}
    85  
    86  //确保测试功能不会在(非Nacl)主机进程中运行。
    87  	return true
    88  }
    89  
    90  func skipPlaygroundOutputHeaders(out io.Writer, in io.Reader) {
    91  //附加输出可以不打印标题
    92  //在Nacl二进制文件开始运行之前(例如编译器错误消息)。
    93  	bufin := bufio.NewReader(in)
    94  	output, err := bufin.ReadBytes(0)
    95  	output = bytes.TrimSuffix(output, []byte{0})
    96  	if len(output) > 0 {
    97  		out.Write(output)
    98  	}
    99  	if err != nil {
   100  		return
   101  	}
   102  	bufin.UnreadByte()
   103  
   104  //回放头:0 0 p b<8字节时间><4字节数据长度>
   105  	head := make([]byte, 4+8+4)
   106  	for {
   107  		if _, err := io.ReadFull(bufin, head); err != nil {
   108  			if err != io.EOF {
   109  				fmt.Fprintln(out, "read error:", err)
   110  			}
   111  			return
   112  		}
   113  		if !bytes.HasPrefix(head, []byte{0x00, 0x00, 'P', 'B'}) {
   114  			fmt.Fprintf(out, "expected playback header, got %q\n", head)
   115  			io.Copy(out, bufin)
   116  			return
   117  		}
   118  //将数据复制到下一个标题。
   119  		size := binary.BigEndian.Uint32(head[12:])
   120  		io.CopyN(out, bufin, int64(size))
   121  	}
   122  }
   123