/
sync_test.go
128 lines (116 loc) · 2.77 KB
/
sync_test.go
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package i3
import (
"context"
"fmt"
"math/rand"
"os"
"os/exec"
"path/filepath"
"reflect"
"testing"
"github.com/BurntSushi/xgb/xproto"
"github.com/BurntSushi/xgbutil"
)
// TestSyncSubprocess runs in a process which has been started with
// DISPLAY= pointing to an Xvfb instance with i3 -c testdata/i3.config running.
func TestSyncSubprocess(t *testing.T) {
if os.Getenv("GO_WANT_XVFB") != "1" {
t.Skip("parent process")
}
xu, err := xgbutil.NewConn()
if err != nil {
t.Fatalf("NewConn: %v", err)
}
defer xu.Conn().Close()
// Create an X11 window
X := xu.Conn()
wid, err := xproto.NewWindowId(X)
if err != nil {
t.Fatal(err)
}
screen := xproto.Setup(X).DefaultScreen(X)
cookie := xproto.CreateWindowChecked(
X,
screen.RootDepth,
wid,
screen.Root,
0, // x
0, // y
1, // width
1, // height
0, // border width
xproto.WindowClassInputOutput,
screen.RootVisual,
xproto.CwBackPixel|xproto.CwEventMask,
[]uint32{ // values must be in the order defined by the protocol
0xffffffff,
xproto.EventMaskStructureNotify |
xproto.EventMaskKeyPress |
xproto.EventMaskKeyRelease})
if err := cookie.Check(); err != nil {
t.Fatal(err)
}
// Synchronize i3 with that X11 window
rnd := rand.Uint32()
resp, err := Sync(SyncRequest{
Rnd: rnd,
Window: uint32(wid),
})
if err != nil {
t.Fatal(err)
}
if got, want := resp.Success, true; got != want {
t.Fatalf("SyncResult.Success: got %v, want %v", got, want)
}
for {
ev, xerr := X.WaitForEvent()
if xerr != nil {
t.Fatalf("WaitEvent: got X11 error %v", xerr)
}
cm, ok := ev.(xproto.ClientMessageEvent)
if !ok {
t.Logf("ignoring non-ClientMessage %v", ev)
continue
}
if got, want := cm.Window, wid; got != want {
t.Errorf("sync ClientMessage.Window: got %v, want %v", got, want)
}
if got, want := cm.Data.Data32[:2], []uint32{uint32(wid), rnd}; !reflect.DeepEqual(got, want) {
t.Errorf("sync ClientMessage.Data: got %x, want %x", got, want)
}
break
}
}
func TestSync(t *testing.T) {
t.Parallel()
ctx, canc := context.WithCancel(context.Background())
defer canc()
_, DISPLAY, err := launchXvfb(ctx)
if err != nil {
t.Fatal(err)
}
abs, err := filepath.Abs("testdata/i3.config")
if err != nil {
t.Fatal(err)
}
wm := exec.CommandContext(ctx, "i3", "-c", abs, "-d", "all", fmt.Sprintf("--shmlog-size=%d", 5*1024*1024))
wm.Env = []string{
"DISPLAY=" + DISPLAY,
"PATH=" + os.Getenv("PATH"),
}
wm.Stderr = os.Stderr
if err := wm.Start(); err != nil {
t.Fatal(err)
}
cmd := exec.Command(os.Args[0], "-test.run=TestSyncSubprocess", "-test.v")
cmd.Env = []string{
"GO_WANT_XVFB=1",
"DISPLAY=" + DISPLAY,
"PATH=" + os.Getenv("PATH"),
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
t.Fatal(err.Error())
}
}