github.com/honeycombio/honeytail@v1.9.0/httime/httime_test.go (about)

     1  package httime
     2  
     3  import (
     4  	"math"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/honeycombio/honeytail/httime/httimetest"
     9  )
    10  
    11  func init() {
    12  	DefaultNower = &httimetest.FakeNower{}
    13  }
    14  
    15  func TestFormat(t *testing.T) {
    16  	tsts := []struct {
    17  		strftime string
    18  		expected string
    19  	}{
    20  		{"%Y-%m-%d %H:%M:%S", "2006-01-02 15:04:05"},
    21  		{"%Y-%m-%d %H:%M", "2006-01-02 15:04"},
    22  		{"%Y-%m-%d %k:%M", "2006-01-02 15:04"},
    23  		{"%m/%d/%y %I:%M %p", "01/02/06 03:04 PM"},
    24  		{"%m/%d/%y %I:%M %P%t%z", "01/02/06 03:04 pm\t-0700"},
    25  		{"%a %B %d %C %r", "Mon January 02 06 03:04:05 PM"},
    26  		{"%c %G %g %O %u %V %w %X", "       "},
    27  		{"%H:%M:%S.%f", "15:04:05.999"},
    28  	}
    29  
    30  	for _, tt := range tsts {
    31  		gotime := convertTimeFormat(tt.strftime)
    32  		if gotime != tt.expected {
    33  			t.Errorf("strftime format '%s' was parsed to go time '%s', expected '%s'",
    34  				tt.strftime, gotime, tt.expected)
    35  		}
    36  	}
    37  }
    38  
    39  type testTimestamp struct {
    40  	format        string         // the format this test's time is in
    41  	fieldName     string         // the field in the map containing the time
    42  	input         interface{}    // the value corresponding to the fieldName
    43  	tz            *time.Location // the expected time zone
    44  	auto          bool           // whether the input should be parsable even without specifying format/fieldName
    45  	expected      time.Time      // the expected time object to get back
    46  	diffThreshold time.Duration  // the epsilon for which different times are the same, to handle floats
    47  }
    48  
    49  var utc = time.UTC
    50  var pacific, _ = time.LoadLocation("America/Los_Angeles")
    51  
    52  var tts = []testTimestamp{
    53  	{
    54  		format:        "2006-01-02 15:04:05.999999999 -0700 MST",
    55  		fieldName:     "time",
    56  		input:         "2014-04-10 19:57:38.123456789 -0800 PST",
    57  		tz:            utc,
    58  		auto:          true,
    59  		expected:      time.Unix(1397188658, 123456789),
    60  		diffThreshold: 0,
    61  	},
    62  	{
    63  		format:        time.RFC3339Nano,
    64  		fieldName:     "timestamp",
    65  		input:         "2014-04-10T19:57:38.123456789-08:00",
    66  		tz:            utc,
    67  		auto:          true,
    68  		expected:      time.Unix(1397188658, 123456789),
    69  		diffThreshold: 0,
    70  	},
    71  	{
    72  		format:        time.RFC3339,
    73  		fieldName:     "Date",
    74  		input:         "2014-04-10T19:57:38-08:00",
    75  		tz:            utc,
    76  		auto:          true,
    77  		expected:      time.Unix(1397188658, 0),
    78  		diffThreshold: 0,
    79  	},
    80  	{
    81  		format:        time.RFC3339,
    82  		fieldName:     "Date",
    83  		input:         "2014-04-10T19:57:38Z",
    84  		tz:            utc,
    85  		auto:          true,
    86  		expected:      time.Unix(1397159858, 0),
    87  		diffThreshold: 0,
    88  	},
    89  	{
    90  		format:        time.RubyDate,
    91  		fieldName:     "datetime",
    92  		input:         "Thu Apr 10 19:57:38.123456789 -0800 2014",
    93  		tz:            utc,
    94  		auto:          true,
    95  		expected:      time.Unix(1397188658, 123456789),
    96  		diffThreshold: 0,
    97  	},
    98  	{
    99  		format:        "%Y-%m-%d %H:%M",
   100  		fieldName:     "time",
   101  		input:         "2014-07-30 07:02",
   102  		tz:            utc,
   103  		expected:      time.Unix(1406703720, 0),
   104  		diffThreshold: 0,
   105  	},
   106  	{
   107  		format:        "%Y-%m-%d %H:%M",
   108  		fieldName:     "time",
   109  		input:         "2014-07-30 07:02",
   110  		tz:            pacific,
   111  		expected:      time.Unix(1406728920, 0),
   112  		diffThreshold: 0,
   113  	},
   114  	{
   115  		format:        "%Y-%m-%d %k:%M", // check trailing space behavior
   116  		fieldName:     "time",
   117  		input:         "2014-07-30  7:02",
   118  		tz:            utc,
   119  		expected:      time.Unix(1406703720, 0),
   120  		diffThreshold: 0,
   121  	},
   122  	{
   123  		format:        "%Y-%m-%d %H:%M:%S",
   124  		fieldName:     "time",
   125  		input:         "2014-07-30 07:02:15",
   126  		tz:            utc,
   127  		expected:      time.Unix(1406703735, 0),
   128  		diffThreshold: 0,
   129  	},
   130  	{
   131  		format:        UnixTimestampFmt,
   132  		fieldName:     "time",
   133  		input:         "1440116565",
   134  		tz:            utc,
   135  		expected:      time.Unix(1440116565, 0),
   136  		diffThreshold: 0,
   137  	},
   138  	{
   139  		format:        UnixTimestampFmt,
   140  		fieldName:     "time",
   141  		input:         1440116565,
   142  		tz:            utc,
   143  		expected:      time.Unix(1440116565, 0),
   144  		diffThreshold: 0,
   145  	},
   146  	// millis
   147  	{
   148  		format:        UnixTimestampFmt,
   149  		fieldName:     "time",
   150  		input:         "1440116565.123",
   151  		tz:            utc,
   152  		expected:      time.Unix(1440116565, 123000000),
   153  		diffThreshold: time.Millisecond,
   154  	},
   155  	{
   156  		format:        UnixTimestampFmtAlt,
   157  		fieldName:     "time",
   158  		input:         "1440116565.123456",
   159  		tz:            utc,
   160  		expected:      time.Unix(1440116565, 123456000),
   161  		diffThreshold: time.Microsecond,
   162  	},
   163  	{
   164  		format:        UnixTimestampFmtTxt,
   165  		fieldName:     "time",
   166  		input:         "1440116565.12345678",
   167  		tz:            utc,
   168  		expected:      time.Unix(1440116565, 123456780),
   169  		diffThreshold: 100 * time.Nanosecond,
   170  	},
   171  	{
   172  		format:        "%Y-%m-%d %z",
   173  		input:         "2014-04-10 -0700",
   174  		tz:            utc,
   175  		fieldName:     "time",
   176  		expected:      time.Unix(1397113200, 0),
   177  		diffThreshold: 0,
   178  	},
   179  	{
   180  		format:        "",
   181  		input:         "1538860697500",
   182  		tz:            utc,
   183  		fieldName:     "timestamp",
   184  		expected:      time.Unix(1538860697, 500000000),
   185  		diffThreshold: 0,
   186  	},
   187  }
   188  
   189  func TestGetTimestampValid(t *testing.T) {
   190  	for i, tTimeSet := range tts {
   191  		Location = tTimeSet.tz
   192  		if tTimeSet.auto {
   193  			fields := map[string]interface{}{tTimeSet.fieldName: tTimeSet.input}
   194  			resp := GetTimestamp(fields, "", "")
   195  			if !resp.Equal(tTimeSet.expected) {
   196  				t.Errorf("time %d: should've been parsed automatically, without required config", i)
   197  			}
   198  			if len(fields) != 0 {
   199  				t.Error("time field should have been deleted, but was not")
   200  			}
   201  		}
   202  
   203  		fields := map[string]interface{}{tTimeSet.fieldName: tTimeSet.input}
   204  		resp := GetTimestamp(fields, tTimeSet.fieldName, tTimeSet.format)
   205  		if !approxEqual(resp, tTimeSet.expected, tTimeSet.diffThreshold) {
   206  			t.Errorf("time %d: resp time %s didn't match expected time %s", i, resp, tTimeSet.expected)
   207  		}
   208  		if len(fields) != 0 {
   209  			t.Error("time field should have been deleted, but was not")
   210  		}
   211  	}
   212  }
   213  
   214  func approxEqual(t1, t2 time.Time, threshold time.Duration) bool {
   215  	diff := int64(math.Abs(float64(t1.Sub(t2))))
   216  	return diff <= int64(threshold)
   217  }
   218  
   219  func TestGetTimestampInvalid(t *testing.T) {
   220  	// time field missing
   221  	resp := GetTimestamp(map[string]interface{}{"noTimeField": "not used"}, "", "")
   222  	if !resp.Equal(Now()) {
   223  		t.Errorf("resp time %s didn't match expected time %s", resp, Now())
   224  	}
   225  	// time field unparsable
   226  	resp = GetTimestamp(map[string]interface{}{"time": "not a valid date"}, "", "")
   227  	if !resp.Equal(Now()) {
   228  		t.Errorf("resp time %s didn't match expected time %s", resp, Now())
   229  	}
   230  	fields := map[string]interface{}{"time": "not a valid date", "key": "value"}
   231  	resp = GetTimestamp(fields, "", "")
   232  	if !resp.Equal(Now()) {
   233  		t.Errorf("resp time %s didn't match expected time %s", resp, Now())
   234  	}
   235  	if len(fields) != 2 {
   236  		t.Error("fields was modified despite not having a valid timestamp")
   237  	}
   238  }
   239  
   240  func TestGetTimestampCustomFormat(t *testing.T) {
   241  	weirdFormat := "Mon // 02 ---- Jan ... 06 15:04:05 -0700"
   242  
   243  	testStr := "Mon // 09 ---- Aug ... 10 15:34:56 -0800"
   244  	expected := time.Date(2010, 8, 9, 15, 34, 56, 0, time.FixedZone("PST", -28800))
   245  
   246  	// with just Format defined
   247  	resp := GetTimestamp(map[string]interface{}{"timestamp": testStr}, "", weirdFormat)
   248  	if !resp.Equal(expected) {
   249  		t.Errorf("resp time %s didn't match expected time %s", resp, expected)
   250  	}
   251  
   252  	// with just TimeFieldName defined -- use one of the expected/fallback
   253  	// formats
   254  	resp = GetTimestamp(map[string]interface{}{"funkyTime": expected.Format(time.RubyDate)}, "funkyTime", "")
   255  	if !resp.Equal(expected) {
   256  		t.Errorf("resp time %s didn't match expected time %s", resp, expected)
   257  	}
   258  	resp = GetTimestamp(map[string]interface{}{"funkyTime": testStr}, "funkyTime", weirdFormat)
   259  	if !resp.Equal(expected) {
   260  		t.Errorf("resp time %s didn't match expected time %s", resp, expected)
   261  	}
   262  	// don't parse the "time" field if we're told to look for time in "funkyTime"
   263  	resp = GetTimestamp(map[string]interface{}{"time": "2014-04-10 19:57:38.123456789 -0800 PST"}, "funkyTime", weirdFormat)
   264  	if !resp.Equal(Now()) {
   265  		t.Errorf("resp time %s didn't match expected time %s", resp, Now())
   266  	}
   267  }
   268  
   269  func TestGetTimestampTypeTime(t *testing.T) {
   270  	expected := time.Now()
   271  	resp := GetTimestamp(map[string]interface{}{"real_time_key": expected}, "real_time_key", "")
   272  	if !resp.Equal(expected) {
   273  		t.Errorf("resp time %s didn't match expected time %s", resp, expected)
   274  	}
   275  }
   276  
   277  func TestCommaInTimestamp(t *testing.T) {
   278  	commaTimes := []testTimestamp{
   279  		{ // test commas as the fractional portion separator
   280  			format:    "2006-01-02 15:04:05,999999999 -0700 MST",
   281  			fieldName: "time",
   282  			input:     "2014-03-10 12:57:38,123456789 -0700 PDT",
   283  			expected:  time.Unix(1394481458, 123456789),
   284  		},
   285  		{
   286  			format:    "2006-01-02 15:04:05.999999999 -0700 MST",
   287  			fieldName: "time",
   288  			input:     "2014-03-10 12:57:38,123456789 -0700 PDT",
   289  			expected:  time.Unix(1394481458, 123456789),
   290  		},
   291  	}
   292  	for i, tTimeSet := range commaTimes {
   293  		expectedTime := tTimeSet.expected
   294  		resp := GetTimestamp(map[string]interface{}{tTimeSet.fieldName: tTimeSet.input}, tTimeSet.fieldName, tTimeSet.format)
   295  		if !resp.Equal(expectedTime) {
   296  			t.Errorf("time %d: resp time %s didn't match expected time %s", i, resp, expectedTime)
   297  		}
   298  	}
   299  
   300  }