github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/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/hashicorp/nomad/nomad/mock"
    10  	"github.com/hashicorp/nomad/nomad/structs"
    11  	"github.com/hashicorp/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(999, 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: 50,
   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{Region: "global"},
   253  	}
   254  	var resp structs.AllocsGetResponse
   255  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err != nil {
   256  		t.Fatalf("err: %v", err)
   257  	}
   258  	if resp.Index != 1000 {
   259  		t.Fatalf("Bad index: %d %d", resp.Index, 1000)
   260  	}
   261  
   262  	if len(resp.Allocs) != 2 {
   263  		t.Fatalf("bad: %#v", resp.Allocs)
   264  	}
   265  
   266  	// Lookup non-existent allocs.
   267  	get = &structs.AllocsGetRequest{
   268  		AllocIDs:     []string{"foo"},
   269  		QueryOptions: structs.QueryOptions{Region: "global"},
   270  	}
   271  	if err := msgpackrpc.CallWithCodec(codec, "Alloc.GetAllocs", get, &resp); err == nil {
   272  		t.Fatalf("expect error")
   273  	}
   274  }