github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/nomad/alloc_endpoint_test.go (about)

     1  package nomad
     2  
     3  import (
     4  	"reflect"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/hashicorp/net-rpc-msgpackrpc"
     9  	"github.com/ncodes/nomad/nomad/mock"
    10  	"github.com/ncodes/nomad/nomad/structs"
    11  	"github.com/ncodes/nomad/testutil"
    12  )
    13  
    14  func TestAllocEndpoint_List(t *testing.T) {
    15  	s1 := testServer(t, nil)
    16  	defer s1.Shutdown()
    17  	codec := rpcClient(t, s1)
    18  	testutil.WaitForLeader(t, s1.RPC)
    19  
    20  	// Create the register request
    21  	alloc := mock.Alloc()
    22  	summary := mock.JobSummary(alloc.JobID)
    23  	state := s1.fsm.State()
    24  
    25  	if err := state.UpsertJobSummary(999, summary); err != nil {
    26  		t.Fatalf("err: %v", err)
    27  	}
    28  	if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil {
    29  		t.Fatalf("err: %v", err)
    30  	}
    31  
    32  	// Lookup the allocations
    33  	get := &structs.AllocListRequest{
    34  		QueryOptions: structs.QueryOptions{Region: "global"},
    35  	}
    36  	var resp structs.AllocListResponse
    37  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp); err != nil {
    38  		t.Fatalf("err: %v", err)
    39  	}
    40  	if resp.Index != 1000 {
    41  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
    42  	}
    43  
    44  	if len(resp.Allocations) != 1 {
    45  		t.Fatalf("bad: %#v", resp.Allocations)
    46  	}
    47  	if resp.Allocations[0].ID != alloc.ID {
    48  		t.Fatalf("bad: %#v", resp.Allocations[0])
    49  	}
    50  
    51  	// Lookup the allocations by prefix
    52  	get = &structs.AllocListRequest{
    53  		QueryOptions: structs.QueryOptions{Region: "global", Prefix: alloc.ID[:4]},
    54  	}
    55  
    56  	var resp2 structs.AllocListResponse
    57  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", get, &resp2); err != nil {
    58  		t.Fatalf("err: %v", err)
    59  	}
    60  	if resp2.Index != 1000 {
    61  		t.Fatalf("Bad index: %d %d", resp2.Index, 1000)
    62  	}
    63  
    64  	if len(resp2.Allocations) != 1 {
    65  		t.Fatalf("bad: %#v", resp2.Allocations)
    66  	}
    67  	if resp2.Allocations[0].ID != alloc.ID {
    68  		t.Fatalf("bad: %#v", resp2.Allocations[0])
    69  	}
    70  }
    71  
    72  func TestAllocEndpoint_List_Blocking(t *testing.T) {
    73  	s1 := testServer(t, nil)
    74  	defer s1.Shutdown()
    75  	state := s1.fsm.State()
    76  	codec := rpcClient(t, s1)
    77  	testutil.WaitForLeader(t, s1.RPC)
    78  
    79  	// Create the alloc
    80  	alloc := mock.Alloc()
    81  
    82  	summary := mock.JobSummary(alloc.JobID)
    83  	if err := state.UpsertJobSummary(1, summary); err != nil {
    84  		t.Fatalf("err: %v", err)
    85  	}
    86  	// Upsert alloc triggers watches
    87  	time.AfterFunc(100*time.Millisecond, func() {
    88  		if err := state.UpsertAllocs(2, []*structs.Allocation{alloc}); err != nil {
    89  			t.Fatalf("err: %v", err)
    90  		}
    91  	})
    92  
    93  	req := &structs.AllocListRequest{
    94  		QueryOptions: structs.QueryOptions{
    95  			Region:        "global",
    96  			MinQueryIndex: 1,
    97  		},
    98  	}
    99  	start := time.Now()
   100  	var resp structs.AllocListResponse
   101  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp); err != nil {
   102  		t.Fatalf("err: %v", err)
   103  	}
   104  
   105  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   106  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   107  	}
   108  	if resp.Index != 2 {
   109  		t.Fatalf("Bad index: %d %d", resp.Index, 2)
   110  	}
   111  	if len(resp.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID {
   112  		t.Fatalf("bad: %#v", resp.Allocations)
   113  	}
   114  
   115  	// Client updates trigger watches
   116  	alloc2 := mock.Alloc()
   117  	alloc2.ID = alloc.ID
   118  	alloc2.ClientStatus = structs.AllocClientStatusRunning
   119  	time.AfterFunc(100*time.Millisecond, func() {
   120  		state.UpsertJobSummary(3, mock.JobSummary(alloc2.JobID))
   121  		if err := state.UpdateAllocsFromClient(4, []*structs.Allocation{alloc2}); err != nil {
   122  			t.Fatalf("err: %v", err)
   123  		}
   124  	})
   125  
   126  	req.MinQueryIndex = 3
   127  	start = time.Now()
   128  	var resp2 structs.AllocListResponse
   129  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.List", req, &resp2); err != nil {
   130  		t.Fatalf("err: %v", err)
   131  	}
   132  
   133  	if elapsed := time.Since(start); elapsed < 100*time.Millisecond {
   134  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp2)
   135  	}
   136  	if resp2.Index != 4 {
   137  		t.Fatalf("Bad index: %d %d", resp2.Index, 4)
   138  	}
   139  	if len(resp2.Allocations) != 1 || resp.Allocations[0].ID != alloc.ID ||
   140  		resp2.Allocations[0].ClientStatus != structs.AllocClientStatusRunning {
   141  		t.Fatalf("bad: %#v", resp2.Allocations)
   142  	}
   143  }
   144  
   145  func TestAllocEndpoint_GetAlloc(t *testing.T) {
   146  	s1 := testServer(t, nil)
   147  	defer s1.Shutdown()
   148  	codec := rpcClient(t, s1)
   149  	testutil.WaitForLeader(t, s1.RPC)
   150  
   151  	// Create the register request
   152  	alloc := mock.Alloc()
   153  	state := s1.fsm.State()
   154  	state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID))
   155  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc})
   156  	if err != nil {
   157  		t.Fatalf("err: %v", err)
   158  	}
   159  
   160  	// Lookup the jobs
   161  	get := &structs.AllocSpecificRequest{
   162  		AllocID:      alloc.ID,
   163  		QueryOptions: structs.QueryOptions{Region: "global"},
   164  	}
   165  	var resp structs.SingleAllocResponse
   166  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil {
   167  		t.Fatalf("err: %v", err)
   168  	}
   169  	if resp.Index != 1000 {
   170  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   171  	}
   172  
   173  	if !reflect.DeepEqual(alloc, resp.Alloc) {
   174  		t.Fatalf("bad: %#v", resp.Alloc)
   175  	}
   176  }
   177  
   178  func TestAllocEndpoint_GetAlloc_Blocking(t *testing.T) {
   179  	s1 := testServer(t, nil)
   180  	defer s1.Shutdown()
   181  	state := s1.fsm.State()
   182  	codec := rpcClient(t, s1)
   183  	testutil.WaitForLeader(t, s1.RPC)
   184  
   185  	// Create the allocs
   186  	alloc1 := mock.Alloc()
   187  	alloc2 := mock.Alloc()
   188  
   189  	// First create an unrelated alloc
   190  	time.AfterFunc(100*time.Millisecond, func() {
   191  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   192  		err := state.UpsertAllocs(100, []*structs.Allocation{alloc1})
   193  		if err != nil {
   194  			t.Fatalf("err: %v", err)
   195  		}
   196  	})
   197  
   198  	// Create the alloc we are watching later
   199  	time.AfterFunc(200*time.Millisecond, func() {
   200  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
   201  		err := state.UpsertAllocs(200, []*structs.Allocation{alloc2})
   202  		if err != nil {
   203  			t.Fatalf("err: %v", err)
   204  		}
   205  	})
   206  
   207  	// Lookup the allocs
   208  	get := &structs.AllocSpecificRequest{
   209  		AllocID: alloc2.ID,
   210  		QueryOptions: structs.QueryOptions{
   211  			Region:        "global",
   212  			MinQueryIndex: 150,
   213  		},
   214  	}
   215  	var resp structs.SingleAllocResponse
   216  	start := time.Now()
   217  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAlloc", get, &resp); err != nil {
   218  		t.Fatalf("err: %v", err)
   219  	}
   220  
   221  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   222  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   223  	}
   224  	if resp.Index != 200 {
   225  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   226  	}
   227  	if resp.Alloc == nil || resp.Alloc.ID != alloc2.ID {
   228  		t.Fatalf("bad: %#v", resp.Alloc)
   229  	}
   230  }
   231  
   232  func TestAllocEndpoint_GetAllocs(t *testing.T) {
   233  	s1 := testServer(t, nil)
   234  	defer s1.Shutdown()
   235  	codec := rpcClient(t, s1)
   236  	testutil.WaitForLeader(t, s1.RPC)
   237  
   238  	// Create the register request
   239  	alloc := mock.Alloc()
   240  	alloc2 := mock.Alloc()
   241  	state := s1.fsm.State()
   242  	state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID))
   243  	state.UpsertJobSummary(999, mock.JobSummary(alloc2.JobID))
   244  	err := state.UpsertAllocs(1000, []*structs.Allocation{alloc, alloc2})
   245  	if err != nil {
   246  		t.Fatalf("err: %v", err)
   247  	}
   248  
   249  	// Lookup the allocs
   250  	get := &structs.AllocsGetRequest{
   251  		AllocIDs: []string{alloc.ID, alloc2.ID},
   252  		QueryOptions: structs.QueryOptions{
   253  			Region: "global",
   254  		},
   255  	}
   256  	var resp structs.AllocsGetResponse
   257  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil {
   258  		t.Fatalf("err: %v", err)
   259  	}
   260  	if resp.Index != 1000 {
   261  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   262  	}
   263  
   264  	if len(resp.Allocs) != 2 {
   265  		t.Fatalf("bad: %#v", resp.Allocs)
   266  	}
   267  
   268  	// Lookup non-existent allocs.
   269  	get = &structs.AllocsGetRequest{
   270  		AllocIDs:     []string{"foo"},
   271  		QueryOptions: structs.QueryOptions{Region: "global"},
   272  	}
   273  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err == nil {
   274  		t.Fatalf("expect error")
   275  	}
   276  }
   277  
   278  func TestAllocEndpoint_GetAllocs_Blocking(t *testing.T) {
   279  	s1 := testServer(t, nil)
   280  	defer s1.Shutdown()
   281  	state := s1.fsm.State()
   282  	codec := rpcClient(t, s1)
   283  	testutil.WaitForLeader(t, s1.RPC)
   284  
   285  	// Create the allocs
   286  	alloc1 := mock.Alloc()
   287  	alloc2 := mock.Alloc()
   288  
   289  	// First create an unrelated alloc
   290  	time.AfterFunc(100*time.Millisecond, func() {
   291  		state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID))
   292  		err := state.UpsertAllocs(100, []*structs.Allocation{alloc1})
   293  		if err != nil {
   294  			t.Fatalf("err: %v", err)
   295  		}
   296  	})
   297  
   298  	// Create the alloc we are watching later
   299  	time.AfterFunc(200*time.Millisecond, func() {
   300  		state.UpsertJobSummary(199, mock.JobSummary(alloc2.JobID))
   301  		err := state.UpsertAllocs(200, []*structs.Allocation{alloc2})
   302  		if err != nil {
   303  			t.Fatalf("err: %v", err)
   304  		}
   305  	})
   306  
   307  	// Lookup the allocs
   308  	get := &structs.AllocsGetRequest{
   309  		AllocIDs: []string{alloc1.ID, alloc2.ID},
   310  		QueryOptions: structs.QueryOptions{
   311  			Region:        "global",
   312  			MinQueryIndex: 150,
   313  		},
   314  	}
   315  	var resp structs.AllocsGetResponse
   316  	start := time.Now()
   317  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil {
   318  		t.Fatalf("err: %v", err)
   319  	}
   320  
   321  	if elapsed := time.Since(start); elapsed < 200*time.Millisecond {
   322  		t.Fatalf("should block (returned in %s) %#v", elapsed, resp)
   323  	}
   324  	if resp.Index != 200 {
   325  		t.Fatalf("Bad index: %d %d", resp.Index, 200)
   326  	}
   327  	if len(resp.Allocs) != 2 {
   328  		t.Fatalf("bad: %#v", resp.Allocs)
   329  	}
   330  }