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  }