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 }