blob: 26c6d4ec84354ae15472514185060bff5f674c00 [file] [log] [blame]
Scott Bakeredb0ae12019-10-22 08:55:12 -07001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// This file implements an exit handler that tries to shut down all the
18// running servers before finally exiting. There are 2 triggers to this
19// clean exit thread: signals and an exit channel.
20
21package main
22
23import (
24 "fmt"
25 "github.com/phayes/freeport"
26 "github.com/stretchr/testify/assert"
27 "io/ioutil"
28 "os"
29 "testing"
30)
31
32// Generate a configuration, ensure any ports are randomly chosen free ports
33func MakeConfig() (string, error) {
34 freePort, err := freeport.GetFreePort()
35 if err != nil {
36 return "", err
37 }
38
39 config := fmt.Sprintf(`{
40 "api": {
41 "_comment": "If this isn't defined then no api is available for dynamic configuration and queries",
42 "address": "localhost",
43 "port": %d
44 }
45 }`, freePort)
46
47 return config, nil
48}
49
50// run the function fp() and return its return value and stdout
51func CaptureStdout(fp func() int) (int, string, error) {
52 origStdout := os.Stdout
53
54 // log.Cleanup() will call Sync on sys.stdout, and that doesn't
55 // work on pipes. Instead of creating a pipe, write the output
56 // to a file, then read that file back in.
57 f, err := ioutil.TempFile("", "arouter.json")
58 if err != nil {
59 return 0, "", err
60 }
61
62 // Make sure the file is closed and deleted on exit
63 defer func() { f.Close(); os.Remove(f.Name()) }()
64
65 // reassign stdout to the file, ensure it will be restored on exit
66 os.Stdout = f
67 defer func() { os.Stdout = origStdout }()
68
69 status := fp()
70
71 // read back the contents of the tempfile
72 _, err = f.Seek(0, 0)
73 if err != nil {
74 return 0, "", err
75 }
76 out := make([]byte, 16384)
77 numRead, err := f.Read(out)
78 if err != nil {
79 return 0, "", err
80 }
81
82 return status, string(out[:numRead]), nil
83}
84
85// Test output of "--version" command
86func TestStartupVersionOnly(t *testing.T) {
87 oldArgs := os.Args
88 defer func() { os.Args = oldArgs }()
89
90 config, err := MakeConfig()
91 assert.Nil(t, err)
92
93 f, err := ioutil.TempFile("", "arouter.json")
94 assert.Nil(t, err)
95 _, err = f.WriteString(config)
96 assert.Nil(t, err)
97 f.Close()
98
99 defer func() { os.Remove(f.Name()) }()
100
101 os.Args = []string{os.Args[0], "--version", "--config", f.Name()}
102
103 status, s, err := CaptureStdout(startup)
104 assert.Nil(t, err)
105
106 assert.Equal(t, 0, status)
107
108 expected := `VOLTHA API Server (afrouter)
109 Version: unknown-version
110 GoVersion: unknown-goversion
111 VCS Ref: unknown-vcsref
112 VCS Dirty: unknown-vcsdirty
113 Built: unknown-buildtime
114 OS/Arch: unknown-os/unknown-arch
115
116`
117 assert.Equal(t, expected, s)
118}
119
120func TestStartupMissingConfigFile(t *testing.T) {
121 oldArgs := os.Args
122 defer func() { os.Args = oldArgs }()
123
124 config, err := MakeConfig()
125 assert.Nil(t, err)
126
127 f, err := ioutil.TempFile("", "arouter.json")
128 assert.Nil(t, err)
129 _, err = f.WriteString(config)
130 assert.Nil(t, err)
131 f.Close()
132
133 defer func() { os.Remove(f.Name()) }()
134
135 os.Args = []string{os.Args[0], "--config", "doesnotexist"}
136
137 // The Voltha logger will write messages to stdout
138
139 status, s, err := CaptureStdout(startup)
140 assert.Nil(t, err)
141
142 assert.Equal(t, 1, status)
143
144 assert.Contains(t, s, "open doesnotexist: no such file or directory")
145}
146
147func TestStartupDryRun(t *testing.T) {
148 oldArgs := os.Args
149 defer func() { os.Args = oldArgs }()
150
151 config, err := MakeConfig()
152 assert.Nil(t, err)
153
154 f, err := ioutil.TempFile("", "arouter.json")
155 assert.Nil(t, err)
156 _, err = f.WriteString(config)
157 assert.Nil(t, err)
158 f.Close()
159
160 defer func() { os.Remove(f.Name()) }()
161
162 os.Args = []string{os.Args[0], "--dry-run", "--config", f.Name()}
163
164 status, s, err := CaptureStdout(startup)
165 assert.Nil(t, err)
166
167 assert.Equal(t, 0, status)
168
169 assert.Contains(t, s, "Configuration loaded")
170}
171
172func TestStartupDryRunGrpcLog(t *testing.T) {
173 oldArgs := os.Args
174 defer func() { os.Args = oldArgs }()
175
176 config, err := MakeConfig()
177 assert.Nil(t, err)
178
179 f, err := ioutil.TempFile("", "arouter.json")
180 assert.Nil(t, err)
181 _, err = f.WriteString(config)
182 assert.Nil(t, err)
183 f.Close()
184
185 defer func() { os.Remove(f.Name()) }()
186
187 os.Args = []string{os.Args[0], "--dry-run", "--grpclog", "--config", f.Name()}
188
189 status, s, err := CaptureStdout(startup)
190 assert.Nil(t, err)
191
192 assert.Equal(t, 0, status)
193
194 assert.Contains(t, s, "Configuration loaded")
195}
196
197// An unknown command-line option should produce an error
198func TestStartupBadCommandLine(t *testing.T) {
199 oldArgs := os.Args
200 defer func() { os.Args = oldArgs }()
201
202 config, err := MakeConfig()
203 assert.Nil(t, err)
204
205 f, err := ioutil.TempFile("", "arouter.json")
206 assert.Nil(t, err)
207 _, err = f.WriteString(config)
208 assert.Nil(t, err)
209 f.Close()
210
211 defer func() { os.Remove(f.Name()) }()
212
213 os.Args = []string{os.Args[0], "--dry-run", "--badoption", "--config", f.Name()}
214
215 status, s, err := CaptureStdout(startup)
216 assert.Nil(t, err)
217
218 assert.Equal(t, 1, status)
219
220 assert.Contains(t, s, "Error: Error parsing the command line")
221}
222
223// A config file with invalid contents should cause logging output of the error
224func TestStartupBadConfigFile(t *testing.T) {
225 oldArgs := os.Args
226 defer func() { os.Args = oldArgs }()
227
228 f, err := ioutil.TempFile("", "arouter.json")
229 assert.Nil(t, err)
230 _, err = f.WriteString("this is not proper json")
231 assert.Nil(t, err)
232 f.Close()
233
234 defer func() { os.Remove(f.Name()) }()
235
236 os.Args = []string{os.Args[0], "--dry-run", "--config", f.Name()}
237
238 status, s, err := CaptureStdout(startup)
239 assert.Nil(t, err)
240
241 assert.Equal(t, 1, status)
242
243 assert.Contains(t, s, "invalid character")
244}