github.com/emate/nomad@v0.8.2-wo-binpacking/nomad/eval_broker_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/hashicorp/nomad/nomad/mock"
     9  	"github.com/hashicorp/nomad/nomad/structs"
    10  	"github.com/hashicorp/nomad/testutil"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  var (
    15  	defaultSched = []string{
    16  		structs.JobTypeService,
    17  		structs.JobTypeBatch,
    18  	}
    19  )
    20  
    21  func testBrokerConfig() *Config {
    22  	config := DefaultConfig()
    23  
    24  	// Tune the Nack timeout
    25  	config.EvalNackTimeout = 5 * time.Second
    26  
    27  	// Tune the Nack delay
    28  	config.EvalNackInitialReenqueueDelay = 5 * time.Millisecond
    29  	config.EvalNackSubsequentReenqueueDelay = 50 * time.Millisecond
    30  	return config
    31  }
    32  
    33  func testBroker(t *testing.T, timeout time.Duration) *EvalBroker {
    34  	config := testBrokerConfig()
    35  
    36  	if timeout != 0 {
    37  		config.EvalNackTimeout = timeout
    38  	}
    39  
    40  	return testBrokerFromConfig(t, config)
    41  }
    42  
    43  func testBrokerFromConfig(t *testing.T, c *Config) *EvalBroker {
    44  	b, err := NewEvalBroker(c.EvalNackTimeout, c.EvalNackInitialReenqueueDelay, c.EvalNackSubsequentReenqueueDelay, 3)
    45  	if err != nil {
    46  		t.Fatalf("err: %v", err)
    47  	}
    48  
    49  	return b
    50  }
    51  
    52  func TestEvalBroker_Enqueue_Dequeue_Nack_Ack(t *testing.T) {
    53  	t.Parallel()
    54  	b := testBroker(t, 0)
    55  
    56  	// Enqueue, but broker is disabled!
    57  	eval := mock.Eval()
    58  	b.Enqueue(eval)
    59  
    60  	// Verify nothing was done
    61  	stats := b.Stats()
    62  	if stats.TotalReady != 0 {
    63  		t.Fatalf("bad: %#v", stats)
    64  	}
    65  
    66  	if b.Enabled() {
    67  		t.Fatalf("should not be enabled")
    68  	}
    69  
    70  	// Enable the broker, and enqueue
    71  	b.SetEnabled(true)
    72  	b.Enqueue(eval)
    73  
    74  	// Double enqueue is a no-op
    75  	b.Enqueue(eval)
    76  
    77  	if !b.Enabled() {
    78  		t.Fatalf("should be enabled")
    79  	}
    80  
    81  	// Verify enqueue is done
    82  	stats = b.Stats()
    83  	if stats.TotalReady != 1 {
    84  		t.Fatalf("bad: %#v", stats)
    85  	}
    86  	if stats.ByScheduler[eval.Type].Ready != 1 {
    87  		t.Fatalf("bad: %#v", stats)
    88  	}
    89  
    90  	// Dequeue should work
    91  	out, token, err := b.Dequeue(defaultSched, time.Second)
    92  	if err != nil {
    93  		t.Fatalf("err: %v", err)
    94  	}
    95  	if out != eval {
    96  		t.Fatalf("bad : %#v", out)
    97  	}
    98  
    99  	tokenOut, ok := b.Outstanding(out.ID)
   100  	if !ok {
   101  		t.Fatalf("should be outstanding")
   102  	}
   103  	if tokenOut != token {
   104  		t.Fatalf("Bad: %#v %#v", token, tokenOut)
   105  	}
   106  
   107  	// OutstandingReset should verify the token
   108  	err = b.OutstandingReset("nope", "foo")
   109  	if err != ErrNotOutstanding {
   110  		t.Fatalf("err: %v", err)
   111  	}
   112  	err = b.OutstandingReset(out.ID, "foo")
   113  	if err != ErrTokenMismatch {
   114  		t.Fatalf("err: %v", err)
   115  	}
   116  	err = b.OutstandingReset(out.ID, tokenOut)
   117  	if err != nil {
   118  		t.Fatalf("err: %v", err)
   119  	}
   120  
   121  	// Check the stats
   122  	stats = b.Stats()
   123  	if stats.TotalReady != 0 {
   124  		t.Fatalf("bad: %#v", stats)
   125  	}
   126  	if stats.TotalUnacked != 1 {
   127  		t.Fatalf("bad: %#v", stats)
   128  	}
   129  	if stats.ByScheduler[eval.Type].Ready != 0 {
   130  		t.Fatalf("bad: %#v", stats)
   131  	}
   132  	if stats.ByScheduler[eval.Type].Unacked != 1 {
   133  		t.Fatalf("bad: %#v", stats)
   134  	}
   135  
   136  	// Nack with wrong token should fail
   137  	err = b.Nack(eval.ID, "foobarbaz")
   138  	if err == nil {
   139  		t.Fatalf("should fail to nack")
   140  	}
   141  
   142  	// Nack back into the queue
   143  	err = b.Nack(eval.ID, token)
   144  	if err != nil {
   145  		t.Fatalf("err: %v", err)
   146  	}
   147  
   148  	if _, ok := b.Outstanding(out.ID); ok {
   149  		t.Fatalf("should not be outstanding")
   150  	}
   151  
   152  	// Check the stats
   153  	testutil.WaitForResult(func() (bool, error) {
   154  		stats = b.Stats()
   155  		if stats.TotalReady != 1 {
   156  			return false, fmt.Errorf("bad: %#v", stats)
   157  		}
   158  		if stats.TotalUnacked != 0 {
   159  			return false, fmt.Errorf("bad: %#v", stats)
   160  		}
   161  		if stats.TotalWaiting != 0 {
   162  			return false, fmt.Errorf("bad: %#v", stats)
   163  		}
   164  		if stats.ByScheduler[eval.Type].Ready != 1 {
   165  			return false, fmt.Errorf("bad: %#v", stats)
   166  		}
   167  		if stats.ByScheduler[eval.Type].Unacked != 0 {
   168  			return false, fmt.Errorf("bad: %#v", stats)
   169  		}
   170  
   171  		return true, nil
   172  	}, func(e error) {
   173  		t.Fatal(e)
   174  	})
   175  
   176  	// Dequeue should work again
   177  	out2, token2, err := b.Dequeue(defaultSched, time.Second)
   178  	if err != nil {
   179  		t.Fatalf("err: %v", err)
   180  	}
   181  	if out2 != eval {
   182  		t.Fatalf("bad : %#v", out2)
   183  	}
   184  	if token2 == token {
   185  		t.Fatalf("should get a new token")
   186  	}
   187  
   188  	tokenOut2, ok := b.Outstanding(out.ID)
   189  	if !ok {
   190  		t.Fatalf("should be outstanding")
   191  	}
   192  	if tokenOut2 != token2 {
   193  		t.Fatalf("Bad: %#v %#v", token2, tokenOut2)
   194  	}
   195  
   196  	// Ack with wrong token
   197  	err = b.Ack(eval.ID, "zip")
   198  	if err == nil {
   199  		t.Fatalf("should fail to ack")
   200  	}
   201  
   202  	// Ack finally
   203  	err = b.Ack(eval.ID, token2)
   204  	if err != nil {
   205  		t.Fatalf("err: %v", err)
   206  	}
   207  
   208  	if _, ok := b.Outstanding(out.ID); ok {
   209  		t.Fatalf("should not be outstanding")
   210  	}
   211  
   212  	// Check the stats
   213  	stats = b.Stats()
   214  	if stats.TotalReady != 0 {
   215  		t.Fatalf("bad: %#v", stats)
   216  	}
   217  	if stats.TotalUnacked != 0 {
   218  		t.Fatalf("bad: %#v", stats)
   219  	}
   220  	if stats.ByScheduler[eval.Type].Ready != 0 {
   221  		t.Fatalf("bad: %#v", stats)
   222  	}
   223  	if stats.ByScheduler[eval.Type].Unacked != 0 {
   224  		t.Fatalf("bad: %#v", stats)
   225  	}
   226  }
   227  
   228  func TestEvalBroker_Nack_Delay(t *testing.T) {
   229  	t.Parallel()
   230  	b := testBroker(t, 0)
   231  
   232  	// Enqueue, but broker is disabled!
   233  	b.SetEnabled(true)
   234  	eval := mock.Eval()
   235  	b.Enqueue(eval)
   236  
   237  	// Dequeue should work
   238  	out, token, err := b.Dequeue(defaultSched, time.Second)
   239  	if err != nil {
   240  		t.Fatalf("err: %v", err)
   241  	}
   242  	if out != eval {
   243  		t.Fatalf("bad : %#v", out)
   244  	}
   245  
   246  	// Nack back into the queue
   247  	err = b.Nack(eval.ID, token)
   248  	if err != nil {
   249  		t.Fatalf("err: %v", err)
   250  	}
   251  
   252  	if _, ok := b.Outstanding(out.ID); ok {
   253  		t.Fatalf("should not be outstanding")
   254  	}
   255  
   256  	// Check the stats to ensure that it is waiting
   257  	stats := b.Stats()
   258  	if stats.TotalReady != 0 {
   259  		t.Fatalf("bad: %#v", stats)
   260  	}
   261  	if stats.TotalUnacked != 0 {
   262  		t.Fatalf("bad: %#v", stats)
   263  	}
   264  	if stats.TotalWaiting != 1 {
   265  		t.Fatalf("bad: %#v", stats)
   266  	}
   267  	if stats.ByScheduler[eval.Type].Ready != 0 {
   268  		t.Fatalf("bad: %#v", stats)
   269  	}
   270  	if stats.ByScheduler[eval.Type].Unacked != 0 {
   271  		t.Fatalf("bad: %#v", stats)
   272  	}
   273  
   274  	// Now wait for it to be re-enqueued
   275  	testutil.WaitForResult(func() (bool, error) {
   276  		stats = b.Stats()
   277  		if stats.TotalReady != 1 {
   278  			return false, fmt.Errorf("bad: %#v", stats)
   279  		}
   280  		if stats.TotalUnacked != 0 {
   281  			return false, fmt.Errorf("bad: %#v", stats)
   282  		}
   283  		if stats.TotalWaiting != 0 {
   284  			return false, fmt.Errorf("bad: %#v", stats)
   285  		}
   286  		if stats.ByScheduler[eval.Type].Ready != 1 {
   287  			return false, fmt.Errorf("bad: %#v", stats)
   288  		}
   289  		if stats.ByScheduler[eval.Type].Unacked != 0 {
   290  			return false, fmt.Errorf("bad: %#v", stats)
   291  		}
   292  
   293  		return true, nil
   294  	}, func(e error) {
   295  		t.Fatal(e)
   296  	})
   297  
   298  	// Dequeue should work again
   299  	out2, token2, err := b.Dequeue(defaultSched, time.Second)
   300  	if err != nil {
   301  		t.Fatalf("err: %v", err)
   302  	}
   303  	if out2 != eval {
   304  		t.Fatalf("bad : %#v", out2)
   305  	}
   306  	if token2 == token {
   307  		t.Fatalf("should get a new token")
   308  	}
   309  
   310  	// Capture the time
   311  	start := time.Now()
   312  
   313  	// Nack back into the queue
   314  	err = b.Nack(eval.ID, token2)
   315  	if err != nil {
   316  		t.Fatalf("err: %v", err)
   317  	}
   318  
   319  	// Now wait for it to be re-enqueued
   320  	testutil.WaitForResult(func() (bool, error) {
   321  		stats = b.Stats()
   322  		if stats.TotalReady != 1 {
   323  			return false, fmt.Errorf("bad: %#v", stats)
   324  		}
   325  		if stats.TotalUnacked != 0 {
   326  			return false, fmt.Errorf("bad: %#v", stats)
   327  		}
   328  		if stats.TotalWaiting != 0 {
   329  			return false, fmt.Errorf("bad: %#v", stats)
   330  		}
   331  		if stats.ByScheduler[eval.Type].Ready != 1 {
   332  			return false, fmt.Errorf("bad: %#v", stats)
   333  		}
   334  		if stats.ByScheduler[eval.Type].Unacked != 0 {
   335  			return false, fmt.Errorf("bad: %#v", stats)
   336  		}
   337  
   338  		return true, nil
   339  	}, func(e error) {
   340  		t.Fatal(e)
   341  	})
   342  
   343  	delay := time.Now().Sub(start)
   344  	if delay < b.subsequentNackDelay {
   345  		t.Fatalf("bad: delay was %v; want at least %v", delay, b.subsequentNackDelay)
   346  	}
   347  
   348  	// Dequeue should work again
   349  	out3, token3, err := b.Dequeue(defaultSched, time.Second)
   350  	if err != nil {
   351  		t.Fatalf("err: %v", err)
   352  	}
   353  	if out3 != eval {
   354  		t.Fatalf("bad : %#v", out3)
   355  	}
   356  	if token3 == token || token3 == token2 {
   357  		t.Fatalf("should get a new token")
   358  	}
   359  
   360  	// Ack finally
   361  	err = b.Ack(eval.ID, token3)
   362  	if err != nil {
   363  		t.Fatalf("err: %v", err)
   364  	}
   365  
   366  	if _, ok := b.Outstanding(out.ID); ok {
   367  		t.Fatalf("should not be outstanding")
   368  	}
   369  
   370  	// Check the stats
   371  	stats = b.Stats()
   372  	if stats.TotalReady != 0 {
   373  		t.Fatalf("bad: %#v", stats)
   374  	}
   375  	if stats.TotalUnacked != 0 {
   376  		t.Fatalf("bad: %#v", stats)
   377  	}
   378  	if stats.ByScheduler[eval.Type].Ready != 0 {
   379  		t.Fatalf("bad: %#v", stats)
   380  	}
   381  	if stats.ByScheduler[eval.Type].Unacked != 0 {
   382  		t.Fatalf("bad: %#v", stats)
   383  	}
   384  }
   385  
   386  func TestEvalBroker_Serialize_DuplicateJobID(t *testing.T) {
   387  	t.Parallel()
   388  	b := testBroker(t, 0)
   389  	b.SetEnabled(true)
   390  
   391  	ns1 := "namespace-one"
   392  	ns2 := "namespace-two"
   393  	eval := mock.Eval()
   394  	eval.Namespace = ns1
   395  	b.Enqueue(eval)
   396  
   397  	eval2 := mock.Eval()
   398  	eval2.JobID = eval.JobID
   399  	eval2.Namespace = ns1
   400  	eval2.CreateIndex = eval.CreateIndex + 1
   401  	b.Enqueue(eval2)
   402  
   403  	eval3 := mock.Eval()
   404  	eval3.JobID = eval.JobID
   405  	eval3.Namespace = ns1
   406  	eval3.CreateIndex = eval.CreateIndex + 2
   407  	b.Enqueue(eval3)
   408  
   409  	eval4 := mock.Eval()
   410  	eval4.JobID = eval.JobID
   411  	eval4.Namespace = ns2
   412  	eval4.CreateIndex = eval.CreateIndex + 3
   413  	b.Enqueue(eval4)
   414  
   415  	eval5 := mock.Eval()
   416  	eval5.JobID = eval.JobID
   417  	eval5.Namespace = ns2
   418  	eval5.CreateIndex = eval.CreateIndex + 4
   419  	b.Enqueue(eval5)
   420  
   421  	stats := b.Stats()
   422  	if stats.TotalReady != 2 {
   423  		t.Fatalf("bad: %#v", stats)
   424  	}
   425  	if stats.TotalBlocked != 3 {
   426  		t.Fatalf("bad: %#v", stats)
   427  	}
   428  
   429  	// Dequeue should work
   430  	out, token, err := b.Dequeue(defaultSched, time.Second)
   431  	if err != nil {
   432  		t.Fatalf("err: %v", err)
   433  	}
   434  	if out != eval {
   435  		t.Fatalf("bad : %#v", out)
   436  	}
   437  
   438  	// Check the stats
   439  	stats = b.Stats()
   440  	if stats.TotalReady != 1 {
   441  		t.Fatalf("bad: %#v", stats)
   442  	}
   443  	if stats.TotalUnacked != 1 {
   444  		t.Fatalf("bad: %#v", stats)
   445  	}
   446  	if stats.TotalBlocked != 3 {
   447  		t.Fatalf("bad: %#v", stats)
   448  	}
   449  
   450  	// Ack out
   451  	err = b.Ack(eval.ID, token)
   452  	if err != nil {
   453  		t.Fatalf("err: %v", err)
   454  	}
   455  
   456  	// Check the stats
   457  	stats = b.Stats()
   458  	if stats.TotalReady != 2 {
   459  		t.Fatalf("bad: %#v", stats)
   460  	}
   461  	if stats.TotalUnacked != 0 {
   462  		t.Fatalf("bad: %#v", stats)
   463  	}
   464  	if stats.TotalBlocked != 2 {
   465  		t.Fatalf("bad: %#v", stats)
   466  	}
   467  
   468  	// Dequeue should work
   469  	out, token, err = b.Dequeue(defaultSched, time.Second)
   470  	if err != nil {
   471  		t.Fatalf("err: %v", err)
   472  	}
   473  	if out != eval2 {
   474  		t.Fatalf("bad : %#v", out)
   475  	}
   476  
   477  	// Check the stats
   478  	stats = b.Stats()
   479  	if stats.TotalReady != 1 {
   480  		t.Fatalf("bad: %#v", stats)
   481  	}
   482  	if stats.TotalUnacked != 1 {
   483  		t.Fatalf("bad: %#v", stats)
   484  	}
   485  	if stats.TotalBlocked != 2 {
   486  		t.Fatalf("bad: %#v", stats)
   487  	}
   488  
   489  	// Ack out
   490  	err = b.Ack(eval2.ID, token)
   491  	if err != nil {
   492  		t.Fatalf("err: %v", err)
   493  	}
   494  
   495  	// Check the stats
   496  	stats = b.Stats()
   497  	if stats.TotalReady != 2 {
   498  		t.Fatalf("bad: %#v", stats)
   499  	}
   500  	if stats.TotalUnacked != 0 {
   501  		t.Fatalf("bad: %#v", stats)
   502  	}
   503  	if stats.TotalBlocked != 1 {
   504  		t.Fatalf("bad: %#v", stats)
   505  	}
   506  
   507  	// Dequeue should work
   508  	out, token, err = b.Dequeue(defaultSched, time.Second)
   509  	if err != nil {
   510  		t.Fatalf("err: %v", err)
   511  	}
   512  	if out != eval3 {
   513  		t.Fatalf("bad : %#v", out)
   514  	}
   515  
   516  	// Check the stats
   517  	stats = b.Stats()
   518  	if stats.TotalReady != 1 {
   519  		t.Fatalf("bad: %#v", stats)
   520  	}
   521  	if stats.TotalUnacked != 1 {
   522  		t.Fatalf("bad: %#v", stats)
   523  	}
   524  	if stats.TotalBlocked != 1 {
   525  		t.Fatalf("bad: %#v", stats)
   526  	}
   527  
   528  	// Ack out
   529  	err = b.Ack(eval3.ID, token)
   530  	if err != nil {
   531  		t.Fatalf("err: %v", err)
   532  	}
   533  
   534  	// Check the stats
   535  	stats = b.Stats()
   536  	if stats.TotalReady != 1 {
   537  		t.Fatalf("bad: %#v", stats)
   538  	}
   539  	if stats.TotalUnacked != 0 {
   540  		t.Fatalf("bad: %#v", stats)
   541  	}
   542  	if stats.TotalBlocked != 1 {
   543  		t.Fatalf("bad: %#v", stats)
   544  	}
   545  
   546  	// Dequeue should work
   547  	out, token, err = b.Dequeue(defaultSched, time.Second)
   548  	if err != nil {
   549  		t.Fatalf("err: %v", err)
   550  	}
   551  	if out != eval4 {
   552  		t.Fatalf("bad : %#v", out)
   553  	}
   554  
   555  	// Check the stats
   556  	stats = b.Stats()
   557  	if stats.TotalReady != 0 {
   558  		t.Fatalf("bad: %#v", stats)
   559  	}
   560  	if stats.TotalUnacked != 1 {
   561  		t.Fatalf("bad: %#v", stats)
   562  	}
   563  	if stats.TotalBlocked != 1 {
   564  		t.Fatalf("bad: %#v", stats)
   565  	}
   566  
   567  	// Ack out
   568  	err = b.Ack(eval4.ID, token)
   569  	if err != nil {
   570  		t.Fatalf("err: %v", err)
   571  	}
   572  
   573  	// Check the stats
   574  	stats = b.Stats()
   575  	if stats.TotalReady != 1 {
   576  		t.Fatalf("bad: %#v", stats)
   577  	}
   578  	if stats.TotalUnacked != 0 {
   579  		t.Fatalf("bad: %#v", stats)
   580  	}
   581  	if stats.TotalBlocked != 0 {
   582  		t.Fatalf("bad: %#v", stats)
   583  	}
   584  
   585  	// Dequeue should work
   586  	out, token, err = b.Dequeue(defaultSched, time.Second)
   587  	if err != nil {
   588  		t.Fatalf("err: %v", err)
   589  	}
   590  	if out != eval5 {
   591  		t.Fatalf("bad : %#v", out)
   592  	}
   593  
   594  	// Check the stats
   595  	stats = b.Stats()
   596  	if stats.TotalReady != 0 {
   597  		t.Fatalf("bad: %#v", stats)
   598  	}
   599  	if stats.TotalUnacked != 1 {
   600  		t.Fatalf("bad: %#v", stats)
   601  	}
   602  	if stats.TotalBlocked != 0 {
   603  		t.Fatalf("bad: %#v", stats)
   604  	}
   605  
   606  	// Ack out
   607  	err = b.Ack(eval5.ID, token)
   608  	if err != nil {
   609  		t.Fatalf("err: %v", err)
   610  	}
   611  
   612  	// Check the stats
   613  	stats = b.Stats()
   614  	if stats.TotalReady != 0 {
   615  		t.Fatalf("bad: %#v", stats)
   616  	}
   617  	if stats.TotalUnacked != 0 {
   618  		t.Fatalf("bad: %#v", stats)
   619  	}
   620  	if stats.TotalBlocked != 0 {
   621  		t.Fatalf("bad: %#v", stats)
   622  	}
   623  }
   624  
   625  func TestEvalBroker_Enqueue_Disable(t *testing.T) {
   626  	t.Parallel()
   627  	b := testBroker(t, 0)
   628  
   629  	// Enqueue
   630  	eval := mock.Eval()
   631  	b.SetEnabled(true)
   632  	b.Enqueue(eval)
   633  
   634  	// Flush via SetEnabled
   635  	b.SetEnabled(false)
   636  
   637  	// Check the stats
   638  	stats := b.Stats()
   639  	if stats.TotalReady != 0 {
   640  		t.Fatalf("bad: %#v", stats)
   641  	}
   642  	if stats.TotalUnacked != 0 {
   643  		t.Fatalf("bad: %#v", stats)
   644  	}
   645  	if _, ok := stats.ByScheduler[eval.Type]; ok {
   646  		t.Fatalf("bad: %#v", stats)
   647  	}
   648  }
   649  
   650  func TestEvalBroker_Dequeue_Timeout(t *testing.T) {
   651  	t.Parallel()
   652  	b := testBroker(t, 0)
   653  	b.SetEnabled(true)
   654  
   655  	start := time.Now()
   656  	out, _, err := b.Dequeue(defaultSched, 5*time.Millisecond)
   657  	end := time.Now()
   658  
   659  	if err != nil {
   660  		t.Fatalf("err: %v", err)
   661  	}
   662  	if out != nil {
   663  		t.Fatalf("unexpected: %#v", out)
   664  	}
   665  
   666  	if diff := end.Sub(start); diff < 5*time.Millisecond {
   667  		t.Fatalf("bad: %#v", diff)
   668  	}
   669  }
   670  
   671  func TestEvalBroker_Dequeue_Empty_Timeout(t *testing.T) {
   672  	t.Parallel()
   673  	b := testBroker(t, 0)
   674  	b.SetEnabled(true)
   675  	doneCh := make(chan struct{}, 1)
   676  
   677  	go func() {
   678  		out, _, err := b.Dequeue(defaultSched, 0)
   679  		if err != nil {
   680  			t.Fatalf("err: %v", err)
   681  		}
   682  		if out == nil {
   683  			t.Fatal("Expect an eval")
   684  		}
   685  		doneCh <- struct{}{}
   686  	}()
   687  
   688  	// Sleep for a little bit
   689  	select {
   690  	case <-time.After(5 * time.Millisecond):
   691  	case <-doneCh:
   692  		t.Fatalf("Dequeue(0) should block")
   693  	}
   694  
   695  	// Enqueue to unblock the dequeue.
   696  	eval := mock.Eval()
   697  	b.Enqueue(eval)
   698  
   699  	select {
   700  	case <-doneCh:
   701  		return
   702  	case <-time.After(5 * time.Millisecond):
   703  		t.Fatal("timeout: Dequeue(0) should return after enqueue")
   704  	}
   705  }
   706  
   707  // Ensure higher priority dequeued first
   708  func TestEvalBroker_Dequeue_Priority(t *testing.T) {
   709  	t.Parallel()
   710  	b := testBroker(t, 0)
   711  	b.SetEnabled(true)
   712  
   713  	eval1 := mock.Eval()
   714  	eval1.Priority = 10
   715  	b.Enqueue(eval1)
   716  
   717  	eval2 := mock.Eval()
   718  	eval2.Priority = 30
   719  	b.Enqueue(eval2)
   720  
   721  	eval3 := mock.Eval()
   722  	eval3.Priority = 20
   723  	b.Enqueue(eval3)
   724  
   725  	out1, _, _ := b.Dequeue(defaultSched, time.Second)
   726  	if out1 != eval2 {
   727  		t.Fatalf("bad: %#v", out1)
   728  	}
   729  
   730  	out2, _, _ := b.Dequeue(defaultSched, time.Second)
   731  	if out2 != eval3 {
   732  		t.Fatalf("bad: %#v", out2)
   733  	}
   734  
   735  	out3, _, _ := b.Dequeue(defaultSched, time.Second)
   736  	if out3 != eval1 {
   737  		t.Fatalf("bad: %#v", out3)
   738  	}
   739  }
   740  
   741  // Ensure FIFO at fixed priority
   742  func TestEvalBroker_Dequeue_FIFO(t *testing.T) {
   743  	t.Parallel()
   744  	b := testBroker(t, 0)
   745  	b.SetEnabled(true)
   746  	NUM := 100
   747  
   748  	for i := 0; i < NUM; i++ {
   749  		eval1 := mock.Eval()
   750  		eval1.CreateIndex = uint64(i)
   751  		eval1.ModifyIndex = uint64(i)
   752  		b.Enqueue(eval1)
   753  	}
   754  
   755  	for i := 0; i < NUM; i++ {
   756  		out1, _, _ := b.Dequeue(defaultSched, time.Second)
   757  		if out1.CreateIndex != uint64(i) {
   758  			t.Fatalf("bad: %d %#v", i, out1)
   759  		}
   760  	}
   761  }
   762  
   763  // Ensure fairness between schedulers
   764  func TestEvalBroker_Dequeue_Fairness(t *testing.T) {
   765  	t.Parallel()
   766  	b := testBroker(t, 0)
   767  	b.SetEnabled(true)
   768  	NUM := 1000
   769  
   770  	for i := 0; i < NUM; i++ {
   771  		eval1 := mock.Eval()
   772  		if i < (NUM / 2) {
   773  			eval1.Type = structs.JobTypeService
   774  		} else {
   775  			eval1.Type = structs.JobTypeBatch
   776  		}
   777  		b.Enqueue(eval1)
   778  	}
   779  
   780  	counter := 0
   781  	for i := 0; i < NUM; i++ {
   782  		out1, _, _ := b.Dequeue(defaultSched, time.Second)
   783  
   784  		switch out1.Type {
   785  		case structs.JobTypeService:
   786  			if counter < 0 {
   787  				counter = 0
   788  			}
   789  			counter += 1
   790  		case structs.JobTypeBatch:
   791  			if counter > 0 {
   792  				counter = 0
   793  			}
   794  			counter -= 1
   795  		}
   796  
   797  		// This will fail randomly at times. It is very hard to
   798  		// test deterministically that its acting randomly.
   799  		if counter >= 250 || counter <= -250 {
   800  			t.Fatalf("unlikely sequence: %d", counter)
   801  		}
   802  	}
   803  }
   804  
   805  // Ensure we get unblocked
   806  func TestEvalBroker_Dequeue_Blocked(t *testing.T) {
   807  	t.Parallel()
   808  	b := testBroker(t, 0)
   809  	b.SetEnabled(true)
   810  
   811  	// Start with a blocked dequeue
   812  	outCh := make(chan *structs.Evaluation, 1)
   813  	go func() {
   814  		start := time.Now()
   815  		out, _, err := b.Dequeue(defaultSched, time.Second)
   816  		end := time.Now()
   817  		outCh <- out
   818  		if err != nil {
   819  			t.Fatalf("err: %v", err)
   820  		}
   821  		if d := end.Sub(start); d < 5*time.Millisecond {
   822  			t.Fatalf("bad: %v", d)
   823  		}
   824  	}()
   825  
   826  	// Wait for a bit
   827  	time.Sleep(5 * time.Millisecond)
   828  
   829  	// Enqueue
   830  	eval := mock.Eval()
   831  	b.Enqueue(eval)
   832  
   833  	// Ensure dequeue
   834  	select {
   835  	case out := <-outCh:
   836  		if out != eval {
   837  			t.Fatalf("bad: %v", out)
   838  		}
   839  	case <-time.After(time.Second):
   840  		t.Fatalf("timeout")
   841  	}
   842  }
   843  
   844  // Ensure we nack in a timely manner
   845  func TestEvalBroker_Nack_Timeout(t *testing.T) {
   846  	t.Parallel()
   847  	b := testBroker(t, 5*time.Millisecond)
   848  	b.SetEnabled(true)
   849  
   850  	// Enqueue
   851  	eval := mock.Eval()
   852  	b.Enqueue(eval)
   853  
   854  	// Dequeue
   855  	out, _, err := b.Dequeue(defaultSched, time.Second)
   856  	start := time.Now()
   857  	if err != nil {
   858  		t.Fatalf("err: %v", err)
   859  	}
   860  	if out != eval {
   861  		t.Fatalf("bad: %v", out)
   862  	}
   863  
   864  	// Dequeue, should block on Nack timer
   865  	out, _, err = b.Dequeue(defaultSched, time.Second)
   866  	end := time.Now()
   867  	if err != nil {
   868  		t.Fatalf("err: %v", err)
   869  	}
   870  	if out != eval {
   871  		t.Fatalf("bad: %v", out)
   872  	}
   873  
   874  	// Check the nack timer
   875  	if diff := end.Sub(start); diff < 5*time.Millisecond {
   876  		t.Fatalf("bad: %#v", diff)
   877  	}
   878  }
   879  
   880  // Ensure we nack in a timely manner
   881  func TestEvalBroker_Nack_TimeoutReset(t *testing.T) {
   882  	t.Parallel()
   883  	b := testBroker(t, 50*time.Millisecond)
   884  	b.SetEnabled(true)
   885  
   886  	// Enqueue
   887  	eval := mock.Eval()
   888  	b.Enqueue(eval)
   889  
   890  	// Dequeue
   891  	out, token, err := b.Dequeue(defaultSched, time.Second)
   892  	start := time.Now()
   893  	if err != nil {
   894  		t.Fatalf("err: %v", err)
   895  	}
   896  	if out != eval {
   897  		t.Fatalf("bad: %v", out)
   898  	}
   899  
   900  	// Reset in 20 milliseconds
   901  	time.Sleep(20 * time.Millisecond)
   902  	if err := b.OutstandingReset(out.ID, token); err != nil {
   903  		t.Fatalf("err: %v", err)
   904  	}
   905  
   906  	// Dequeue, should block on Nack timer
   907  	out, _, err = b.Dequeue(defaultSched, time.Second)
   908  	end := time.Now()
   909  	if err != nil {
   910  		t.Fatalf("err: %v", err)
   911  	}
   912  	if out != eval {
   913  		t.Fatalf("bad: %v", out)
   914  	}
   915  
   916  	// Check the nack timer
   917  	if diff := end.Sub(start); diff < 75*time.Millisecond {
   918  		t.Fatalf("bad: %#v", diff)
   919  	}
   920  }
   921  
   922  func TestEvalBroker_PauseResumeNackTimeout(t *testing.T) {
   923  	t.Parallel()
   924  	b := testBroker(t, 50*time.Millisecond)
   925  	b.SetEnabled(true)
   926  
   927  	// Enqueue
   928  	eval := mock.Eval()
   929  	b.Enqueue(eval)
   930  
   931  	// Dequeue
   932  	out, token, err := b.Dequeue(defaultSched, time.Second)
   933  	start := time.Now()
   934  	if err != nil {
   935  		t.Fatalf("err: %v", err)
   936  	}
   937  	if out != eval {
   938  		t.Fatalf("bad: %v", out)
   939  	}
   940  
   941  	// Pause in 20 milliseconds
   942  	time.Sleep(20 * time.Millisecond)
   943  	if err := b.PauseNackTimeout(out.ID, token); err != nil {
   944  		t.Fatalf("err: %v", err)
   945  	}
   946  
   947  	go func() {
   948  		time.Sleep(20 * time.Millisecond)
   949  		if err := b.ResumeNackTimeout(out.ID, token); err != nil {
   950  			t.Fatalf("err: %v", err)
   951  		}
   952  	}()
   953  
   954  	// Dequeue, should block until the timer is resumed
   955  	out, _, err = b.Dequeue(defaultSched, time.Second)
   956  	end := time.Now()
   957  	if err != nil {
   958  		t.Fatalf("err: %v", err)
   959  	}
   960  	if out != eval {
   961  		t.Fatalf("bad: %v", out)
   962  	}
   963  
   964  	// Check the nack timer
   965  	if diff := end.Sub(start); diff < 95*time.Millisecond {
   966  		t.Fatalf("bad: %#v", diff)
   967  	}
   968  }
   969  
   970  func TestEvalBroker_DeliveryLimit(t *testing.T) {
   971  	t.Parallel()
   972  	b := testBroker(t, 0)
   973  	b.SetEnabled(true)
   974  
   975  	eval := mock.Eval()
   976  	b.Enqueue(eval)
   977  
   978  	for i := 0; i < 3; i++ {
   979  		// Dequeue should work
   980  		out, token, err := b.Dequeue(defaultSched, time.Second)
   981  		if err != nil {
   982  			t.Fatalf("err: %v", err)
   983  		}
   984  		if out != eval {
   985  			t.Fatalf("bad : %#v", out)
   986  		}
   987  
   988  		// Nack with wrong token should fail
   989  		err = b.Nack(eval.ID, token)
   990  		if err != nil {
   991  			t.Fatalf("err: %v", err)
   992  		}
   993  	}
   994  
   995  	// Check the stats
   996  	stats := b.Stats()
   997  	if stats.TotalReady != 1 {
   998  		t.Fatalf("bad: %#v", stats)
   999  	}
  1000  	if stats.TotalUnacked != 0 {
  1001  		t.Fatalf("bad: %#v", stats)
  1002  	}
  1003  	if stats.ByScheduler[failedQueue].Ready != 1 {
  1004  		t.Fatalf("bad: %#v", stats)
  1005  	}
  1006  	if stats.ByScheduler[failedQueue].Unacked != 0 {
  1007  		t.Fatalf("bad: %#v", stats)
  1008  	}
  1009  
  1010  	// Dequeue from failed queue
  1011  	out, token, err := b.Dequeue([]string{failedQueue}, time.Second)
  1012  	if err != nil {
  1013  		t.Fatalf("err: %v", err)
  1014  	}
  1015  	if out != eval {
  1016  		t.Fatalf("bad : %#v", out)
  1017  	}
  1018  
  1019  	// Check the stats
  1020  	stats = b.Stats()
  1021  	if stats.TotalReady != 0 {
  1022  		t.Fatalf("bad: %#v", stats)
  1023  	}
  1024  	if stats.TotalUnacked != 1 {
  1025  		t.Fatalf("bad: %#v", stats)
  1026  	}
  1027  	if stats.ByScheduler[failedQueue].Ready != 0 {
  1028  		t.Fatalf("bad: %#v", stats)
  1029  	}
  1030  	if stats.ByScheduler[failedQueue].Unacked != 1 {
  1031  		t.Fatalf("bad: %#v", stats)
  1032  	}
  1033  
  1034  	// Ack finally
  1035  	err = b.Ack(out.ID, token)
  1036  	if err != nil {
  1037  		t.Fatalf("err: %v", err)
  1038  	}
  1039  
  1040  	if _, ok := b.Outstanding(out.ID); ok {
  1041  		t.Fatalf("should not be outstanding")
  1042  	}
  1043  
  1044  	// Check the stats
  1045  	stats = b.Stats()
  1046  	if stats.TotalReady != 0 {
  1047  		t.Fatalf("bad: %#v", stats)
  1048  	}
  1049  	if stats.TotalUnacked != 0 {
  1050  		t.Fatalf("bad: %#v", stats)
  1051  	}
  1052  	if stats.ByScheduler[failedQueue].Ready != 0 {
  1053  		t.Fatalf("bad: %#v", stats.ByScheduler[failedQueue])
  1054  	}
  1055  	if stats.ByScheduler[failedQueue].Unacked != 0 {
  1056  		t.Fatalf("bad: %#v", stats.ByScheduler[failedQueue])
  1057  	}
  1058  }
  1059  
  1060  func TestEvalBroker_AckAtDeliveryLimit(t *testing.T) {
  1061  	t.Parallel()
  1062  	b := testBroker(t, 0)
  1063  	b.SetEnabled(true)
  1064  
  1065  	eval := mock.Eval()
  1066  	b.Enqueue(eval)
  1067  
  1068  	for i := 0; i < 3; i++ {
  1069  		// Dequeue should work
  1070  		out, token, err := b.Dequeue(defaultSched, time.Second)
  1071  		if err != nil {
  1072  			t.Fatalf("err: %v", err)
  1073  		}
  1074  		if out != eval {
  1075  			t.Fatalf("bad : %#v", out)
  1076  		}
  1077  
  1078  		if i == 2 {
  1079  			b.Ack(eval.ID, token)
  1080  		} else {
  1081  			// Nack with wrong token should fail
  1082  			err = b.Nack(eval.ID, token)
  1083  			if err != nil {
  1084  				t.Fatalf("err: %v", err)
  1085  			}
  1086  		}
  1087  	}
  1088  
  1089  	// Check the stats
  1090  	stats := b.Stats()
  1091  	if stats.TotalReady != 0 {
  1092  		t.Fatalf("bad: %#v", stats)
  1093  	}
  1094  	if stats.TotalUnacked != 0 {
  1095  		t.Fatalf("bad: %#v", stats)
  1096  	}
  1097  	if _, ok := stats.ByScheduler[failedQueue]; ok {
  1098  		t.Fatalf("bad: %#v", stats)
  1099  	}
  1100  }
  1101  
  1102  // Ensure fairness between schedulers
  1103  func TestEvalBroker_Wait(t *testing.T) {
  1104  	t.Parallel()
  1105  	b := testBroker(t, 0)
  1106  	b.SetEnabled(true)
  1107  
  1108  	// Create an eval that should wait
  1109  	eval := mock.Eval()
  1110  	eval.Wait = 10 * time.Millisecond
  1111  	b.Enqueue(eval)
  1112  
  1113  	// Verify waiting
  1114  	stats := b.Stats()
  1115  	if stats.TotalReady != 0 {
  1116  		t.Fatalf("bad: %#v", stats)
  1117  	}
  1118  	if stats.TotalWaiting != 1 {
  1119  		t.Fatalf("bad: %#v", stats)
  1120  	}
  1121  
  1122  	// Let the wait elapse
  1123  	time.Sleep(20 * time.Millisecond)
  1124  
  1125  	// Verify ready
  1126  	stats = b.Stats()
  1127  	if stats.TotalReady != 1 {
  1128  		t.Fatalf("bad: %#v", stats)
  1129  	}
  1130  	if stats.TotalWaiting != 0 {
  1131  		t.Fatalf("bad: %#v", stats)
  1132  	}
  1133  
  1134  	// Dequeue should work
  1135  	out, _, err := b.Dequeue(defaultSched, time.Second)
  1136  	if err != nil {
  1137  		t.Fatalf("err: %v", err)
  1138  	}
  1139  	if out != eval {
  1140  		t.Fatalf("bad : %#v", out)
  1141  	}
  1142  }
  1143  
  1144  // Ensure that delayed evaluations work as expected
  1145  func TestEvalBroker_WaitUntil(t *testing.T) {
  1146  	t.Parallel()
  1147  	require := require.New(t)
  1148  	b := testBroker(t, 0)
  1149  	b.SetEnabled(true)
  1150  
  1151  	now := time.Now()
  1152  	// Create a few of evals with WaitUntil set
  1153  	eval1 := mock.Eval()
  1154  	eval1.WaitUntil = now.Add(1 * time.Second)
  1155  	eval1.CreateIndex = 1
  1156  	b.Enqueue(eval1)
  1157  
  1158  	eval2 := mock.Eval()
  1159  	eval2.WaitUntil = now.Add(100 * time.Millisecond)
  1160  	// set CreateIndex to use as a tie breaker when eval2
  1161  	// and eval3 are both in the pending evals heap
  1162  	eval2.CreateIndex = 2
  1163  	b.Enqueue(eval2)
  1164  
  1165  	eval3 := mock.Eval()
  1166  	eval3.WaitUntil = now.Add(20 * time.Millisecond)
  1167  	eval3.CreateIndex = 1
  1168  	b.Enqueue(eval3)
  1169  	require.Equal(3, b.stats.TotalWaiting)
  1170  	// sleep enough for two evals to be ready
  1171  	time.Sleep(200 * time.Millisecond)
  1172  
  1173  	// first dequeue should return eval3
  1174  	out, _, err := b.Dequeue(defaultSched, time.Second)
  1175  	require.Nil(err)
  1176  	require.Equal(eval3, out)
  1177  
  1178  	// second dequeue should return eval2
  1179  	out, _, err = b.Dequeue(defaultSched, time.Second)
  1180  	require.Nil(err)
  1181  	require.Equal(eval2, out)
  1182  
  1183  	// third dequeue should return eval1
  1184  	out, _, err = b.Dequeue(defaultSched, 2*time.Second)
  1185  	require.Nil(err)
  1186  	require.Equal(eval1, out)
  1187  	require.Equal(0, b.stats.TotalWaiting)
  1188  }
  1189  
  1190  // Ensure that priority is taken into account when enqueueing many evaluations.
  1191  func TestEvalBroker_EnqueueAll_Dequeue_Fair(t *testing.T) {
  1192  	t.Parallel()
  1193  	b := testBroker(t, 0)
  1194  	b.SetEnabled(true)
  1195  
  1196  	// Start with a blocked dequeue
  1197  	outCh := make(chan *structs.Evaluation, 1)
  1198  	go func() {
  1199  		start := time.Now()
  1200  		out, _, err := b.Dequeue(defaultSched, time.Second)
  1201  		end := time.Now()
  1202  		outCh <- out
  1203  		if err != nil {
  1204  			t.Fatalf("err: %v", err)
  1205  		}
  1206  		if d := end.Sub(start); d < 5*time.Millisecond {
  1207  			t.Fatalf("bad: %v", d)
  1208  		}
  1209  	}()
  1210  
  1211  	// Wait for a bit
  1212  	time.Sleep(5 * time.Millisecond)
  1213  
  1214  	// Enqueue
  1215  	evals := make(map[*structs.Evaluation]string, 8)
  1216  	expectedPriority := 90
  1217  	for i := 10; i <= expectedPriority; i += 10 {
  1218  		eval := mock.Eval()
  1219  		eval.Priority = i
  1220  		evals[eval] = ""
  1221  
  1222  	}
  1223  	b.EnqueueAll(evals)
  1224  
  1225  	// Ensure dequeue
  1226  	select {
  1227  	case out := <-outCh:
  1228  		if out.Priority != expectedPriority {
  1229  			t.Fatalf("bad: %v", out)
  1230  		}
  1231  	case <-time.After(time.Second):
  1232  		t.Fatalf("timeout")
  1233  	}
  1234  }
  1235  
  1236  func TestEvalBroker_EnqueueAll_Requeue_Ack(t *testing.T) {
  1237  	t.Parallel()
  1238  	b := testBroker(t, 0)
  1239  	b.SetEnabled(true)
  1240  
  1241  	// Create the evaluation, enqueue and dequeue
  1242  	eval := mock.Eval()
  1243  	b.Enqueue(eval)
  1244  
  1245  	out, token, err := b.Dequeue(defaultSched, time.Second)
  1246  	if err != nil {
  1247  		t.Fatalf("err: %v", err)
  1248  	}
  1249  	if out != eval {
  1250  		t.Fatalf("bad : %#v", out)
  1251  	}
  1252  
  1253  	// Requeue the same evaluation.
  1254  	b.EnqueueAll(map[*structs.Evaluation]string{eval: token})
  1255  
  1256  	// The stats should show one unacked
  1257  	stats := b.Stats()
  1258  	if stats.TotalReady != 0 {
  1259  		t.Fatalf("bad: %#v", stats)
  1260  	}
  1261  	if stats.TotalUnacked != 1 {
  1262  		t.Fatalf("bad: %#v", stats)
  1263  	}
  1264  
  1265  	// Ack the evaluation.
  1266  	if err := b.Ack(eval.ID, token); err != nil {
  1267  		t.Fatalf("err: %v", err)
  1268  	}
  1269  
  1270  	// Check stats again as this should cause the re-enqueued one to transition
  1271  	// into the ready state
  1272  	stats = b.Stats()
  1273  	if stats.TotalReady != 1 {
  1274  		t.Fatalf("bad: %#v", stats)
  1275  	}
  1276  	if stats.TotalUnacked != 0 {
  1277  		t.Fatalf("bad: %#v", stats)
  1278  	}
  1279  
  1280  	// Another dequeue should be successful
  1281  	out2, token2, err := b.Dequeue(defaultSched, time.Second)
  1282  	if err != nil {
  1283  		t.Fatalf("err: %v", err)
  1284  	}
  1285  	if out2 != eval {
  1286  		t.Fatalf("bad : %#v", out)
  1287  	}
  1288  	if token == token2 {
  1289  		t.Fatalf("bad : %s and %s", token, token2)
  1290  	}
  1291  }
  1292  
  1293  func TestEvalBroker_EnqueueAll_Requeue_Nack(t *testing.T) {
  1294  	t.Parallel()
  1295  	b := testBroker(t, 0)
  1296  	b.SetEnabled(true)
  1297  
  1298  	// Create the evaluation, enqueue and dequeue
  1299  	eval := mock.Eval()
  1300  	b.Enqueue(eval)
  1301  
  1302  	out, token, err := b.Dequeue(defaultSched, time.Second)
  1303  	if err != nil {
  1304  		t.Fatalf("err: %v", err)
  1305  	}
  1306  	if out != eval {
  1307  		t.Fatalf("bad : %#v", out)
  1308  	}
  1309  
  1310  	// Requeue the same evaluation.
  1311  	b.EnqueueAll(map[*structs.Evaluation]string{eval: token})
  1312  
  1313  	// The stats should show one unacked
  1314  	stats := b.Stats()
  1315  	if stats.TotalReady != 0 {
  1316  		t.Fatalf("bad: %#v", stats)
  1317  	}
  1318  	if stats.TotalUnacked != 1 {
  1319  		t.Fatalf("bad: %#v", stats)
  1320  	}
  1321  
  1322  	// Nack the evaluation.
  1323  	if err := b.Nack(eval.ID, token); err != nil {
  1324  		t.Fatalf("err: %v", err)
  1325  	}
  1326  
  1327  	// Check stats again as this should cause the re-enqueued one to be dropped
  1328  	testutil.WaitForResult(func() (bool, error) {
  1329  		stats = b.Stats()
  1330  		if stats.TotalReady != 1 {
  1331  			return false, fmt.Errorf("bad: %#v", stats)
  1332  		}
  1333  		if stats.TotalUnacked != 0 {
  1334  			return false, fmt.Errorf("bad: %#v", stats)
  1335  		}
  1336  		if len(b.requeue) != 0 {
  1337  			return false, fmt.Errorf("bad: %#v", b.requeue)
  1338  		}
  1339  
  1340  		return true, nil
  1341  	}, func(e error) {
  1342  		t.Fatal(e)
  1343  	})
  1344  }
  1345  
  1346  func TestEvalBroker_NamespacedJobs(t *testing.T) {
  1347  	t.Parallel()
  1348  	b := testBroker(t, 0)
  1349  	b.SetEnabled(true)
  1350  
  1351  	// Create evals with the same jobid and different namespace
  1352  	jobId := "test-jobID"
  1353  
  1354  	eval1 := mock.Eval()
  1355  	eval1.JobID = jobId
  1356  	eval1.Namespace = "n1"
  1357  	b.Enqueue(eval1)
  1358  
  1359  	// This eval should not block
  1360  	eval2 := mock.Eval()
  1361  	eval2.JobID = jobId
  1362  	eval2.Namespace = "default"
  1363  	b.Enqueue(eval2)
  1364  
  1365  	// This eval should block
  1366  	eval3 := mock.Eval()
  1367  	eval3.JobID = jobId
  1368  	eval3.Namespace = "default"
  1369  	b.Enqueue(eval3)
  1370  
  1371  	require := require.New(t)
  1372  	out1, _, err := b.Dequeue(defaultSched, 5*time.Millisecond)
  1373  	require.Nil(err)
  1374  	require.Equal(eval1.ID, out1.ID)
  1375  
  1376  	out2, _, err := b.Dequeue(defaultSched, 5*time.Millisecond)
  1377  	require.Nil(err)
  1378  	require.Equal(eval2.ID, out2.ID)
  1379  
  1380  	out3, _, err := b.Dequeue(defaultSched, 5*time.Millisecond)
  1381  	require.Nil(err)
  1382  	require.Nil(out3)
  1383  
  1384  	require.Equal(1, len(b.blocked))
  1385  
  1386  }