mirror of https://github.com/tailscale/tailscale/
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
2.9 KiB
Go
151 lines
2.9 KiB
Go
2 years ago
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||
|
|
||
|
package lazy
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"sync"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestSyncValue(t *testing.T) {
|
||
|
var lt SyncValue[int]
|
||
|
n := int(testing.AllocsPerRun(1000, func() {
|
||
|
got := lt.Get(fortyTwo)
|
||
|
if got != 42 {
|
||
|
t.Fatalf("got %v; want 42", got)
|
||
|
}
|
||
|
}))
|
||
|
if n != 0 {
|
||
|
t.Errorf("allocs = %v; want 0", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSyncValueErr(t *testing.T) {
|
||
|
var lt SyncValue[int]
|
||
|
n := int(testing.AllocsPerRun(1000, func() {
|
||
|
got, err := lt.GetErr(func() (int, error) {
|
||
|
return 42, nil
|
||
|
})
|
||
|
if got != 42 || err != nil {
|
||
|
t.Fatalf("got %v, %v; want 42, nil", got, err)
|
||
|
}
|
||
|
}))
|
||
|
if n != 0 {
|
||
|
t.Errorf("allocs = %v; want 0", n)
|
||
|
}
|
||
|
|
||
|
var lterr SyncValue[int]
|
||
|
wantErr := errors.New("test error")
|
||
|
n = int(testing.AllocsPerRun(1000, func() {
|
||
|
got, err := lterr.GetErr(func() (int, error) {
|
||
|
return 0, wantErr
|
||
|
})
|
||
|
if got != 0 || err != wantErr {
|
||
|
t.Fatalf("got %v, %v; want 0, %v", got, err, wantErr)
|
||
|
}
|
||
|
}))
|
||
|
if n != 0 {
|
||
|
t.Errorf("allocs = %v; want 0", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSyncValueSet(t *testing.T) {
|
||
|
var lt SyncValue[int]
|
||
|
if !lt.Set(42) {
|
||
|
t.Fatalf("Set failed")
|
||
|
}
|
||
|
if lt.Set(43) {
|
||
|
t.Fatalf("Set succeeded after first Set")
|
||
|
}
|
||
|
n := int(testing.AllocsPerRun(1000, func() {
|
||
|
got := lt.Get(fortyTwo)
|
||
|
if got != 42 {
|
||
|
t.Fatalf("got %v; want 42", got)
|
||
|
}
|
||
|
}))
|
||
|
if n != 0 {
|
||
|
t.Errorf("allocs = %v; want 0", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSyncValueMustSet(t *testing.T) {
|
||
|
var lt SyncValue[int]
|
||
|
lt.MustSet(42)
|
||
|
defer func() {
|
||
|
if e := recover(); e == nil {
|
||
|
t.Errorf("unexpected success; want panic")
|
||
|
}
|
||
|
}()
|
||
|
lt.MustSet(43)
|
||
|
}
|
||
|
|
||
|
func TestSyncValueConcurrent(t *testing.T) {
|
||
|
var (
|
||
|
lt SyncValue[int]
|
||
|
wg sync.WaitGroup
|
||
|
start = make(chan struct{})
|
||
|
routines = 10000
|
||
|
)
|
||
|
wg.Add(routines)
|
||
|
for i := 0; i < routines; i++ {
|
||
|
go func() {
|
||
|
defer wg.Done()
|
||
|
// Every goroutine waits for the go signal, so that more of them
|
||
|
// have a chance to race on the initial Get than with sequential
|
||
|
// goroutine starts.
|
||
|
<-start
|
||
|
got := lt.Get(fortyTwo)
|
||
|
if got != 42 {
|
||
|
t.Errorf("got %v; want 42", got)
|
||
|
}
|
||
|
}()
|
||
|
}
|
||
|
close(start)
|
||
|
wg.Wait()
|
||
|
}
|
||
|
|
||
|
func TestSyncFunc(t *testing.T) {
|
||
|
f := SyncFunc(fortyTwo)
|
||
|
|
||
|
n := int(testing.AllocsPerRun(1000, func() {
|
||
|
got := f()
|
||
|
if got != 42 {
|
||
|
t.Fatalf("got %v; want 42", got)
|
||
|
}
|
||
|
}))
|
||
|
if n != 0 {
|
||
|
t.Errorf("allocs = %v; want 0", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSyncFuncErr(t *testing.T) {
|
||
|
f := SyncFuncErr(func() (int, error) {
|
||
|
return 42, nil
|
||
|
})
|
||
|
n := int(testing.AllocsPerRun(1000, func() {
|
||
|
got, err := f()
|
||
|
if got != 42 || err != nil {
|
||
|
t.Fatalf("got %v, %v; want 42, nil", got, err)
|
||
|
}
|
||
|
}))
|
||
|
if n != 0 {
|
||
|
t.Errorf("allocs = %v; want 0", n)
|
||
|
}
|
||
|
|
||
|
wantErr := errors.New("test error")
|
||
|
f = SyncFuncErr(func() (int, error) {
|
||
|
return 0, wantErr
|
||
|
})
|
||
|
n = int(testing.AllocsPerRun(1000, func() {
|
||
|
got, err := f()
|
||
|
if got != 0 || err != wantErr {
|
||
|
t.Fatalf("got %v, %v; want 0, %v", got, err, wantErr)
|
||
|
}
|
||
|
}))
|
||
|
if n != 0 {
|
||
|
t.Errorf("allocs = %v; want 0", n)
|
||
|
}
|
||
|
}
|