-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathfake_server.go
More file actions
113 lines (97 loc) · 2.18 KB
/
Copy pathfake_server.go
File metadata and controls
113 lines (97 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package pgsnap
import (
"net"
"sync"
"testing"
"time"
"github.com/jackc/pgmock"
"github.com/jackc/pgproto3/v2"
)
type (
server struct {
t testing.TB
l net.Listener
done chan<- struct{}
isDebug bool
wg sync.WaitGroup
}
)
// newServer will create FakePostgresServer with errchan and donechan
func newServer(l net.Listener,
done chan<- struct{},
t testing.TB,
isDebug bool,
) *server {
return &server{
l: l,
done: done,
t: t,
isDebug: isDebug,
}
}
// Run will
func (s *server) Run(script *pgmock.Script) {
s.runFakePostgres(script)
}
func (s *server) Wait() {
s.wg.Wait()
}
func (s *server) runFakePostgres(script *pgmock.Script) {
s.wg.Add(1)
go s.acceptConnForScript(script)
}
func (s *server) acceptConnForScript(script *pgmock.Script) {
// need to defer this to make sure we send the done signal
defer func() {
s.debugLogf("server: finish script")
s.wg.Done()
s.done <- struct{}{}
}()
conn, err := s.l.Accept()
if err != nil {
s.t.Errorf("server: cannot accept connection: %v", err)
return
}
defer conn.Close()
s.debugLogf("server: accepted connection")
be := pgproto3.NewBackend(pgproto3.NewChunkReader(conn), conn)
s.debugLogf("server: run script")
if err := script.Run(be); err != nil {
s.t.Errorf("server: run script got error: %v", err)
s.waitTilSync(be)
s.sendError(be, err)
return
}
}
func (s *server) waitTilSync(be *pgproto3.Backend) {
for i := 0; i < 10; i++ {
msg, err := be.Receive()
if err != nil {
continue
}
_, ok := msg.(*pgproto3.Sync)
if ok {
break
}
}
}
func (s *server) sendError(be *pgproto3.Backend, postgresError error) {
err := be.Send(&pgproto3.ErrorResponse{
Severity: "ERROR",
SeverityUnlocalized: "ERROR",
Code: "99999",
Message: "pgsnap:\n" + postgresError.Error(),
})
if err != nil {
s.t.Errorf("BE send Error (%s) caused by %s", err, postgresError)
}
// ignore the error
_ = be.Send(&pgproto3.ReadyForQuery{TxStatus: 'I'})
}
func (s *server) debugLogf(format string, args ...interface{}) {
if s.isDebug {
s.t.Helper()
args = append([]interface{}{time.Now()}, args...)
s.t.Logf("%v: "+format, args...)
}
}