Skip to content

Commit

Permalink
Add clock tests
Browse files Browse the repository at this point in the history
Signed-off-by: Vladimir Popov <vladimir.popov@xored.com>
  • Loading branch information
Vladimir Popov committed Mar 23, 2021
1 parent 54368af commit 003494e
Showing 1 changed file with 310 additions and 0 deletions.
310 changes: 310 additions & 0 deletions pkg/tools/clock/mock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
// Copyright (c) 2021 Doc.ai and/or its affiliates.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package clock_test

import (
"context"
"sync/atomic"
"testing"
"time"

"github.com/stretchr/testify/require"
"go.uber.org/goleak"

"github.com/networkservicemesh/sdk/pkg/tools/clock"
)

const (
timeout = 2 * time.Hour
testWait = 100 * time.Millisecond
testTick = testWait / 100
)

func TestMock_Timer(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

timer := m.Timer(timeout)

select {
case <-timer.C():
require.FailNow(t, "too early")
case <-time.After(testWait):
}

m.Add(timeout / 2)

select {
case <-timer.C():
require.FailNow(t, "too early")
case <-time.After(testWait):
}

m.Add(timeout / 2)

select {
case <-timer.C():
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}

func TestMock_Timer_Stop(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

timer := m.Timer(timeout)

require.True(t, timer.Stop())
require.False(t, timer.Stop())

m.Add(timeout)

select {
case <-timer.C():
require.FailNow(t, "is stopped")
case <-time.After(testWait):
}
}

func TestMock_Timer_StopResult(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

timer := m.Timer(timeout)

m.Add(timeout)
require.False(t, timer.Stop())

<-timer.C()
}

func TestMock_Timer_Reset(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

timer := m.Timer(timeout)

m.Add(timeout / 2)

timer.Stop()
timer.Reset(timeout)

m.Add(timeout / 2)

select {
case <-timer.C():
require.FailNow(t, "too early")
case <-time.After(testWait):
}

m.Add(timeout / 2)

select {
case <-timer.C():
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}

func TestMock_Timer_ResetExpired(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

timer := m.Timer(timeout)

m.Add(timeout)

timer.Stop()
<-timer.C()
timer.Reset(timeout)

m.Add(timeout / 2)

select {
case <-timer.C():
require.FailNow(t, "too early")
case <-time.After(testWait):
}

m.Add(timeout / 2)

select {
case <-timer.C():
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}

func TestMock_AfterFunc(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

var count int32
for i := time.Duration(0); i < 10; i++ {
m.AfterFunc(timeout*i, func() {
atomic.AddInt32(&count, 1)
})
}

m.Add(4 * timeout)

require.Eventually(t, func() bool {
return atomic.LoadInt32(&count) == 5
}, testWait, testTick)

require.Never(t, func() bool {
return atomic.LoadInt32(&count) > 5
}, testWait, testTick)

m.Add(5 * timeout)

require.Eventually(t, func() bool {
return atomic.LoadInt32(&count) == 10
}, testWait, testTick)
}

func TestMock_AfterFunc_Ticker(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

ticker := m.Ticker(timeout)

for i := 0; i < 2; i++ {
select {
case <-ticker.C():
require.FailNow(t, "too early")
case <-time.After(testWait):
}

m.Add(timeout / 2)

select {
case <-ticker.C():
require.FailNow(t, "too early")
case <-time.After(testWait):
}

m.Add(timeout / 2)

select {
case <-ticker.C():
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}
}

func TestMock_WithDeadline(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

ctx, cancel := m.WithDeadline(context.Background(), m.Now().Add(timeout))
defer cancel()

select {
case <-ctx.Done():
require.FailNow(t, "too early")
case <-time.After(testWait):
require.NoError(t, ctx.Err())
}

m.Add(timeout)

select {
case <-ctx.Done():
require.Error(t, ctx.Err())
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}

func TestMock_WithDeadline_Expired(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

ctx, cancel := m.WithDeadline(context.Background(), m.Now())
defer cancel()

select {
case <-ctx.Done():
require.Error(t, ctx.Err())
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}

func TestMock_WithDeadline_ParentCanceled(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

parentCtx, parentCancel := context.WithCancel(context.Background())

ctx, cancel := m.WithDeadline(parentCtx, m.Now().Add(timeout))
defer cancel()

select {
case <-ctx.Done():
require.FailNow(t, "too early")
case <-time.After(testWait):
require.NoError(t, ctx.Err())
}

parentCancel()

select {
case <-ctx.Done():
require.Error(t, ctx.Err())
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}

func TestMock_WithTimeout(t *testing.T) {
defer goleak.VerifyNone(t, goleak.IgnoreCurrent())

m := clock.NewMock()

ctx, cancel := m.WithTimeout(context.Background(), timeout)
defer cancel()

select {
case <-ctx.Done():
require.FailNow(t, "too early")
case <-time.After(testWait):
require.NoError(t, ctx.Err())
}

m.Add(timeout)

select {
case <-ctx.Done():
require.Error(t, ctx.Err())
case <-time.After(testWait):
require.FailNow(t, "too late")
}
}

0 comments on commit 003494e

Please sign in to comment.