github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/ntpdate/ntpdate_test.go (about) 1 // Copyright 2017-2021 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ntpdate 6 7 import ( 8 "bufio" 9 "errors" 10 "reflect" 11 "strings" 12 "testing" 13 "time" 14 ) 15 16 var configFileTests = []struct { 17 config string 18 out []string 19 }{ 20 { 21 config: "", 22 out: []string{}, 23 }, 24 { 25 config: "server 127.0.0.1", 26 out: []string{"127.0.0.1"}, 27 }, 28 { 29 config: "server 127.0.0.1\n", 30 out: []string{"127.0.0.1"}, 31 }, 32 { 33 config: "servers 127.0.0.1", 34 out: []string{}, 35 }, 36 { 37 config: "server time.google.com", 38 out: []string{"time.google.com"}, 39 }, 40 { 41 config: "server 127.0.0.1\n" + 42 "server time.google.com", 43 out: []string{"127.0.0.1", "time.google.com"}, 44 }, 45 { 46 config: "servers 127.0.0.1\n" + 47 "server time.google.com", 48 out: []string{"time.google.com"}, 49 }, 50 } 51 52 func TestConfigParsing(t *testing.T) { 53 for _, tt := range configFileTests { 54 b := bufio.NewReader(strings.NewReader(tt.config)) 55 out := parseServers(b) 56 57 if len(out) != len(tt.out) { 58 t.Errorf(`len(%v) = %d, want %d`, out, len(out), len(tt.out)) 59 } 60 61 for i := range out { 62 if out[i] != tt.out[i] { 63 t.Errorf(`out[%d] = %v, want %v`, i, out[i], tt.out[i]) 64 } 65 } 66 } 67 } 68 69 var getTimeTests = []struct { 70 servers []string 71 time time.Time 72 err string 73 }{ 74 { 75 servers: []string{}, 76 err: "unable to get any time from servers", 77 }, 78 { 79 servers: []string{"nope.nothing.here"}, 80 err: "unable to get any time from servers", 81 }, 82 { 83 servers: []string{"nope.nothing.here", "nope.nothing.here2"}, 84 err: "unable to get any time from servers", 85 }, 86 } 87 88 func TestGetNoTime(t *testing.T) { 89 for _, tt := range getTimeTests { 90 _, s, err := getTime(tt.servers) 91 if err == nil || s != "" { 92 t.Errorf(`getTime(%v) = _, %q, %v, want "", not nil`, tt.servers, s, err) 93 } 94 if match := strings.HasPrefix(err.Error(), tt.err); !match { 95 t.Errorf(`strings.HasPrefix(%q, %v) = %t, want true`, err.Error(), tt.err, match) 96 } 97 } 98 } 99 100 type mockGetterSetter struct { 101 getTimeCalls int 102 getTimeArg []string 103 getTimeResult time.Time 104 getTimeResultServer string 105 setSystemTimeCalls int 106 setSystemTimeArg time.Time 107 setSystemTimeResult error 108 setRTCTimeCalls int 109 setRTCTimeArg time.Time 110 setRTCTimeResult error 111 } 112 113 func (mgs *mockGetterSetter) GetTime(servers []string) (time.Time, string, error) { 114 mgs.getTimeCalls++ 115 mgs.getTimeArg = servers 116 if mgs.getTimeResult.Equal(time.Time{}) { 117 return mgs.getTimeResult, "", errors.New("ASPLODE") 118 } 119 return mgs.getTimeResult, mgs.getTimeResultServer, nil 120 } 121 122 func (mgs *mockGetterSetter) SetSystemTime(t time.Time) error { 123 mgs.setSystemTimeCalls++ 124 mgs.setSystemTimeArg = t 125 return mgs.setSystemTimeResult 126 } 127 128 func (mgs *mockGetterSetter) SetRTCTime(t time.Time) error { 129 mgs.setRTCTimeCalls++ 130 mgs.setRTCTimeArg = t 131 return mgs.setRTCTimeResult 132 } 133 134 func TestSetTime(t *testing.T) { 135 { // No args, no config, no fallback - fail 136 m := &mockGetterSetter{} 137 server, offset, err := setTime(nil, "", "", true, m) 138 if err == nil { 139 t.Fatalf(`setTime(nil, "", "", true, %v) = _, _, %v, want not nil`, m, err) 140 } 141 if match := strings.Contains(err.Error(), "no servers"); !match { 142 t.Errorf(`strings.Contains(%q, "no servers") = %t, want true`, err.Error(), match) 143 } 144 if server != "" || offset != 0.0 { 145 t.Errorf(`setTime(nil, "", "", true, %v) = %q, %f, _, want "", 0.0`, m, server, offset) 146 } 147 if m.getTimeCalls != 0 || m.setSystemTimeCalls != 0 || m.setRTCTimeCalls != 0 { 148 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls = %d, %d, %d, want 0, 0, 0`, 149 m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls) 150 } 151 } 152 { // Servers from cmd line first, then config, no fallback 153 ts := time.Now() 154 m := &mockGetterSetter{ 155 getTimeResult: ts, 156 getTimeResultServer: "foo", 157 } 158 server, offset, err := setTime([]string{"foo", "bar"}, "testdata/ntp.conf", "unused", false, m) 159 if err != nil || server != "foo" || offset == 0.0 { 160 t.Errorf(`setTime([]string{"foo", "bar"}, "testdata/ntp.conf", "unused", false, %v) = %q, %f, %v, want "foo", not 0.0, nil`, 161 m, server, offset, err) 162 } 163 if m.getTimeCalls != 1 || m.setSystemTimeCalls != 1 { 164 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls = %d, %d, want 1, 1`, m.getTimeCalls, m.setSystemTimeCalls) 165 } 166 if match := reflect.DeepEqual([]string{"foo", "bar", "s1", "s2"}, m.getTimeArg); !match { 167 t.Errorf(`reflect.DeepEqual([]string{"foo", "bar", "s1", "s2"}, %v) = %t, want true`, m.getTimeArg, match) 168 } 169 if m.setSystemTimeArg != ts || m.setRTCTimeCalls != 0 { 170 t.Errorf(`m.setSystemTimeArg, m.setRTCTimeCalls = %v, %d, want %v, 0`, m.setSystemTimeArg, m.setRTCTimeCalls, ts) 171 } 172 } 173 { // Servers from config only, no fallback. Also sets RTC. 174 ts := time.Now() 175 m := &mockGetterSetter{ 176 getTimeResult: ts, 177 getTimeResultServer: "bar", 178 } 179 server, offset, err := setTime(nil, "testdata/ntp.conf", "unused", true, m) 180 if err != nil || server != "bar" || offset == 0.0 { 181 t.Errorf(`setTime(nil, "testdata/ntp.conf", "unused", true, %v) = %q, %f, %v, want "bar", not 0.0, nil`, 182 m, server, offset, err) 183 } 184 if m.getTimeCalls != 1 || m.setSystemTimeCalls != 1 || m.setRTCTimeCalls != 1 { 185 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls = %d, %d, %d, want 1, 1, 1`, 186 m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls) 187 } 188 if match := reflect.DeepEqual([]string{"s1", "s2"}, m.getTimeArg); !match { 189 t.Errorf(`reflect.DeepEqual([]string{"s1", "s2"}, %v) = %t, want true`, m.getTimeArg, match) 190 } 191 if m.setSystemTimeArg != ts || m.setRTCTimeArg != ts { 192 t.Errorf(`m.setSystemTimeArg, m.setRTCTimeArg = %v, %v, want %v, %v`, m.setSystemTimeArg, m.setRTCTimeArg, ts, ts) 193 } 194 } 195 { // Servers from cmdline only, no fallback. 196 ts := time.Now() 197 m := &mockGetterSetter{ 198 getTimeResult: ts, 199 getTimeResultServer: "foo", 200 } 201 server, offset, err := setTime([]string{"foo", "bar"}, "", "unused", false, m) 202 if err != nil || server != "foo" || offset == 0.0 { 203 t.Errorf(`setTime([]string{"foo", "bar"}, "", "unused", false, %v) = %q, %f, %v, want "foo", not 0.0, nil`, 204 m, server, offset, err) 205 } 206 if m.getTimeCalls != 1 || m.setSystemTimeCalls != 1 { 207 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls = %d, %d, want 1, 1`, m.getTimeCalls, m.setSystemTimeCalls) 208 } 209 if match := reflect.DeepEqual([]string{"foo", "bar"}, m.getTimeArg); !match { 210 t.Errorf(`reflect.DeepEqual([]string{"foo", "bar"}, %v) = %t, want true`, m.getTimeArg, match) 211 } 212 if m.setSystemTimeArg != ts || m.setRTCTimeCalls != 0 { 213 t.Errorf(`m.setSystemTimeArg, m.setRTCTimeCalls = %v, %d, want %v, 0`, m.setSystemTimeArg, m.setRTCTimeCalls, ts) 214 } 215 } 216 { // Config not found, fallback is used. 217 ts := time.Now() 218 m := &mockGetterSetter{ 219 getTimeResult: ts, 220 getTimeResultServer: "HALP", 221 } 222 server, offset, err := setTime(nil, "testdata/nosuch.conf", "HALP", true, m) 223 if err != nil || server != "HALP" || offset == 0.0 { 224 t.Errorf(`setTime(nil, "testdata/nosuch.conf", "HALP", true, %v) = %q, %f, %v, want "HALP", not 0.0, nil`, 225 m, server, offset, err) 226 } 227 if m.getTimeCalls != 1 || m.setSystemTimeCalls != 1 || m.setRTCTimeCalls != 1 { 228 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls = %d, %d, %d, want 1, 1, 1`, 229 m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls) 230 } 231 if match := reflect.DeepEqual([]string{"HALP"}, m.getTimeArg); !match { 232 t.Errorf(`reflect.DeepEqual([]string{"HALP"}, %v) = %t, want true`, m.getTimeArg, match) 233 } 234 if m.setSystemTimeArg != ts || m.setRTCTimeArg != ts { 235 t.Errorf(`m.setSystemTimeArg, m.setRTCTimeArg = %v, %v, want %v, %v`, m.setSystemTimeArg, m.setRTCTimeArg, ts, ts) 236 } 237 } 238 { // Get NTP time fails, set not attempted. 239 m := &mockGetterSetter{ 240 getTimeResult: time.Time{}, 241 } 242 server, offset, err := setTime([]string{"foo", "bar"}, "", "unused", true, m) 243 if err == nil || server != "" || offset != 0.0 { 244 t.Errorf(`setTime([]string{"foo", "bar"}, "", "unused", true, %v) = %q, %f, %v, want "", 0.0, not nil`, 245 m, server, offset, err) 246 } 247 if match := strings.Contains(err.Error(), "ASPLODE"); !match { 248 t.Errorf(`strings.Contains(%q, "ASPLODE") = %t, want true`, err.Error(), match) 249 } 250 if match := reflect.DeepEqual([]string{"foo", "bar"}, m.getTimeArg); !match { 251 t.Errorf(`reflect.DeepEqual([]string{"foo", "bar"}, %v) = %t, want true`, m.getTimeArg, match) 252 } 253 if m.getTimeCalls != 1 || m.setSystemTimeCalls != 0 || m.setRTCTimeCalls != 0 { 254 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls = %d, %d, %d, want 1, 0, 0`, 255 m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls) 256 } 257 } 258 { // Set system time fails, set RTC not attempted. 259 ts := time.Now() 260 m := &mockGetterSetter{ 261 getTimeResult: ts, 262 getTimeResultServer: "foo", 263 setSystemTimeResult: errors.New("ASPLODE"), 264 } 265 server, offset, err := setTime([]string{"foo", "bar"}, "", "unused", true, m) 266 if err == nil || server != "" || offset != 0.0 { 267 t.Errorf(`setTime([]string{"foo", "bar"}, "", "unused", true, %v) = %q, %f, %v, want "", 0.0, not nil`, 268 m, server, offset, err) 269 } 270 if match := strings.Contains(err.Error(), "ASPLODE"); !match { 271 t.Errorf(`strings.Contains(%q, "ASPLODE") = %t, want true`, err.Error(), match) 272 } 273 if match := reflect.DeepEqual([]string{"foo", "bar"}, m.getTimeArg); !match { 274 t.Errorf(`reflect.DeepEqual([]string{"foo", "bar"}, %v) = %t, want true`, m.getTimeArg, match) 275 } 276 if m.getTimeCalls != 1 || m.setSystemTimeCalls != 1 || m.setRTCTimeCalls != 0 { 277 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls = %d, %d, %d, want 1, 1, 0`, 278 m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls) 279 } 280 if !m.setSystemTimeArg.Equal(ts) { 281 t.Error("setSystemTimeArg is not correct") 282 } 283 if m.setSystemTimeArg != ts { 284 t.Errorf(`m.setSystemTimeArg, = %v, want %v`, m.setSystemTimeArg, ts) 285 } 286 } 287 { // Set RTC time fails. 288 ts := time.Now() 289 m := &mockGetterSetter{ 290 getTimeResult: ts, 291 getTimeResultServer: "foo", 292 setRTCTimeResult: errors.New("ASPLODE"), 293 } 294 server, offset, err := setTime([]string{"foo", "bar"}, "", "unused", true, m) 295 if err == nil || server != "" || offset != 0.0 { 296 t.Errorf(`setTime([]string{"foo", "bar"}, "", "unused", true, %v) = %q, %f, %v, want "", 0.0, not nil`, 297 m, server, offset, err) 298 } 299 if match := strings.Contains(err.Error(), "ASPLODE"); !match { 300 t.Errorf(`strings.Contains(%q, "ASPLODE") = %t, want true`, err.Error(), match) 301 } 302 if m.getTimeCalls != 1 || m.setSystemTimeCalls != 1 || m.setRTCTimeCalls != 1 { 303 t.Errorf(`m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls = %d, %d, %d, want 1, 1, 1`, 304 m.getTimeCalls, m.setSystemTimeCalls, m.setRTCTimeCalls) 305 } 306 if match := reflect.DeepEqual([]string{"foo", "bar"}, m.getTimeArg); !match { 307 t.Errorf(`reflect.DeepEqual([]string{"foo", "bar"}, %v) = %t, want true`, m.getTimeArg, match) 308 } 309 if m.setSystemTimeArg != ts || m.setRTCTimeArg != ts { 310 t.Errorf(`m.setSystemTimeArg, m.setRTCTimeArg = %v, %v, want %v, %v`, m.setSystemTimeArg, m.setRTCTimeArg, ts, ts) 311 } 312 } 313 }