github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/nomad/drainer/draining_node_test.go (about) 1 package drainer 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/hashicorp/nomad/nomad/mock" 8 "github.com/hashicorp/nomad/nomad/state" 9 "github.com/hashicorp/nomad/nomad/structs" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 // testDrainingNode creates a *drainingNode with a 1h deadline but no allocs 15 func testDrainingNode(t *testing.T) *drainingNode { 16 t.Helper() 17 state := state.TestStateStore(t) 18 node := mock.Node() 19 node.DrainStrategy = &structs.DrainStrategy{ 20 DrainSpec: structs.DrainSpec{ 21 Deadline: time.Hour, 22 }, 23 ForceDeadline: time.Now().Add(time.Hour), 24 } 25 26 require.Nil(t, state.UpsertNode(100, node)) 27 return NewDrainingNode(node, state) 28 } 29 30 func assertDrainingNode(t *testing.T, dn *drainingNode, isDone bool, remaining, running int) { 31 t.Helper() 32 33 done, err := dn.IsDone() 34 require.Nil(t, err) 35 assert.Equal(t, isDone, done, "IsDone mismatch") 36 37 allocs, err := dn.RemainingAllocs() 38 require.Nil(t, err) 39 assert.Len(t, allocs, remaining, "RemainingAllocs mismatch") 40 41 jobs, err := dn.DrainingJobs() 42 require.Nil(t, err) 43 assert.Len(t, jobs, running, "DrainingJobs mismatch") 44 } 45 46 func TestDrainingNode_Table(t *testing.T) { 47 cases := []struct { 48 name string 49 isDone bool 50 remaining int 51 running int 52 setup func(*testing.T, *drainingNode) 53 }{ 54 { 55 name: "Empty", 56 isDone: true, 57 remaining: 0, 58 running: 0, 59 setup: func(*testing.T, *drainingNode) {}, 60 }, 61 { 62 name: "Batch", 63 isDone: false, 64 remaining: 1, 65 running: 1, 66 setup: func(t *testing.T, dn *drainingNode) { 67 alloc := mock.BatchAlloc() 68 alloc.NodeID = dn.node.ID 69 require.Nil(t, dn.state.UpsertJob(101, alloc.Job)) 70 require.Nil(t, dn.state.UpsertAllocs(102, []*structs.Allocation{alloc})) 71 }, 72 }, 73 { 74 name: "Service", 75 isDone: false, 76 remaining: 1, 77 running: 1, 78 setup: func(t *testing.T, dn *drainingNode) { 79 alloc := mock.Alloc() 80 alloc.NodeID = dn.node.ID 81 require.Nil(t, dn.state.UpsertJob(101, alloc.Job)) 82 require.Nil(t, dn.state.UpsertAllocs(102, []*structs.Allocation{alloc})) 83 }, 84 }, 85 { 86 name: "System", 87 isDone: true, 88 remaining: 1, 89 running: 0, 90 setup: func(t *testing.T, dn *drainingNode) { 91 alloc := mock.SystemAlloc() 92 alloc.NodeID = dn.node.ID 93 require.Nil(t, dn.state.UpsertJob(101, alloc.Job)) 94 require.Nil(t, dn.state.UpsertAllocs(102, []*structs.Allocation{alloc})) 95 }, 96 }, 97 { 98 name: "AllTerminal", 99 isDone: true, 100 remaining: 0, 101 running: 0, 102 setup: func(t *testing.T, dn *drainingNode) { 103 allocs := []*structs.Allocation{mock.Alloc(), mock.BatchAlloc(), mock.SystemAlloc()} 104 for _, a := range allocs { 105 a.NodeID = dn.node.ID 106 require.Nil(t, dn.state.UpsertJob(101, a.Job)) 107 } 108 require.Nil(t, dn.state.UpsertAllocs(102, allocs)) 109 110 // StateStore doesn't like inserting new allocs 111 // with a terminal status, so set the status in 112 // a second pass 113 for _, a := range allocs { 114 a.ClientStatus = structs.AllocClientStatusComplete 115 } 116 require.Nil(t, dn.state.UpsertAllocs(103, allocs)) 117 }, 118 }, 119 { 120 name: "ServiceTerminal", 121 isDone: false, 122 remaining: 2, 123 running: 1, 124 setup: func(t *testing.T, dn *drainingNode) { 125 allocs := []*structs.Allocation{mock.Alloc(), mock.BatchAlloc(), mock.SystemAlloc()} 126 for _, a := range allocs { 127 a.NodeID = dn.node.ID 128 require.Nil(t, dn.state.UpsertJob(101, a.Job)) 129 } 130 require.Nil(t, dn.state.UpsertAllocs(102, allocs)) 131 132 // Set only the service job as terminal 133 allocs[0].ClientStatus = structs.AllocClientStatusComplete 134 require.Nil(t, dn.state.UpsertAllocs(103, allocs)) 135 }, 136 }, 137 { 138 name: "AllTerminalButBatch", 139 isDone: false, 140 remaining: 1, 141 running: 1, 142 setup: func(t *testing.T, dn *drainingNode) { 143 allocs := []*structs.Allocation{mock.Alloc(), mock.BatchAlloc(), mock.SystemAlloc()} 144 for _, a := range allocs { 145 a.NodeID = dn.node.ID 146 require.Nil(t, dn.state.UpsertJob(101, a.Job)) 147 } 148 require.Nil(t, dn.state.UpsertAllocs(102, allocs)) 149 150 // Set only the service and batch jobs as terminal 151 allocs[0].ClientStatus = structs.AllocClientStatusComplete 152 allocs[2].ClientStatus = structs.AllocClientStatusComplete 153 require.Nil(t, dn.state.UpsertAllocs(103, allocs)) 154 }, 155 }, 156 { 157 name: "AllTerminalButSystem", 158 isDone: true, 159 remaining: 1, 160 running: 0, 161 setup: func(t *testing.T, dn *drainingNode) { 162 allocs := []*structs.Allocation{mock.Alloc(), mock.BatchAlloc(), mock.SystemAlloc()} 163 for _, a := range allocs { 164 a.NodeID = dn.node.ID 165 require.Nil(t, dn.state.UpsertJob(101, a.Job)) 166 } 167 require.Nil(t, dn.state.UpsertAllocs(102, allocs)) 168 169 // Set only the service and batch jobs as terminal 170 allocs[0].ClientStatus = structs.AllocClientStatusComplete 171 allocs[1].ClientStatus = structs.AllocClientStatusComplete 172 require.Nil(t, dn.state.UpsertAllocs(103, allocs)) 173 }, 174 }, 175 { 176 name: "HalfTerminal", 177 isDone: false, 178 remaining: 3, 179 running: 2, 180 setup: func(t *testing.T, dn *drainingNode) { 181 allocs := []*structs.Allocation{ 182 mock.Alloc(), 183 mock.BatchAlloc(), 184 mock.SystemAlloc(), 185 mock.Alloc(), 186 mock.BatchAlloc(), 187 mock.SystemAlloc(), 188 } 189 for _, a := range allocs { 190 a.NodeID = dn.node.ID 191 require.Nil(t, dn.state.UpsertJob(101, a.Job)) 192 } 193 require.Nil(t, dn.state.UpsertAllocs(102, allocs)) 194 195 // Set only the service and batch jobs as terminal 196 allocs[0].ClientStatus = structs.AllocClientStatusComplete 197 allocs[1].ClientStatus = structs.AllocClientStatusComplete 198 allocs[2].ClientStatus = structs.AllocClientStatusComplete 199 require.Nil(t, dn.state.UpsertAllocs(103, allocs)) 200 }, 201 }, 202 } 203 204 // Default test drainingNode has no allocs, so it should be done and 205 // have no remaining allocs. 206 for _, tc := range cases { 207 tc := tc 208 t.Run(tc.name, func(t *testing.T) { 209 t.Parallel() 210 dn := testDrainingNode(t) 211 tc.setup(t, dn) 212 assertDrainingNode(t, dn, tc.isDone, tc.remaining, tc.running) 213 }) 214 } 215 }