1// Copyright (c) 2013-2017 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package blockchain
6
7import (
8	"strconv"
9	"testing"
10	"time"
11)
12
13// TestMedianTime tests the medianTime implementation.
14func TestMedianTime(t *testing.T) {
15	tests := []struct {
16		in         []int64
17		wantOffset int64
18		useDupID   bool
19	}{
20		// Not enough samples must result in an offset of 0.
21		{in: []int64{1}, wantOffset: 0},
22		{in: []int64{1, 2}, wantOffset: 0},
23		{in: []int64{1, 2, 3}, wantOffset: 0},
24		{in: []int64{1, 2, 3, 4}, wantOffset: 0},
25
26		// Various number of entries.  The expected offset is only
27		// updated on odd number of elements.
28		{in: []int64{-13, 57, -4, -23, -12}, wantOffset: -12},
29		{in: []int64{55, -13, 61, -52, 39, 55}, wantOffset: 39},
30		{in: []int64{-62, -58, -30, -62, 51, -30, 15}, wantOffset: -30},
31		{in: []int64{29, -47, 39, 54, 42, 41, 8, -33}, wantOffset: 39},
32		{in: []int64{37, 54, 9, -21, -56, -36, 5, -11, -39}, wantOffset: -11},
33		{in: []int64{57, -28, 25, -39, 9, 63, -16, 19, -60, 25}, wantOffset: 9},
34		{in: []int64{-5, -4, -3, -2, -1}, wantOffset: -3, useDupID: true},
35
36		// The offset stops being updated once the max number of entries
37		// has been reached.  This is actually a bug from Bitcoin Core,
38		// but since the time is ultimately used as a part of the
39		// consensus rules, it must be mirrored.
40		{in: []int64{-67, 67, -50, 24, 63, 17, 58, -14, 5, -32, -52}, wantOffset: 17},
41		{in: []int64{-67, 67, -50, 24, 63, 17, 58, -14, 5, -32, -52, 45}, wantOffset: 17},
42		{in: []int64{-67, 67, -50, 24, 63, 17, 58, -14, 5, -32, -52, 45, 4}, wantOffset: 17},
43
44		// Offsets that are too far away from the local time should
45		// be ignored.
46		{in: []int64{-4201, 4202, -4203, 4204, -4205}, wantOffset: 0},
47
48		// Exercise the condition where the median offset is greater
49		// than the max allowed adjustment, but there is at least one
50		// sample that is close enough to the current time to avoid
51		// triggering a warning about an invalid local clock.
52		{in: []int64{4201, 4202, 4203, 4204, -299}, wantOffset: 0},
53	}
54
55	// Modify the max number of allowed median time entries for these tests.
56	maxMedianTimeEntries = 10
57	defer func() { maxMedianTimeEntries = 200 }()
58
59	for i, test := range tests {
60		filter := NewMedianTime()
61		for j, offset := range test.in {
62			id := strconv.Itoa(j)
63			now := time.Unix(time.Now().Unix(), 0)
64			tOffset := now.Add(time.Duration(offset) * time.Second)
65			filter.AddTimeSample(id, tOffset)
66
67			// Ensure the duplicate IDs are ignored.
68			if test.useDupID {
69				// Modify the offsets to ensure the final median
70				// would be different if the duplicate is added.
71				tOffset = tOffset.Add(time.Duration(offset) *
72					time.Second)
73				filter.AddTimeSample(id, tOffset)
74			}
75		}
76
77		// Since it is possible that the time.Now call in AddTimeSample
78		// and the time.Now calls here in the tests will be off by one
79		// second, allow a fudge factor to compensate.
80		gotOffset := filter.Offset()
81		wantOffset := time.Duration(test.wantOffset) * time.Second
82		wantOffset2 := time.Duration(test.wantOffset-1) * time.Second
83		if gotOffset != wantOffset && gotOffset != wantOffset2 {
84			t.Errorf("Offset #%d: unexpected offset -- got %v, "+
85				"want %v or %v", i, gotOffset, wantOffset,
86				wantOffset2)
87			continue
88		}
89
90		// Since it is possible that the time.Now call in AdjustedTime
91		// and the time.Now call here in the tests will be off by one
92		// second, allow a fudge factor to compensate.
93		adjustedTime := filter.AdjustedTime()
94		now := time.Unix(time.Now().Unix(), 0)
95		wantTime := now.Add(filter.Offset())
96		wantTime2 := now.Add(filter.Offset() - time.Second)
97		if !adjustedTime.Equal(wantTime) && !adjustedTime.Equal(wantTime2) {
98			t.Errorf("AdjustedTime #%d: unexpected result -- got %v, "+
99				"want %v or %v", i, adjustedTime, wantTime,
100				wantTime2)
101			continue
102		}
103	}
104}
105