1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package journal_test
19
20 import (
21 "fmt"
22 "os"
23 "os/exec"
24 "syscall"
25 "testing"
26
27 "github.com/coreos/go-systemd/v22/journal"
28 )
29
30 func TestJournalStreamParsing(t *testing.T) {
31 if _, ok := os.LookupEnv("JOURNAL_STREAM"); ok {
32 t.Fatal("unset JOURNAL_STREAM before running this test")
33 }
34
35 t.Run("Missing", func(t *testing.T) {
36 ok, err := journal.StderrIsJournalStream()
37 if err != nil {
38 t.Fatal(err)
39 }
40 if ok {
41 t.Error("stderr shouldn't be connected to journal stream")
42 }
43 })
44 t.Run("Present", func(t *testing.T) {
45 f, stat := getUnixStreamSocket(t)
46 defer f.Close()
47 os.Setenv("JOURNAL_STREAM", fmt.Sprintf("%d:%d", stat.Dev, stat.Ino))
48 defer os.Unsetenv("JOURNAL_STREAM")
49 replaceStderr(int(f.Fd()), func() {
50 ok, err := journal.StderrIsJournalStream()
51 if err != nil {
52 t.Fatal(err)
53 }
54 if !ok {
55 t.Error("stderr should've been connected to journal stream")
56 }
57 })
58 })
59 t.Run("NotMatching", func(t *testing.T) {
60 f, stat := getUnixStreamSocket(t)
61 defer f.Close()
62 os.Setenv("JOURNAL_STREAM", fmt.Sprintf("%d:%d", stat.Dev+1, stat.Ino))
63 defer os.Unsetenv("JOURNAL_STREAM")
64 replaceStderr(int(f.Fd()), func() {
65 ok, err := journal.StderrIsJournalStream()
66 if err != nil {
67 t.Fatal(err)
68 }
69 if ok {
70 t.Error("stderr shouldn't be connected to journal stream")
71 }
72 })
73 })
74 t.Run("Malformed", func(t *testing.T) {
75 f, stat := getUnixStreamSocket(t)
76 defer f.Close()
77 os.Setenv("JOURNAL_STREAM", fmt.Sprintf("%d-%d", stat.Dev, stat.Ino))
78 defer os.Unsetenv("JOURNAL_STREAM")
79 replaceStderr(int(f.Fd()), func() {
80 _, err := journal.StderrIsJournalStream()
81 if err == nil {
82 t.Fatal("JOURNAL_STREAM is malformed, but no error returned")
83 }
84 })
85 })
86 }
87
88 func TestStderrIsJournalStream(t *testing.T) {
89 const (
90 message = "TEST_MESSAGE"
91 )
92
93 userOrSystem := "--user"
94 if os.Getuid() == 0 {
95 userOrSystem = "--system"
96 }
97
98 if _, ok := os.LookupEnv("JOURNAL_STREAM"); !ok {
99
100
101 args := []string{
102 "systemd-run",
103 userOrSystem,
104 "--wait",
105 "--quiet",
106 "--",
107 os.Args[0],
108 "-test.run=TestStderrIsJournalStream",
109 "-test.count=1",
110 }
111
112 cmd := exec.Command(args[0], args[1:]...)
113 cmd.Stderr = os.Stderr
114 if err := cmd.Run(); err != nil {
115 t.Fatal(err)
116 }
117 } else {
118 ok, err := journal.StderrIsJournalStream()
119 if err != nil {
120 t.Fatal(err)
121 }
122 if !ok {
123 t.Fatal("StderrIsJournalStream should've returned true")
124 }
125
126 err = journal.Send(message, journal.PriInfo, nil)
127 if err != nil {
128 t.Fatal(err)
129 }
130 }
131 }
132
133 func ExampleStderrIsJournalStream() {
134
135
136
137 ok, err := journal.StderrIsJournalStream()
138 if err != nil {
139 panic(err)
140 }
141
142 if ok {
143
144 journal.Send("this is a message logged through the native protocol", journal.PriInfo, nil)
145 } else {
146
147 fmt.Fprintln(os.Stderr, "this is a message logged through stderr")
148 }
149 }
150
151 func replaceStderr(fd int, cb func()) {
152 savedStderr, err := syscall.Dup(syscall.Stderr)
153 if err != nil {
154 panic(err)
155 }
156 defer syscall.Close(savedStderr)
157 err = syscall.Dup2(fd, syscall.Stderr)
158 if err != nil {
159 panic(err)
160 }
161 defer func() {
162 err := syscall.Dup2(savedStderr, syscall.Stderr)
163 if err != nil {
164 panic(err)
165 }
166 }()
167 cb()
168 }
169
170
171
172
173
174 func getUnixStreamSocket(t *testing.T) (*os.File, *syscall.Stat_t) {
175 fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
176 if err != nil {
177 t.Fatal(os.NewSyscallError("socketpair", err))
178 }
179
180 syscall.Close(fds[1])
181
182 file := os.NewFile(uintptr(fds[0]), "unix-stream")
183 stat, err := file.Stat()
184 if err != nil {
185 t.Fatal(err)
186 }
187 return file, stat.Sys().(*syscall.Stat_t)
188 }
189
View as plain text