decred.org/dcrdex@v1.0.5/server/market/epump_test.go (about)

     1  package market
     2  
     3  import (
     4  	"context"
     5  	"math/rand"
     6  	"runtime"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  )
    11  
    12  func TestMarket_epochPumpHalt(t *testing.T) {
    13  	// This tests stopping the epochPump.
    14  
    15  	ctx, cancel := context.WithCancel(context.Background())
    16  	defer cancel()
    17  
    18  	ePump := newEpochPump()
    19  	var wg sync.WaitGroup
    20  	wg.Add(1)
    21  	go func() {
    22  		defer wg.Done()
    23  		ePump.Run(ctx)
    24  	}()
    25  
    26  	eq0 := NewEpoch(123413513, 1000)
    27  	rq0 := ePump.Insert(eq0)
    28  
    29  	eq1 := NewEpoch(123413514, 1000)
    30  	rq1 := ePump.Insert(eq1) // testing ep.q append
    31  
    32  	close(rq1.ready)
    33  
    34  	var rq0Out *readyEpoch
    35  	select {
    36  	case rq0Out = <-ePump.ready:
    37  		t.Fatalf("readyQueue provided out of order, got epoch %d", rq0Out.Epoch)
    38  	default:
    39  		// good, nothing was supposed to come out yet
    40  	}
    41  
    42  	close(rq0.ready)
    43  
    44  	rq0Out = <-ePump.ready
    45  	if rq0Out.EpochQueue.Epoch != eq0.Epoch {
    46  		t.Errorf("expected epoch %d, got %d", eq0.Epoch, rq0Out.EpochQueue.Epoch)
    47  	}
    48  
    49  	cancel() // testing len(ep.q) == 0 (Ready to shutdown), with rq1 in head
    50  	wg.Wait()
    51  
    52  	// pump should be done, but the final readyEpoch should have been sent on
    53  	// the buffered ready chan.
    54  	rq1Out := <-ePump.ready
    55  	if rq1Out.EpochQueue.Epoch != eq1.Epoch {
    56  		t.Errorf("expected epoch %d, got %d", eq1.Epoch, rq1Out.EpochQueue.Epoch)
    57  	}
    58  
    59  	// Test shutdown with multiple queued epochs.
    60  	ctx, cancel = context.WithCancel(context.Background())
    61  	defer cancel()
    62  
    63  	ePump = newEpochPump()
    64  	wg.Add(1)
    65  	go func() {
    66  		defer wg.Done()
    67  		ePump.Run(ctx)
    68  	}()
    69  
    70  	eq0 = NewEpoch(123413513, 1000)
    71  	rq0 = ePump.Insert(eq0)
    72  	eq1 = NewEpoch(123413514, 1000)
    73  	rq1 = ePump.Insert(eq1)
    74  	eq2 := NewEpoch(123413515, 1000)
    75  	rq2 := ePump.Insert(eq2)
    76  
    77  	cancel()          // testing len(ep.q) != 0 (stop after it drains the queue).
    78  	runtime.Gosched() // let Run start shutting things down
    79  	time.Sleep(50 * time.Millisecond)
    80  
    81  	// Make sure epochs come out in order.
    82  	close(rq0.ready)
    83  	rq0Out = <-ePump.ready
    84  	if rq0Out.EpochQueue.Epoch != eq0.Epoch {
    85  		t.Errorf("expected epoch %d, got %d", eq0.Epoch, rq0Out.EpochQueue.Epoch)
    86  	}
    87  
    88  	close(rq1.ready)
    89  	rq1Out = <-ePump.ready
    90  	if rq1Out.EpochQueue.Epoch != eq1.Epoch {
    91  		t.Errorf("expected epoch %d, got %d", eq1.Epoch, rq1Out.EpochQueue.Epoch)
    92  	}
    93  
    94  	close(rq2.ready)
    95  	rq2Out := <-ePump.ready
    96  	if rq2Out.EpochQueue.Epoch != eq2.Epoch {
    97  		t.Errorf("expected epoch %d, got %d", eq2.Epoch, rq2Out.EpochQueue.Epoch)
    98  	}
    99  
   100  	select {
   101  	case _, ok := <-ePump.ready:
   102  		if ok {
   103  			t.Errorf("ready channel should be closed now (Run returned), but something came through")
   104  		}
   105  	case <-time.After(time.Second):
   106  		t.Errorf("ready channel should be closed by now (Run returned)")
   107  	}
   108  
   109  	rqX := ePump.Insert(eq2)
   110  	if rqX != nil {
   111  		t.Errorf("halted epoch pump allowed insertion of new epoch queue")
   112  	}
   113  
   114  	wg.Wait()
   115  }
   116  
   117  func Test_epochPump_next(t *testing.T) {
   118  	ctx, cancel := context.WithCancel(context.Background())
   119  	defer cancel()
   120  
   121  	ep := newEpochPump()
   122  	var wg sync.WaitGroup
   123  	wg.Add(1)
   124  	go func() {
   125  		ep.Run(ctx)
   126  		wg.Done()
   127  	}()
   128  
   129  	waitTime := int64(5 * time.Second)
   130  	if testing.Short() {
   131  		waitTime = int64(1 * time.Second)
   132  	}
   133  
   134  	var epochStart, epochDur, numEpochs int64 = 123413513, 1_000, 100
   135  	epochs := make([]*readyEpoch, numEpochs)
   136  	for i := int64(0); i < numEpochs; i++ {
   137  		rq := ep.Insert(NewEpoch(i+epochStart, epochDur))
   138  		epochs[i] = rq
   139  
   140  		// Simulate preimage collection, randomly making the queues ready.
   141  		go func() {
   142  			wait := time.Duration(rand.Int63n(waitTime))
   143  			time.Sleep(wait)
   144  			close(rq.ready)
   145  		}()
   146  	}
   147  
   148  	// Receive all the ready epochs, verifying they come in order.
   149  	for i := epochStart; i < numEpochs+epochStart; i++ {
   150  		rq := <-ep.ready
   151  		if rq.Epoch != i {
   152  			t.Errorf("Received epoch %d, expected %d", rq.Epoch, i)
   153  		}
   154  	}
   155  	// All fake preimage collection goroutines are done now.
   156  
   157  	cancel()
   158  	wg.Wait()
   159  }