github.com/XiaoMi/Gaea@v1.2.5/util/mocks/pipeTest/pipeTest.go (about)

     1  package pipeTest
     2  
     3  import (
     4  	"bufio"
     5  	"github.com/stretchr/testify/require"
     6  	"net"
     7  	"sync"
     8  	"testing"
     9  )
    10  
    11  // ReplyMsgFuncType 回应函数的型态,测试时,当客户端或服务端接收到讯息时,可以利用此函数去建立回传讯息
    12  type ReplyMsgFuncType func([]uint8) []uint8
    13  
    14  // TestReplyMsgFunc ,目前是用于验证测试流程是否正确,在这里会处理常接收到什么讯息,要将下来跟着回应什么讯息
    15  // 每次的回应讯息为接收讯息加 1
    16  //     比如 当接收值为 1,就会回传值为 2 给对方
    17  //     比如 当接收值为 2,就会回传值为 3 给对方
    18  func TestReplyMsgFunc(data []uint8) []uint8 {
    19  	return []uint8{data[0] + 1} // 回应讯息为接收讯息加 1
    20  }
    21  
    22  // DcMocker 用来模拟数据库服务器的读取和回应的类
    23  type DcMocker struct {
    24  	t         *testing.T       // 单元测试的类
    25  	bufReader *bufio.Reader    // 有缓存的读取 (接收端)
    26  	bufWriter *bufio.Writer    // 有缓存的写入 (传送端)
    27  	connRead  net.Conn         // pipe 的读取连线 (接收端)
    28  	connWrite net.Conn         // pipe 的写入连线 (传送端)
    29  	wg        *sync.WaitGroup  // 在测试流程的操作边界等待
    30  	replyFunc ReplyMsgFuncType // 设定相对应的回应函数
    31  	err       error            // 错误
    32  }
    33  
    34  // NewDcServerClient 产生直连 DC 模拟双方对象,包含 客户端对象 和 服务端对象
    35  func NewDcServerClient(t *testing.T, reply ReplyMsgFuncType) (mockClient *DcMocker, mockServer *DcMocker) {
    36  	// 先产生两组 Pipe
    37  	read0, write0 := net.Pipe() // 第一组 Pipe
    38  	read1, write1 := net.Pipe() // 第二组 Pipe
    39  
    40  	// 产生客户端和服务端直连 DC 模拟双方对象,分别为 mockClient 和 mockServer
    41  	mockClient = NewDcMocker(t, read0, write1, reply) // 客户端
    42  	mockServer = NewDcMocker(t, read1, write0, reply) // 服务端
    43  
    44  	// 结束
    45  	return
    46  }
    47  
    48  // NewDcMocker 产生新的直连 dc 模拟对象
    49  func NewDcMocker(t *testing.T, connRead, connWrite net.Conn, reply ReplyMsgFuncType) *DcMocker {
    50  	return &DcMocker{
    51  		t:         t,                          // 单元测试的对象
    52  		bufReader: bufio.NewReader(connRead),  // 服务器的读取 (实现缓存)
    53  		bufWriter: bufio.NewWriter(connWrite), // 服务器的写入 (实现缓存)
    54  		connRead:  connRead,                   // pipe 的读取连线 (接收端)
    55  		connWrite: connWrite,                  // pipe 的写入连线 (传送端)
    56  		wg:        &sync.WaitGroup{},          // 在测试流程的操作边界等待
    57  		replyFunc: reply,                      // 设定相对应的回应函数
    58  	}
    59  }
    60  
    61  // GetConnRead 为获得直连 dc 模拟对象的读取连线
    62  func (dcM *DcMocker) GetConnRead() net.Conn {
    63  	return dcM.connRead
    64  }
    65  
    66  // GetConnWrite 为获得直连 dc 模拟对象的写入连线
    67  func (dcM *DcMocker) GetConnWrite() net.Conn {
    68  	return dcM.connWrite
    69  }
    70  
    71  // GetBufReader 为获得直连 dc 模拟对象的缓存读取
    72  func (dcM *DcMocker) GetBufReader() *bufio.Reader {
    73  	return dcM.bufReader
    74  }
    75  
    76  // GetBufWriter 为获得直连 dc 模拟对象的缓存写入
    77  func (dcM *DcMocker) GetBufWriter() *bufio.Writer {
    78  	return dcM.bufWriter
    79  }
    80  
    81  // OverwriteConnBufRead 为临时覆写取代直连 dc 模拟对象的 读取连线 connRead 或者是 缓存读取 bufReader
    82  func (dcM *DcMocker) OverwriteConnBufRead(connRead net.Conn, bufReader *bufio.Reader) error {
    83  	// 先进行修改
    84  	if connRead != nil {
    85  		dcM.connRead = connRead // 修改读取连线
    86  	}
    87  	if bufReader != nil {
    88  		dcM.bufReader = bufReader // 修改读取缓存
    89  	}
    90  
    91  	// 正确回传
    92  	return nil
    93  }
    94  
    95  // OverwriteConnBufWrite 为临时覆写取代直连 dc 模拟对象的 写入连线 connWrite 或者是 缓存写入 bufWriter
    96  func (dcM *DcMocker) OverwriteConnBufWrite(connWrite net.Conn, bufWriter *bufio.Writer) error {
    97  	// 如果 写入连线 connWrite 参数传入为空值时,则进行修改
    98  	if connWrite != nil {
    99  		dcM.connWrite = connWrite
   100  	}
   101  	// 如果 缓存写入 bufWriter 参数传入为空值时,则进行修改
   102  	if bufWriter != nil {
   103  		dcM.bufWriter = bufWriter
   104  	}
   105  
   106  	// 正确回传
   107  	return nil
   108  }
   109  
   110  // ResetDcMockers 为重置单一连线方向的直连 dc 模拟对象
   111  func (dcM *DcMocker) ResetDcMockers(otherSide *DcMocker) error {
   112  	// 重新建立全新两组 Pipe
   113  	newRead, newWrite := net.Pipe() // 第一组 Pipe
   114  
   115  	// 单方向的状况为 dcM 写入 Pipe,otherSide 读取 Pipe
   116  
   117  	// 先重置 发送讯息的那一方 部份
   118  	dcM.bufWriter = bufio.NewWriter(newWrite) // 服务器的回应 (实现缓存)
   119  	dcM.connWrite = newWrite                  // pipe 的写入连线
   120  	dcM.wg = &sync.WaitGroup{}                // 流程的操作边界
   121  
   122  	// 先重置 mockServer 部份
   123  	otherSide.bufReader = bufio.NewReader(newRead) // 服务器的读取 (实现缓存)
   124  	otherSide.connRead = newRead                   // pipe 的读取连线
   125  
   126  	// 正常回传
   127  	return nil
   128  }
   129  
   130  // SendOrReceiveMsg 为直连 dc 用来模拟接收或传入讯息
   131  // 比如客户端 "传送 Send" 讯息到服务端、客户端再 "接收 Receive" 服务端的回传讯息
   132  func (dcM *DcMocker) SendOrReceiveMsg(data []uint8) *DcMocker {
   133  	// dc 模拟开始
   134  	dcM.wg.Add(1) // 只要等待直到确认资料有写入 pipe
   135  
   136  	// 在这里执行 1传送讯息 或者是 2接收讯息
   137  	go func() {
   138  		// 执行写入工作
   139  		_, err := dcM.bufWriter.Write(data) // 写入资料到 pipe
   140  		err = dcM.bufWriter.Flush()         // 把缓存资料写进 pipe
   141  		require.Equal(dcM.t, err, nil)
   142  		err = dcM.connWrite.Close() // 资料写入完成,终结连线
   143  		require.Equal(dcM.t, err, nil)
   144  
   145  		// 写入工作完成
   146  		dcM.wg.Done()
   147  	}()
   148  
   149  	// 重复使用对象
   150  	return dcM
   151  }
   152  
   153  // UseAnonymousFuncSendMsg 使用匿名函式去傳送訊息
   154  func (dcM *DcMocker) UseAnonymousFuncSendMsg(customFunc func()) *DcMocker {
   155  	// dc 模拟开始
   156  	dcM.wg.Add(1) // 只要等待直到确认资料有写入 pipe
   157  
   158  	// 在这里执行 1传送讯息 或者是 2接收讯息
   159  	go func() {
   160  		customFunc()
   161  
   162  		// 写入工作完成
   163  		dcM.wg.Done()
   164  	}()
   165  
   166  	// 重复使用对象
   167  	return dcM
   168  }
   169  
   170  // ReplyMsg 为直连 dc 用来模拟回应数据,大部份接连 SendOrReceiveMsg 函数后执行
   171  func (dcM *DcMocker) ReplyMsg(otherSide *DcMocker) (msg []uint8) {
   172  	// 读取传送过来的讯息
   173  	b, _, err := otherSide.bufReader.ReadLine() // 由另一方接收传来的讯息
   174  	require.Equal(dcM.t, err, nil)
   175  
   176  	// 等待和确认资料已经写入 pipe
   177  	dcM.wg.Wait()
   178  
   179  	// 重置模拟对象
   180  	err = dcM.ResetDcMockers(otherSide)
   181  	require.Equal(dcM.t, err, nil)
   182  
   183  	// 回传回应讯息
   184  	if otherSide.replyFunc != nil {
   185  		msg = otherSide.replyFunc(b)
   186  	}
   187  
   188  	// 结束
   189  	return
   190  }
   191  
   192  // CheckArrivedMsg 是用于当模拟时,直连 dc 讯息传送到对方时,立刻对传送到的讯息进行查询,以方便后续的除错和检查
   193  func (dcM *DcMocker) CheckArrivedMsg(otherSide *DcMocker) (msg []uint8) {
   194  	// 读取传送过来的讯息
   195  	b, _, err := otherSide.bufReader.ReadLine() // 由另一方接收传来的讯息
   196  	require.Equal(dcM.t, err, nil)
   197  
   198  	// 等待和确认资料已经写入 pipe
   199  	dcM.wg.Wait()
   200  
   201  	// 重置模拟对象
   202  	err = dcM.ResetDcMockers(otherSide)
   203  	require.Equal(dcM.t, err, nil)
   204  
   205  	// 回传回应讯息
   206  	msg = b
   207  
   208  	// 结束
   209  	return
   210  }
   211  
   212  // WaitAndReset 为直连 dc 用来等待在 Pipe 的整个数据读写操作完成
   213  func (dcM *DcMocker) WaitAndReset(otherSide *DcMocker) error {
   214  	// 先等待整个数据读写操作完成
   215  	dcM.wg.Wait()
   216  
   217  	// 单方向完成 Pipe 的连线重置
   218  	err := dcM.ResetDcMockers(otherSide)
   219  	require.Equal(dcM.t, err, nil)
   220  
   221  	// 正确回传
   222  	return nil
   223  }