package test
import (
"context"
"fmt"
"io"
"net"
"os"
"sync"
"sync/atomic"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
sst "github.com/pancsta/asyncmachine-go/internal/testing/states"
"github.com/pancsta/asyncmachine-go/internal/testing/utils"
amhelp "github.com/pancsta/asyncmachine-go/pkg/helpers"
amhelpt "github.com/pancsta/asyncmachine-go/pkg/helpers/testing"
am "github.com/pancsta/asyncmachine-go/pkg/machine"
arpc "github.com/pancsta/asyncmachine-go/pkg/rpc"
ssrpc "github.com/pancsta/asyncmachine-go/pkg/rpc/states"
"github.com/pancsta/asyncmachine-go/pkg/telemetry/dbg"
)
var (
ssC = ssrpc .ClientStates
ssCo = ssrpc .ConsumerStates
ssS = ssrpc .ServerStates
ssM = ssrpc .MuxStates
Pass = am .Pass
)
func TemplateTestBasic (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
schema := ssrpc .StateSourceSchema .Merge (am .Schema {
"Foo" : {},
"Bar" : {Require : am .S {"Foo" }},
})
names := am .SAdd (ssrpc .StateSourceStates .Names (), am .S {"Foo" , "Bar" })
netSrc := am .New (ctx , schema , &am .Opts {Id : "ns-" + t .Name ()})
err := netSrc .VerifyStates (names )
if err != nil {
t .Fatal (err )
}
amhelpt .MachDebugEnv (t , netSrc )
_ , _ , s , c := newTest (t , ctx , netSrc , nil , 0 , false , nil , nil )
c .NetMach .Add1 ("Foo" , nil )
assert .True (t , s .Mach .Is1 (ssrpc .ServerStates .Ready ), "Server ready" )
assert .True (t , c .Mach .Is1 (ssrpc .ClientStates .Ready ), "Client ready" )
assert .True (t , s .Mach .Not1 (am .StateException ), "No server errors" )
assert .True (t , c .Mach .Not1 (am .StateException ), "No client errors" )
assert .True (t , netSrc .Is1 ("Foo" ), "NetworkMachine state set on the server" )
assert .True (t , c .NetMach .Is1 ("Foo" ), "NetworkMachine state set on the client" )
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
c .Mach .Remove1 (ssrpc .ClientStates .Start , nil )
s .Mach .Remove1 (ssrpc .ServerStates .Start , nil )
}
func TemplateTestTypeSafe (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
amDbgAddr := os .Getenv (dbg .EnvAmDbgAddr )
logLvl := am .EnvLogLevel ("" )
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
worker := utils .NewRelsNetSrc (t , nil )
amhelpt .MachDebug (t , worker , amDbgAddr , logLvl , true )
_ , _ , s , c := newTest (t , ctx , worker , nil , 0 , false , nil , nil )
states := am .S {sst .A , sst .C }
c .NetMach .Add (states , nil )
assert .True (t , s .Mach .Is1 (ssrpc .ServerStates .Ready ), "Server ready" )
assert .True (t , s .Mach .Is1 (ssrpc .ClientStates .Ready ), "Client ready" )
assert .True (t , s .Mach .Not1 (am .StateException ), "No server errors" )
assert .True (t , c .Mach .Not1 (am .StateException ), "No client errors" )
assert .True (t , worker .Is (states ), "NetworkMachine state set on the server" )
assert .True (t , c .NetMach .Is (states ),
"NetworkMachine state set on the client" )
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
c .Mach .Remove1 (ssrpc .ClientStates .Start , nil )
s .Mach .Remove1 (ssrpc .ServerStates .Start , nil )
}
func TemplateTestWaiting (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
end := make (chan struct {})
counter , _ , s , c := newTest (t , ctx , nil , end , 0 , false , nil , nil )
whenA := make (chan struct {})
go func () {
<-c .NetMach .When1 (sst .A , ctx )
close (whenA )
}()
states := am .S {sst .A , sst .C }
c .NetMach .Add (states , nil )
<-whenA
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
close (end )
assert .Equal (t , 0 , int (s .CallCount ),
"Server piggybacked clock on resp" )
assert .Equal (t , 3 , int (c .CallCount ),
"Client called RemoteHello, RemoteHandshake, RemoteAdd" )
bytesCount := <-counter
assert .LessOrEqual (t , 1_300 , int (bytesCount ),
"Bytes transferred (both ways)" )
assert .GreaterOrEqual (t , 20_000 , int (bytesCount ),
"Bytes transferred (both ways)" )
disposeTest (t , c , s , true )
}
func TemplateTestAddMany (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
end := make (chan struct {})
counter , _ , s , c := newTest (t , ctx , nil , end , 0 , false , nil , nil )
whenD := make (chan struct {})
go func () {
<-c .NetMach .When1 (sst .D , ctx )
close (whenD )
}()
states := am .S {sst .A , sst .C }
for i := 0 ; i < 500 ; i ++ {
c .NetMach .Add (states , nil )
}
c .NetMach .Add1 (sst .D , nil )
<-whenD
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
close (end )
assert .Equal (t , 0 , int (s .CallCount ),
"Server piggybacked clock on resp" )
bytesCount := <-counter
assert .LessOrEqual (t , 20_000 , int (bytesCount ),
"Client called handshake (2) and A,C (500) and D(1)" )
assert .GreaterOrEqual (t , 200_000 , int (bytesCount ),
"Client called handshake (2) and A,C (500) and D(1)" )
disposeTest (t , c , s , true )
}
func TemplateTestAddManyNoSync (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
end := make (chan struct {})
counter , _ , s , c := newTest (t , ctx , nil , end , 0 , false , nil , nil )
whenD := make (chan struct {})
go func () {
<-c .NetMach .When1 (sst .D , ctx )
close (whenD )
}()
states := am .S {sst .A , sst .C }
for i := 0 ; i < 500 ; i ++ {
c .NetMach .AddNS (states , nil )
}
c .NetMach .Add1NS (sst .D , nil )
time .Sleep (1000 * time .Millisecond )
c .Sync ()
<-whenD
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
close (end )
bytesCount := <-counter
assert .LessOrEqual (t , 10_000 , int (bytesCount ),
"Client called handshake (2) and A,C (500) and D(1)" )
assert .GreaterOrEqual (t , 100_000 , int (bytesCount ),
"Client called handshake (2) and A,C (500) and D(1)" )
disposeTest (t , c , s , true )
}
func TemplateTestAddManyInstantClock (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
end := make (chan struct {})
interval := 1 * time .Nanosecond
counter , _ , s , c := newTest (t , ctx , nil , end , interval , false , nil , nil )
whenD := make (chan struct {})
go func () {
<-c .NetMach .When1 (sst .D , ctx )
close (whenD )
}()
states := am .S {sst .A , sst .C }
for i := 0 ; i < 500 ; i ++ {
c .NetMach .Add (states , nil )
}
c .NetMach .Add1 (sst .D , nil )
<-whenD
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
close (end )
bytesCount := <-counter
assert .LessOrEqual (t , 20_000 , int (bytesCount ),
"Bytes transferred (both ways)" )
assert .GreaterOrEqual (t , 200_000 , int (bytesCount ),
"Bytes transferred (both ways)" )
disposeTest (t , c , s , true )
}
func TemplateTestManyStates (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
end := make (chan struct {})
schema := ssrpc .StateSourceSchema .Merge (sst .States )
names := am .SAdd (ssrpc .StateSourceStates .Names (), sst .Names )
randAmount := 100
for i := 0 ; i < randAmount ; i ++ {
n := fmt .Sprintf ("State%d" , i )
names = append (names , n )
schema [n ] = am .State {}
}
netSrc , err := am .NewCommon (context .Background (), "ns-" +t .Name (), schema ,
names , nil , nil , nil )
if err != nil {
t .Fatal (err )
}
counter , _ , s , c := newTest (t , ctx , netSrc , end , 0 , false , nil , nil )
whenD := make (chan struct {})
go func () {
<-c .NetMach .When1 (sst .D , ctx )
close (whenD )
}()
c .NetMach .Add1 (sst .C , nil )
for i := 5 ; i < randAmount -5 ; i ++ {
c .NetMach .Remove1 (names [i -3 ], nil )
c .NetMach .Add1 (names [i ], nil )
}
c .NetMach .Add1 (sst .D , nil )
<-whenD
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
close (end )
assert .Equal (t , 184 , int (c .CallCount ),
"Client called handshake (2) and mutations (181)" )
bytesCount := <-counter
assert .LessOrEqual (t , 10_000 , int (bytesCount ),
"Bytes transferred (both ways)" )
assert .GreaterOrEqual (t , 100_000 , int (bytesCount ),
"Bytes transferred (both ways)" )
disposeTest (t , c , s , true )
}
func TemplateTestHighInstantClocks (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
end := make (chan struct {})
worker := utils .NewRelsNetSrc (t , nil )
clock := worker .Clock (nil )
clock [sst .A ] = 1_000_000
clock [sst .C ] = 1_000_000
am .TestMockClock (worker , clock )
counter , _ , s , c := newTest (t , ctx , worker , end , 0 , false , nil , nil )
assert .GreaterOrEqual (t , int (worker .Tick (sst .A )), 1_000_000 ,
"Tick count should be greater or equal to 1M" )
whenD := make (chan struct {})
go func () {
<-c .NetMach .When1 (sst .D , ctx )
close (whenD )
}()
states := am .S {sst .A , sst .C }
for i := 0 ; i < 500 ; i ++ {
c .NetMach .Add (states , nil )
c .NetMach .Remove (states , nil )
}
c .NetMach .Add1 (sst .D , nil )
<-whenD
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
close (end )
bytesCount := <-counter
assert .LessOrEqual (t , 48_000 , int (bytesCount ),
"Bytes transferred (both ways)" )
assert .GreaterOrEqual (t , 350_000 , int (bytesCount ),
"Bytes transferred (both ways)" )
disposeTest (t , c , s , true )
}
func TemplateTestClockPush (t *testing .T , newTest NewTestFactory ) {
t .Skip ("test server-side mutations push their clock" )
}
type TestRetryCallHandlers struct {
blocked bool
}
func (h *TestRetryCallHandlers ) DState (e *am .Event ) {
if h .blocked {
return
}
e .Machine ().Log ("Blocking for 1s" )
time .Sleep (1 * time .Second )
h .blocked = true
}
func TemplateTestRetryCall (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
_ , w , s , c := newTest (t , ctx , nil , nil , 0 , false , nil , nil )
handlers := &TestRetryCallHandlers {}
_ , err := w .HandlersBind (handlers )
require .NoError (t , err )
c .TmpTestErr = fmt .Errorf ("IGNORE MOCK ERR" )
whenRetrying := c .Mach .When1 (ssrpc .ClientStates .RetryingCall , nil )
c .NetMach .Add1 (sst .A , nil )
amhelpt .WaitForAll (t , "RetryingCall" , ctx , 2 *time .Second , whenRetrying )
assert .True (t , s .Mach .Is1 (ssrpc .ServerStates .Ready ), "Server ready" )
assert .True (t , s .Mach .Is1 (ssrpc .ClientStates .Ready ), "Client ready" )
c .Mach .Log ("Generic err retried" )
<-w .WhenQueueEnds ()
time .Sleep (100 *time .Millisecond )
w .HandlerTimeout = 5 * time .Second
c .CallTimeout = 500 * time .Millisecond
wg := sync .WaitGroup {}
wg .Add (2 )
go func () {
c .NetMach .Add1 (sst .D , nil )
wg .Done ()
}()
go func () {
<-c .Mach .When1 (ssrpc .ClientStates .RetryingCall , ctx )
c .Mach .Log ("Timeout err retried" )
wg .Done ()
}()
wg .Wait ()
assert .True (t , w .Is1 (sst .D ), "NetworkMachine state set" )
assert .True (t , s .Mach .Is1 (ssrpc .ServerStates .Ready ), "Server ready" )
assert .True (t , s .Mach .Is1 (ssrpc .ClientStates .Ready ), "Client ready" )
assert .True (t , handlers .blocked , "Handlers should block" )
disposeTest (t , c , s , false )
}
func TemplateTestRetryConn (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
_ , _ , s , c := newTest (t , ctx , nil , nil , 0 , true , nil , nil )
lis := *s .Listener .Load ()
addr := lis .Addr ()
_ = lis .Close ()
s .Addr = addr .String ()
go func () {
<-c .Mach .WhenTime1 (ssC .Connecting , 3 , nil )
s .Start (nil )
}()
c .Start (nil )
amhelpt .WaitForAll (t , "client-server Ready" , ctx , 5 *time .Second ,
c .Mach .When1 (ssC .Ready , ctx ),
s .Mach .When1 (ssS .Ready , ctx ))
c .NetMach .Add1 (sst .A , nil )
amhelpt .AssertIs1 (t , c .Mach , ssrpc .ClientStates .Ready )
amhelpt .AssertIs1 (t , s .Mach , ssrpc .ServerStates .Ready )
amhelpt .AssertNot1 (t , c .Mach , ssrpc .ClientStates .RetryingCall )
amhelpt .AssertNot1 (t , c .Mach , ssrpc .ClientStates .RetryingConn )
c .Mach .Log ("Network err retried" )
disposeTest (t , c , s , false )
}
type TestRetryErrNetworkTimeoutHandlers struct {
blocked bool
shouldBlock bool
}
func (h *TestRetryErrNetworkTimeoutHandlers ) DState (e *am .Event ) {
if !h .shouldBlock {
return
}
e .Machine ().Log ("Blocking for 1s" )
time .Sleep (1 * time .Second )
h .blocked = true
}
func TemplateTestRetryErrNetworkTimeout (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
_ , w , s , c := newTest (t , ctx , nil , nil , 0 , false , nil , nil )
handlers := &TestRetryErrNetworkTimeoutHandlers {
shouldBlock : true ,
}
_ , err := w .HandlersBind (handlers )
require .NoError (t , err )
w .HandlerTimeout = 5 * time .Second
c .CallTimeout = 500 * time .Millisecond
wg := sync .WaitGroup {}
wg .Add (2 )
go func () {
<-c .Mach .When1 (ssrpc .ClientStates .RetryingCall , ctx )
c .Mach .Log ("Timeout err retried" )
wg .Done ()
}()
go func () {
c .NetMach .Add1 (sst .D , nil )
wg .Done ()
}()
wg .Wait ()
amhelpt .AssertIs1 (t , w , sst .D )
amhelpt .AssertIs1 (t , c .Mach , ssrpc .ClientStates .Ready )
amhelpt .AssertIs1 (t , s .Mach , ssrpc .ServerStates .Ready )
amhelpt .AssertNot1 (t , c .Mach , ssrpc .ClientStates .RetryingCall )
amhelpt .AssertNot1 (t , c .Mach , ssrpc .ClientStates .RetryingConn )
assert .True (t , handlers .blocked , "Handlers should block" )
disposeTest (t , c , s , false )
}
func TemplateTestRetryClosedListener (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
_ , _ , s , c := newTest (t , ctx , nil , nil , 0 , false , nil , nil )
lis := *s .Listener .Load ()
_ = lis .Close ()
time .Sleep (100 * time .Millisecond )
c .NetMach .Add1 (sst .D , nil )
amhelpt .WaitForAll (t , t .Name (), ctx , 2 *time .Second ,
c .NetMach .When1 (sst .D , ctx ))
amhelpt .AssertIs1 (t , c .NetMach , sst .D )
amhelpt .AssertIs1 (t , c .Mach , ssrpc .ClientStates .Ready )
amhelpt .AssertIs1 (t , s .Mach , ssrpc .ServerStates .Ready )
amhelpt .AssertNot1 (t , c .Mach , ssrpc .ClientStates .RetryingCall )
amhelpt .AssertNot1 (t , c .Mach , ssrpc .ClientStates .RetryingConn )
amhelpt .AssertTime (t , c .Mach ,
am .S {ssC .RetryingConn , ssC .HandshakeDone , ssC .Disconnected },
am .Time {2 , 3 , 2 })
disposeTest (t , c , s , false )
}
type TestPayloadHandlers struct {
srv *arpc .Server
}
func (w *TestPayloadHandlers ) CState (e *am .Event ) {
e .Machine ().EvRemove1 (e , sst .C , nil )
args := am .ParseArgs [arpc .A ](e .Args )
_ = w .srv .SendPayload (context .Background (), e , &arpc .MsgSrvPayload {
Data : "Hello" ,
Name : args .Name ,
})
}
type TestPayloadConsumer struct {
t *testing .T
delivered bool
}
func (c *TestPayloadConsumer ) ServerPayloadState (e *am .Event ) {
e .Machine ().Remove1 (ssCo .ServerPayload , nil )
args := am .ParseArgs [arpc .AServerPayload ](e .Args )
assert .Equal (c .t , "TestPayload" , args .Name )
assert .Equal (c .t , "Hello" , args .Payload .Data .(string ))
c .delivered = true
}
func TemplateTestPayload (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
ssCo := ssrpc .ConsumerStates
consHandlers := &TestPayloadConsumer {t : t }
consMach , err := am .NewCommon (ctx , "TestPayloadConsumer" ,
ssrpc .ConsumerSchema , ssCo .Names (), consHandlers , nil , nil )
if err != nil {
t .Fatal (err )
}
source := utils .NewNoRelsNetSrc (t , nil , "" )
handlers := &TestPayloadHandlers {}
_, err = source .HandlersBind (handlers )
if err != nil {
t .Fatal (err )
}
_ , _ , s , c := newTest (t , ctx , source , nil , 0 , false , &arpc .ClientOpts {
Consumer : consMach ,
}, nil )
handlers .srv = s
whenDelivered := consMach .When1 (ssCo .ServerPayload , nil )
c .NetMach .Add1 (sst .C , Pass (&arpc .A {
Name : "TestPayload" ,
}))
err = amhelp .WaitForAll (ctx , 2 *time .Second , whenDelivered )
assert .NoError (t , err , "Timeout when waiting for the package" )
assert .True (t , consHandlers .delivered , "Consumer got the package" )
disposeTest (t , c , s , true )
}
func TemplateTestRetryingConnState (t *testing .T , newTest NewTestFactory ) {
t .Skip ("TODO" )
}
func TemplateTestPartial (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
source := utils .NewNoRelsNetSrc (t , nil , "" )
source .Add1 (sst .C , nil )
source .Remove1 (sst .C , nil )
_ , _ , s , c := newTest (t , ctx , source , nil , 0 , false , &arpc .ClientOpts {
AllowedStates : am .S {sst .A , sst .B , sst .C },
SkippedStates : am .S {sst .C },
}, nil )
source .Add1 (sst .A , nil )
source .Add (am .S {sst .B , sst .C }, nil )
source .Add1 (sst .D , nil )
amhelpt .WaitForAll (t , "TestPartial(A, B)" , ctx , time .Second ,
c .NetMach .When (am .S {sst .A , sst .B }, nil ))
amhelpt .AssertIs (t , c .NetMach , am .S {sst .A , sst .B })
disposeTest (t , c , s , true )
if amhelp .IsTelemetry () {
time .Sleep (1 * time .Second )
}
}
func TemplateTestPartialInferred (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
source := utils .NewRelsNetSrc (t , nil )
_ , _ , s , c := newTest (t , ctx , source , nil , 0 , false , &arpc .ClientOpts {
AllowedStates : am .S {sst .A },
}, nil )
source .Add1 (sst .C , nil )
amhelpt .WaitForAll (t , "TestPartial(A, C)" , ctx , time .Second ,
c .NetMach .When (am .S {sst .A , sst .C }, nil ))
amhelpt .AssertIs (t , c .NetMach , am .S {sst .A , sst .C })
disposeTest (t , c , s , true )
if amhelp .IsTelemetry () {
time .Sleep (1 * time .Second )
}
}
func TemplateTestPartialNoSchema (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
source := utils .NewRelsNetSrc (t , nil )
_ , _ , s , c := newTest (t , ctx , source , nil , 0 , false , &arpc .ClientOpts {
AllowedStates : am .S {sst .C },
NoSchema : true ,
}, nil )
source .Add1 (sst .C , nil )
expected := am .S {sst .C }
amhelpt .WaitForAll (t , "TestPartial(A, C)" , ctx , time .Second ,
c .NetMach .When (expected , nil ))
amhelpt .AssertIs (t , c .NetMach , expected )
disposeTest (t , c , s , true )
if amhelp .IsTelemetry () {
time .Sleep (1 * time .Second )
}
}
type TestSchemaFilteringSyncTracer struct {
*am .TracerNoOp
amount int
}
func (t *TestSchemaFilteringSyncTracer ) MutationQueued (
machine am .Api , mutation *am .Mutation ,
) {
t .amount ++
}
func TemplateTestSchemaFilteringSync (t *testing .T , newTest NewTestFactory ) {
t .Skip ("mutation filtering not implemented yet" )
return
}
func TemplateTestShallowSync (t *testing .T , newTest NewTestFactory ) {
t .Skip ("TODO" )
}
func TemplateTestNoSchema (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
source := utils .NewRelsNetSrc (t , nil )
_ , _ , s , c := newTest (t , ctx , source , nil , 0 , false , &arpc .ClientOpts {
NoSchema : true ,
}, nil )
source .Add1 (sst .C , nil )
expected := am .S {sst .A , sst .C }
amhelpt .WaitForAll (t , "TestNoSchema(A, B, C, D)" , ctx , time .Second ,
c .NetMach .When (expected , nil ))
amhelpt .AssertIs (t , c .NetMach , expected )
disposeTest (t , c , s , true )
if amhelp .IsTelemetry () {
time .Sleep (1 * time .Second )
}
}
type TestMutationsSyncTracer struct {
*am .TracerNoOp
amount int
}
func (t *TestMutationsSyncTracer ) TransitionEnd (tx *am .Transition ) {
t .amount ++
}
func TemplateTestMutationsSync (t *testing .T , newTest NewTestFactory ) {
if os .Getenv (am .EnvAmTestDbgAddr ) == "" {
t .Parallel ()
}
ctx , cancel := context .WithCancel (context .Background ())
defer cancel ()
end := make (chan struct {})
counter , netSrc , s , c := newTest (t , ctx , nil , end , time .Second , false ,
&arpc .ClientOpts {
SyncMutations : true ,
}, nil )
txCount := &TestMutationsSyncTracer {TracerNoOp : &am .TracerNoOp {Id : t .Name ()}}
_ , err := c .NetMach .BindTracer (txCount )
require .NoError (t , err )
netSrc .Add1 (sst .B , nil )
netSrc .Add1 (sst .D , nil )
time .Sleep (100 * time .Millisecond )
intNano := time .Nanosecond
s .PushInterval .Store (&intNano )
s .PushClient ()
amhelpt .WaitForAll (t , "mutations pushed" , ctx , time .Second ,
c .NetMach .When1 (sst .D , nil ))
c .Mach .Log ("OK" )
s .Mach .Log ("OK" )
close (end )
assert .Equal (t , 3 , txCount .amount ,
"3 mutations came from the server" )
bytesCount := <-counter
assert .LessOrEqual (t , 1_000 , int (bytesCount ))
assert .GreaterOrEqual (t , 2_000 , int (bytesCount ))
disposeTest (t , c , s , true )
}
func TemplateTestExport (t *testing .T , newTest NewTestFactory ) {
t .Skip ("TODO" )
}
type NewTestFactory func (t *testing .T , ctx context .Context , netSrc *am .Machine ,
disposeMeter <-chan struct {}, pushInterval time .Duration , skipStart bool ,
clientOpts *arpc .ClientOpts , serverOpts *arpc .ServerOpts ,
) (<-chan int64 , *am .Machine , *arpc .Server , *arpc .Client )
func disposeTest(t *testing .T , c *arpc .Client , s *arpc .Server , checkErrs bool ) {
if checkErrs {
amhelpt .AssertNoErrEver (t , c .Mach )
amhelpt .AssertNoErrEver (t , s .Mach )
}
if os .Getenv (dbg .EnvAmDbgAddr ) != "" {
time .Sleep (time .Second )
}
c .Stop (context .TODO (), nil , true )
<-c .Mach .WhenDisposed ()
s .Stop (nil , true )
}
func TCPMeter (
listener net .Listener , fwdTo string , counter chan <- int64 ,
end <-chan struct {},
) {
defer listener .Close ()
destination , err := net .Dial ("tcp4" , fwdTo )
if err != nil {
fmt .Println ("Error connecting to destination:" , err .Error())
return
}
defer destination .Close ()
conn , err := listener .Accept ()
if err != nil {
fmt .Println ("Error accepting connection:" , err .Error())
return
}
defer conn .Close ()
wg := sync .WaitGroup {}
wg .Add (2 )
bytes := atomic .Int64 {}
go func () {
c , _ := io .Copy (destination , conn )
bytes .Add (c )
wg .Done ()
}()
go func () {
c , _ := io .Copy (conn , destination )
bytes .Add (c )
wg .Done ()
}()
<-end
_ = listener .Close ()
_ = destination .Close ()
_ = conn .Close ()
wg .Wait ()
c := bytes .Load ()
counter <- c
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .