@@ -19,14 +19,17 @@ import (
1919)
2020
2121func logResponseV5 (t * testing.T , r * Response ) {
22- now := time .Now ()
22+ now := time .Now (). Local ()
2323 t .Logf ("[%s] Version: %d" , host , r .Version )
2424 t .Logf ("[%s] ClockOffset: %s" , host , r .ClockOffset )
2525 t .Logf ("[%s] RTT: %s" , host , r .RTT )
2626 t .Logf ("[%s] Correction: %s" , host , fmtCorrection (r .Correction ))
2727 t .Logf ("[%s] SystemTime: %s" , host , fmtTime (now ))
2828 t .Logf ("[%s] ~TrueTime: %s" , host , fmtTime (now .Add (r .ClockOffset )))
29- t .Logf ("[%s] XmitTime: %s" , host , fmtTime (r .Time ))
29+ t .Logf ("[%s] ClientXmit: %s" , host , fmtTime (r .Timestamps .ClientXmit ))
30+ t .Logf ("[%s] ServerRecv: %s" , host , fmtTime (r .Timestamps .ServerRecv ))
31+ t .Logf ("[%s] ServerXmit: %s" , host , fmtTime (r .Timestamps .ServerXmit ))
32+ t .Logf ("[%s] ClientRecv: %s" , host , fmtTime (r .Timestamps .ClientRecv ))
3033 t .Logf ("[%s] Stratum: %d" , host , r .Stratum )
3134 t .Logf ("[%s] Leap: %s" , host , fmtLeapIndicator (r .Leap ))
3235 t .Logf ("[%s] Flags: %s" , host , fmtResponseFlags (r .Flags ))
@@ -352,29 +355,6 @@ func TestOfflineV5DraftIDExtension(t *testing.T) {
352355 assert .True (t , bytes .Contains (data [4 :], []byte (draftID )), "Extension should contain draft ID string" )
353356}
354357
355- func TestOfflineV5BuildRequest (t * testing.T ) {
356- opt := & QueryOptions {
357- Version : 5 ,
358- Timescale : TimescaleUTC ,
359- }
360-
361- clientCookie := uint64 (0x1234567890abcdef )
362- buf , err := buildV5Request (opt , clientCookie )
363- require .NoError (t , err )
364- require .NotNil (t , buf )
365- require .NotZero (t , clientCookie )
366-
367- data := buf .Bytes ()
368- require .GreaterOrEqual (t , len (data ), msgSize )
369-
370- m , err := parseV5Response (data )
371- require .NoError (t , err )
372- assert .Equal (t , 5 , m .getVersion ())
373- assert .Equal (t , requestMode , m .getMode ())
374- assert .Equal (t , clientCookie , m .ClientCookie )
375- assert .Equal (t , uint8 (TimescaleUTC ), m .Timescale )
376- }
377-
378358func TestOfflineV5ParseMsg (t * testing.T ) {
379359 m := & messageV5 {
380360 Stratum : 2 ,
@@ -385,13 +365,13 @@ func TestOfflineV5ParseMsg(t *testing.T) {
385365 Timescale : 0 ,
386366 Era : 0 ,
387367 Flags : flagSynchronized ,
388- ServerCookie : 0x1234567890ABCDEF ,
368+ ServerCookie : 0x1234567890abcdef ,
389369 ClientCookie : 0xFEDCBA0987654321 ,
390370 ReceiveTime : 1 << 32 , // 1 second
391371 TransmitTime : 2 << 32 , // 2 seconds
392372 }
393373 m .setVersion (5 )
394- m .setMode (requestMode )
374+ m .setMode (responseMode )
395375 m .setLeap (LeapNoWarning )
396376
397377 buf := new (bytes.Buffer )
@@ -412,7 +392,7 @@ func TestOfflineV5ParseMsg(t *testing.T) {
412392 parsed , err := parseV5Response (buf .Bytes ())
413393 require .NoError (t , err )
414394 assert .Equal (t , 5 , parsed .getVersion ())
415- assert .Equal (t , requestMode , parsed .getMode ())
395+ assert .Equal (t , responseMode , parsed .getMode ())
416396 assert .Equal (t , LeapNoWarning , parsed .getLeap ())
417397 assert .Equal (t , uint8 (2 ), parsed .Stratum )
418398 assert .Equal (t , int8 (6 ), parsed .Poll )
@@ -424,35 +404,70 @@ func TestOfflineV5ParseMsg(t *testing.T) {
424404 assert .True (t , parsed .Flags & flagSynchronized != 0 )
425405}
426406
427- // mockV5Server creates a mock connection that echoes the client cookie.
428- type mockV5Server struct {
407+ func TestOfflineV5QueryMock (t * testing.T ) {
408+ conn := & mockV5Conn {
409+ stratum : 2 ,
410+ serverCookie : 0x1234567890abcdef ,
411+ }
412+
413+ opt := QueryOptions {
414+ Version : 5 ,
415+ Timescale : TimescaleTAI ,
416+ GetSystemTime : time .Now ,
417+ Dialer : func (network , address string ) (net.Conn , error ) {
418+ return conn , nil
419+ },
420+ }
421+
422+ r , err := QueryWithOptions ("mock.example.com" , opt )
423+ require .NoError (t , err )
424+ require .NotNil (t , r )
425+ assert .Equal (t , 5 , r .Version )
426+ assert .Equal (t , conn .stratum , r .Stratum )
427+ assert .Equal (t , LeapNoWarning , r .Leap )
428+ assert .True (t , r .Flags & flagSynchronized != 0 )
429+ assert .False (t , r .Flags & flagInterleaved != 0 )
430+ assert .False (t , r .Flags & flagAuthNAK != 0 )
431+ assert .Equal (t , TimescaleTAI , r .Timescale )
432+ assert .Equal (t , uint8 (0 ), r .Era )
433+ assert .Equal (t , conn .serverCookie , r .ServerCookie )
434+ assert .True (t , conn .closed )
435+ }
436+
437+ // mockV5Conn is a mock connection used to simulate a simple NTP exchange.
438+ type mockV5Conn struct {
429439 stratum uint8
430440 serverCookie uint64
431441 request []byte
432442 closed bool
433443}
434444
435- func (s * mockV5Server ) Read (b []byte ) (n int , err error ) {
436- if len (s .request ) < msgSize {
445+ func (c * mockV5Conn ) Read (b []byte ) (n int , err error ) {
446+ if c .closed {
447+ return 0 , fmt .Errorf ("read from closed connection" )
448+ }
449+ if len (c .request ) < msgSize {
437450 return 0 , ErrInvalidTime
438451 }
439- requestMsg , _ := parseV5Response (s .request )
440452
441453 now := time .Now ()
442454 serverRecv := toTimestamp (now )
443- serverXmit := toTimestamp (now .Add (1 * time .Millisecond ))
455+ serverXmit := toTimestamp (now .Add (10 * time .Millisecond ))
456+
457+ timescale := c .request [12 ]
458+ clientCookie := binary .BigEndian .Uint64 (c .request [24 :32 ])
444459
445460 responseMsg := & messageV5 {
446- Stratum : s .stratum ,
461+ Stratum : c .stratum ,
447462 Poll : 6 ,
448463 Precision : - 20 ,
449464 RootDelay : toTimeShortV5 (50 * time .Millisecond ),
450465 RootDisp : toTimeShortV5 (10 * time .Millisecond ),
451- Timescale : 0 ,
466+ Timescale : timescale ,
452467 Era : 0 ,
453468 Flags : flagSynchronized ,
454- ServerCookie : s .serverCookie ,
455- ClientCookie : requestMsg . ClientCookie , // Echo the client cookie
469+ ServerCookie : c .serverCookie ,
470+ ClientCookie : clientCookie ,
456471 ReceiveTime : serverRecv ,
457472 TransmitTime : serverXmit ,
458473 }
@@ -479,45 +494,23 @@ func (s *mockV5Server) Read(b []byte) (n int, err error) {
479494 return buf .Len (), nil
480495}
481496
482- func (s * mockV5Server ) Write (b []byte ) (n int , err error ) {
483- s .request = make ([]byte , len (b ))
484- copy (s .request , b )
497+ func (c * mockV5Conn ) Write (b []byte ) (n int , err error ) {
498+ if c .closed {
499+ return 0 , fmt .Errorf ("write to closed connection" )
500+ }
501+
502+ c .request = make ([]byte , len (b ))
503+ copy (c .request , b )
485504 return len (b ), nil
486505}
487506
488- func (s * mockV5Server ) Close () error {
489- s .closed = true
507+ func (c * mockV5Conn ) Close () error {
508+ c .closed = true
490509 return nil
491510}
492511
493- func (s * mockV5Server ) LocalAddr () net.Addr { return nil }
494- func (s * mockV5Server ) RemoteAddr () net.Addr { return nil }
495- func (s * mockV5Server ) SetDeadline (t time.Time ) error { return nil }
496- func (s * mockV5Server ) SetReadDeadline (t time.Time ) error { return nil }
497- func (s * mockV5Server ) SetWriteDeadline (t time.Time ) error { return nil }
498-
499- func TestOfflineV5QueryMock (t * testing.T ) {
500- mockServer := & mockV5Server {
501- stratum : 2 ,
502- serverCookie : 0x1234567890ABCDEF ,
503- }
504-
505- opt := & QueryOptions {
506- Version : 5 ,
507- Timeout : 5 * time .Second ,
508- GetSystemTime : time .Now ,
509- }
510-
511- resp , err := queryV5 (mockServer , opt )
512- require .NoError (t , err )
513- require .NotNil (t , resp )
514- assert .Equal (t , 5 , resp .Version )
515- assert .Equal (t , uint8 (2 ), resp .Stratum )
516- assert .Equal (t , LeapNoWarning , resp .Leap )
517- assert .True (t , resp .Flags & flagSynchronized != 0 )
518- assert .False (t , resp .Flags & flagInterleaved != 0 )
519- assert .Equal (t , TimescaleUTC , resp .Timescale )
520- assert .Equal (t , uint8 (0 ), resp .Era )
521- assert .Equal (t , uint64 (0x1234567890ABCDEF ), resp .ServerCookie )
522- assert .False (t , mockServer .closed )
523- }
512+ func (c * mockV5Conn ) LocalAddr () net.Addr { return nil }
513+ func (c * mockV5Conn ) RemoteAddr () net.Addr { return nil }
514+ func (c * mockV5Conn ) SetDeadline (t time.Time ) error { return nil }
515+ func (c * mockV5Conn ) SetReadDeadline (t time.Time ) error { return nil }
516+ func (c * mockV5Conn ) SetWriteDeadline (t time.Time ) error { return nil }
0 commit comments