github.com/kardianos/nomad@v0.1.3-0.20151022182107-b13df73ee850/client/alloc_runner_test.go (about)

     1  package client
     2  
     3  import (
     4  	"os"
     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  
    12  	ctestutil "github.com/hashicorp/nomad/client/testutil"
    13  )
    14  
    15  type MockAllocStateUpdater struct {
    16  	Count  int
    17  	Allocs []*structs.Allocation
    18  	Err    error
    19  }
    20  
    21  func (m *MockAllocStateUpdater) Update(alloc *structs.Allocation) error {
    22  	m.Count += 1
    23  	m.Allocs = append(m.Allocs, alloc)
    24  	return m.Err
    25  }
    26  
    27  func testAllocRunner() (*MockAllocStateUpdater, *AllocRunner) {
    28  	logger := testLogger()
    29  	conf := DefaultConfig()
    30  	conf.StateDir = os.TempDir()
    31  	conf.AllocDir = os.TempDir()
    32  	upd := &MockAllocStateUpdater{}
    33  	alloc := mock.Alloc()
    34  	ar := NewAllocRunner(logger, conf, upd.Update, alloc)
    35  	return upd, ar
    36  }
    37  
    38  func TestAllocRunner_SimpleRun(t *testing.T) {
    39  	ctestutil.ExecCompatible(t)
    40  	upd, ar := testAllocRunner()
    41  	go ar.Run()
    42  	defer ar.Destroy()
    43  
    44  	testutil.WaitForResult(func() (bool, error) {
    45  		if upd.Count == 0 {
    46  			return false, nil
    47  		}
    48  		last := upd.Allocs[upd.Count-1]
    49  		return last.ClientStatus == structs.AllocClientStatusDead, nil
    50  	}, func(err error) {
    51  		t.Fatalf("err: %v", err)
    52  	})
    53  }
    54  
    55  func TestAllocRunner_Destroy(t *testing.T) {
    56  	ctestutil.ExecCompatible(t)
    57  	upd, ar := testAllocRunner()
    58  
    59  	// Ensure task takes some time
    60  	task := ar.alloc.Job.TaskGroups[0].Tasks[0]
    61  	task.Config["command"] = "/bin/sleep"
    62  	task.Config["args"] = "10"
    63  	go ar.Run()
    64  	start := time.Now()
    65  
    66  	// Begin the tear down
    67  	go func() {
    68  		time.Sleep(100 * time.Millisecond)
    69  		ar.Destroy()
    70  	}()
    71  
    72  	testutil.WaitForResult(func() (bool, error) {
    73  		if upd.Count == 0 {
    74  			return false, nil
    75  		}
    76  		last := upd.Allocs[upd.Count-1]
    77  		return last.ClientStatus == structs.AllocClientStatusDead, nil
    78  	}, func(err error) {
    79  		t.Fatalf("err: %v %#v %#v", err, upd.Allocs[0], ar.taskStatus)
    80  	})
    81  
    82  	if time.Since(start) > time.Second {
    83  		t.Fatalf("took too long to terminate")
    84  	}
    85  }
    86  
    87  func TestAllocRunner_Update(t *testing.T) {
    88  	ctestutil.ExecCompatible(t)
    89  	upd, ar := testAllocRunner()
    90  
    91  	// Ensure task takes some time
    92  	task := ar.alloc.Job.TaskGroups[0].Tasks[0]
    93  	task.Config["command"] = "/bin/sleep"
    94  	task.Config["args"] = "10"
    95  	go ar.Run()
    96  	defer ar.Destroy()
    97  	start := time.Now()
    98  
    99  	// Update the alloc definition
   100  	newAlloc := new(structs.Allocation)
   101  	*newAlloc = *ar.alloc
   102  	newAlloc.DesiredStatus = structs.AllocDesiredStatusStop
   103  	ar.Update(newAlloc)
   104  
   105  	testutil.WaitForResult(func() (bool, error) {
   106  		if upd.Count == 0 {
   107  			return false, nil
   108  		}
   109  		last := upd.Allocs[upd.Count-1]
   110  		return last.ClientStatus == structs.AllocClientStatusDead, nil
   111  	}, func(err error) {
   112  		t.Fatalf("err: %v %#v %#v", err, upd.Allocs[0], ar.taskStatus)
   113  	})
   114  
   115  	if time.Since(start) > time.Second {
   116  		t.Fatalf("took too long to terminate")
   117  	}
   118  }
   119  
   120  /*
   121  TODO: This test is disabled til a follow-up api changes the restore state interface.
   122  The driver/executor interface will be changed from Open to Cleanup, in which
   123  clean-up tears down previous allocs.
   124  
   125  func TestAllocRunner_SaveRestoreState(t *testing.T) {
   126  	upd, ar := testAllocRunner()
   127  
   128  	// Ensure task takes some time
   129  	task := ar.alloc.Job.TaskGroups[0].Tasks[0]
   130  	task.Config["command"] = "/bin/sleep"
   131  	task.Config["args"] = "10"
   132  	go ar.Run()
   133  	defer ar.Destroy()
   134  
   135  	// Snapshot state
   136  	time.Sleep(200 * time.Millisecond)
   137  	err := ar.SaveState()
   138  	if err != nil {
   139  		t.Fatalf("err: %v", err)
   140  	}
   141  
   142  	// Create a new alloc runner
   143  	ar2 := NewAllocRunner(ar.logger, ar.config, upd.Update,
   144  		&structs.Allocation{ID: ar.alloc.ID})
   145  	err = ar2.RestoreState()
   146  	if err != nil {
   147  		t.Fatalf("err: %v", err)
   148  	}
   149  	go ar2.Run()
   150  	defer ar2.Destroy()
   151  
   152  	// Destroy and wait
   153  	ar2.Destroy()
   154  	start := time.Now()
   155  
   156  	testutil.WaitForResult(func() (bool, error) {
   157  		if upd.Count == 0 {
   158  			return false, nil
   159  		}
   160  		last := upd.Allocs[upd.Count-1]
   161  		return last.ClientStatus == structs.AllocClientStatusDead, nil
   162  	}, func(err error) {
   163  		t.Fatalf("err: %v %#v %#v", err, upd.Allocs[0], ar.taskStatus)
   164  	})
   165  
   166  	if time.Since(start) > time.Second {
   167  		t.Fatalf("took too long to terminate")
   168  	}
   169  }
   170  */