Beispiel #1
0
func TestCustomTimestamp(t *testing.T) {

	// timestamp - epoch = adjusted time
	testCases := []struct {
		ts    int64
		adjTs int64
	}{
		{1397666977000, 72290977000},   // Now
		{1397666978000, 72290978000},   // in 1 second
		{1395881056000, 70505056000},   // 3 weeks ago
		{1303001162000, -22374838000},  // 3 years ago
		{1492390054000, 167014054000},  // in 3 years
		{2344466898000, 1019090898000}, // in 30 years
	}

	// Initialise our custom epoch
	epoch, err := time.Parse(time.RFC3339, defaultEpoch)
	require.NoError(t, err)
	epochMs := util.TimeToMsInt64(epoch)

	for _, tc := range testCases {
		adjTs := util.CustomTimestamp(epochMs, time.Unix(tc.ts/1000, 0))
		assert.Equal(t, adjTs, tc.adjTs, "Times should match")
	}
}
Beispiel #2
0
// Mint a new 128bit ID based on the current time, worker id and sequence
func (bf *Bigflake) Mint() (*BigflakeId, error) {
	bf.Lock()
	defer bf.Unlock()

	// Setup locks in our configured options
	bf.once.Do(bf.setup)

	// Ensure we only mint IDs if correctly configured
	if bf.workerId > bf.maxWorkerId {
		return nil, ErrInvalidWorkerId
	}

	// Get the current timestamp in ms
	// @todo generalise to allow custom epoch
	t := util.TimeToMsInt64(time.Now())

	// Update bigflake with this, which Mawill increment sequence number if needed
	err := bf.update(t)
	if err != nil {
		return nil, err
	}

	// Mint a new ID
	id := bf.mintId(bf.lastTimestamp, bf.workerId, bf.sequence, 48, 16)
	bfId := &BigflakeId{
		id: id,
	}

	return bfId, nil
}
Beispiel #3
0
// New creates a new instance of a snowflake compatible ID minter
// the worker ID must be unique otherwise ID collisions are likely to occur
func New(workerId uint32) (*Snowflake, error) {

	// initialise with the defaults, including epoch
	// 2012-01-01 00:00:00 +0000 UTC => 1325376000000
	epoch, err := time.Parse(time.RFC3339, defaultEpoch)
	if err != nil {
		return nil, err
	}

	return &Snowflake{
		workerId:     workerId,
		sequenceBits: defaultSequenceBits,
		workerIdBits: defaultWorkerIdBits,
		epoch:        util.TimeToMsInt64(epoch),
	}, nil
}
Beispiel #4
0
func newBigflakeMinter(t *testing.T) *Bigflake {
	mac := "80:36:bc:db:64:16"
	workerId, err := util.MacAddressToWorkerId(mac)
	if err != nil {
		t.Fail()
	}

	return &Bigflake{
		lastTimestamp: util.TimeToMsInt64(time.Now()),

		workerIdBits: defaultWorkerIdBits,
		sequenceBits: defaultSequenceBits,

		workerId: int64(workerId),
		sequence: 0,
		epoch:    0,
	}
}
Beispiel #5
0
func ksortability(t *testing.T, formatFunc func(id *BigflakeId) string) {
	var (
		lexicalOrder  sort.StringSlice = make([]string, 0)
		originalOrder                  = make([]string, 0)
		id                             = &BigflakeId{}

		// Allow us to progressively jump forwards in time
		timeDiff time.Duration = 10 * time.Millisecond
	)

	// Generate lots of ids
	bf, err := New(0)
	require.NoError(t, err)
	bf.setup()

	for i := 0; i < 10000000; i++ {
		if i%300000 == 0 {
			timeDiff = timeDiff * 2
			t.Logf("Moved to %v offset", timeDiff)
		}

		// Update time, sequence etc
		err := bf.update(util.TimeToMsInt64(time.Now().Add(timeDiff)))
		require.NoError(t, err)
		id.id = bf.mintId(bf.lastTimestamp, bf.workerId, bf.sequence, 48, 16)

		idStr := formatFunc(id)

		lexicalOrder = append(lexicalOrder, idStr)
		originalOrder = append(originalOrder, idStr)
	}

	// Sort string array
	lexicalOrder.Sort()

	// Compare ordering
	var mismatch int64
	for i, v := range originalOrder {
		if lexicalOrder[i] != v {
			mismatch++
		}
	}
	assert.Equal(t, int64(0), mismatch, fmt.Sprintf("Expected zero mismatches, got %v", mismatch))
}
Beispiel #6
0
func TestSequenceOverflow(t *testing.T) {

	// Setup snowflake at a particular time which we will freeze at
	sf, err := New(0)
	require.NoError(t, err)
	tms := util.TimeToMsInt64(time.Now())
	sf.lastTimestamp = tms

	invalidSequenceIds := []uint32{4096, 5841, 892347934}
	for _, seq := range invalidSequenceIds {

		// Fix the sequence ID, then update
		// This should fail, as we are within the same ms
		sf.sequence = seq
		err := sf.update(tms)
		assert.Error(t, err)
		assert.Equal(t, err, ErrSequenceOverflow, "Error should match")
	}
}
Beispiel #7
0
func TestPreEpochTime(t *testing.T) {
	testCases := []time.Time{
		time.Date(2012, 1, 0, 0, 0, 0, 0, time.UTC),
		time.Date(2011, 9, 5, 0, 0, 0, 0, time.UTC),
		time.Date(1066, 9, 5, 0, 0, 0, 0, time.UTC),
	}
	for _, tc := range testCases {
		sf, err := New(0)
		require.NoError(t, err)

		// Initialise our custom epoch
		epoch, err := time.Parse(time.RFC3339, defaultEpoch)
		require.NoError(t, err)
		epochMs := util.TimeToMsInt64(epoch)
		ts := util.CustomTimestamp(epochMs, tc)

		err = sf.update(ts)
		assert.Error(t, err)
	}
}