github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/model/audit_test.go (about) 1 package model 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/evergreen-ci/evergreen" 8 "github.com/evergreen-ci/evergreen/db" 9 "github.com/evergreen-ci/evergreen/model/host" 10 "github.com/evergreen-ci/evergreen/model/task" 11 "github.com/evergreen-ci/evergreen/testutil" 12 . "github.com/smartystreets/goconvey/convey" 13 ) 14 15 func TestHostTaskAuditing(t *testing.T) { 16 Convey("With pre-made sets of mappings", t, func() { 17 Convey("a valid mapping should return no inconsistencies", func() { 18 h2t := map[string]string{"h1": "t1", "h2": "t2", "h3": "t3"} 19 t2h := map[string]string{"t1": "h1", "t2": "h2", "t3": "h3"} 20 So(len(auditHostTaskMapping(h2t, t2h)), ShouldEqual, 0) 21 }) 22 Convey("a mismapped host should return one inconsistency", func() { 23 h2t := map[string]string{"h1": "t1", "h2": "t2", "h3": "t3", "h4": "t1"} 24 t2h := map[string]string{"t1": "h4", "t2": "h2", "t3": "h3"} 25 out := auditHostTaskMapping(h2t, t2h) 26 So(len(out), ShouldEqual, 1) 27 So(out[0], ShouldResemble, HostTaskInconsistency{ 28 Host: "h1", HostTaskCache: "t1", Task: "t1", TaskHostCache: "h4", 29 }) 30 }) 31 Convey("a swapped host and task should return four inconsistencies", func() { 32 h2t := map[string]string{"h1": "t3", "h2": "t2", "h3": "t1"} 33 t2h := map[string]string{"t1": "h1", "t2": "h2", "t3": "h3"} 34 out := auditHostTaskMapping(h2t, t2h) 35 So(len(out), ShouldEqual, 4) 36 }) 37 Convey("one empty mapping should return inconsistencies", func() { 38 h2t := map[string]string{"h1": "t1", "h2": "t2", "h3": "t3"} 39 out := auditHostTaskMapping(h2t, nil) 40 So(len(out), ShouldEqual, 3) 41 Convey("with reasonable error language", func() { 42 So(out[0].Error(), ShouldContainSubstring, "does not exist") 43 So(out[1].Error(), ShouldContainSubstring, "does not exist") 44 So(out[2].Error(), ShouldContainSubstring, "does not exist") 45 }) 46 }) 47 Convey("two empty mappings should not return inconsistencies", func() { 48 out := auditHostTaskMapping(nil, nil) 49 So(len(out), ShouldEqual, 0) 50 }) 51 }) 52 53 Convey("With tasks and hosts stored in the db", t, func() { 54 testutil.HandleTestingErr(db.Clear(host.Collection), t, 55 "Error clearing '%v' collection", host.Collection) 56 testutil.HandleTestingErr(db.Clear(task.Collection), t, 57 "Error clearing '%v' collection", task.Collection) 58 Convey("no mappings should load with an empty db", func() { 59 h2t, t2h, err := loadHostTaskMapping() 60 So(err, ShouldBeNil) 61 So(len(h2t), ShouldEqual, 0) 62 So(len(t2h), ShouldEqual, 0) 63 }) 64 Convey("with 3 hosts, one with a running task", func() { 65 h1 := host.Host{Id: "h1", Status: evergreen.HostRunning, RunningTask: "t1"} 66 h2 := host.Host{Id: "h2", Status: evergreen.HostRunning} 67 h3 := host.Host{Id: "h3", Status: evergreen.HostRunning} 68 So(h1.Insert(), ShouldBeNil) 69 So(h2.Insert(), ShouldBeNil) 70 So(h3.Insert(), ShouldBeNil) 71 Convey("only mappings should return for the task-running host", func() { 72 h2t, t2h, err := loadHostTaskMapping() 73 So(err, ShouldBeNil) 74 So(len(h2t), ShouldEqual, 1) 75 So(h2t["h1"], ShouldEqual, "t1") 76 So(len(t2h), ShouldEqual, 0) 77 }) 78 }) 79 Convey("with 3 hosts and 3 tasks", func() { 80 h1 := host.Host{Id: "h1", Status: evergreen.HostRunning, RunningTask: "t1"} 81 h2 := host.Host{Id: "h2", Status: evergreen.HostRunning, RunningTask: "t2"} 82 h3 := host.Host{Id: "h3", Status: evergreen.HostRunning} 83 t1 := task.Task{Id: "t1", Status: evergreen.TaskStarted, HostId: "h1"} 84 t2 := task.Task{Id: "t2", Status: evergreen.TaskDispatched, HostId: "h2"} 85 t3 := task.Task{Id: "t3"} 86 So(h1.Insert(), ShouldBeNil) 87 So(h2.Insert(), ShouldBeNil) 88 So(h3.Insert(), ShouldBeNil) 89 So(t1.Insert(), ShouldBeNil) 90 So(t2.Insert(), ShouldBeNil) 91 So(t3.Insert(), ShouldBeNil) 92 Convey("mappings should return for the task-running hosts and running tasks", func() { 93 h2t, t2h, err := loadHostTaskMapping() 94 So(err, ShouldBeNil) 95 So(len(h2t), ShouldEqual, 2) 96 So(h2t["h1"], ShouldEqual, "t1") 97 So(h2t["h2"], ShouldEqual, "t2") 98 So(len(t2h), ShouldEqual, 2) 99 So(t2h["t1"], ShouldEqual, "h1") 100 So(t2h["t2"], ShouldEqual, "h2") 101 }) 102 }) 103 Convey("with a task that has a host but a host that does not have a task", func() { 104 testutil.HandleTestingErr(db.Clear(host.Collection), t, 105 "Error clearing '%v' collection", host.Collection) 106 testutil.HandleTestingErr(db.Clear(task.Collection), t, 107 "Error clearing '%v' collection", task.Collection) 108 h := host.Host{ 109 Id: "host1", 110 Status: evergreen.HostRunning, 111 } 112 So(h.Insert(), ShouldBeNil) 113 t := task.Task{ 114 Id: "task1", 115 HostId: "host1", 116 Status: evergreen.TaskStarted, 117 } 118 So(t.Insert(), ShouldBeNil) 119 h2t, t2h, err := loadHostTaskMapping() 120 So(err, ShouldBeNil) 121 So(len(h2t), ShouldEqual, 0) 122 So(len(t2h), ShouldEqual, 1) 123 So(t2h["task1"], ShouldEqual, "host1") 124 125 }) 126 Convey("with a host that has a task but a task that does not have a host", func() { 127 testutil.HandleTestingErr(db.Clear(host.Collection), t, 128 "Error clearing '%v' collection", host.Collection) 129 testutil.HandleTestingErr(db.Clear(task.Collection), t, 130 "Error clearing '%v' collection", task.Collection) 131 h := host.Host{ 132 Id: "host1", 133 Status: evergreen.HostRunning, 134 RunningTask: "task1", 135 } 136 So(h.Insert(), ShouldBeNil) 137 t := task.Task{ 138 Id: "task1", 139 Status: evergreen.TaskStarted, 140 } 141 So(t.Insert(), ShouldBeNil) 142 h2t, t2h, err := loadHostTaskMapping() 143 So(err, ShouldBeNil) 144 So(len(h2t), ShouldEqual, 1) 145 So(len(t2h), ShouldEqual, 1) 146 So(t2h["task1"], ShouldEqual, "") 147 So(h2t["host1"], ShouldEqual, "task1") 148 149 }) 150 }) 151 } 152 153 func TestStuckHostAuditing(t *testing.T) { 154 Convey("With tasks and hosts inserted into the db", t, func() { 155 testutil.HandleTestingErr(db.Clear(host.Collection), t, 156 "Error clearing '%v' collection", host.Collection) 157 testutil.HandleTestingErr(db.Clear(task.Collection), t, 158 "Error clearing '%v' collection", task.Collection) 159 h1 := host.Host{Id: "h1", Status: evergreen.HostRunning, RunningTask: "t1"} 160 h2 := host.Host{Id: "h2", Status: evergreen.HostRunning, RunningTask: "t2"} 161 h3 := host.Host{Id: "h3", Status: evergreen.HostRunning} 162 163 So(h1.Insert(), ShouldBeNil) 164 So(h2.Insert(), ShouldBeNil) 165 So(h3.Insert(), ShouldBeNil) 166 167 t1 := task.Task{Id: "t1", Status: evergreen.TaskDispatched, HostId: h1.Id} 168 t2 := task.Task{Id: "t2", Status: evergreen.TaskFailed, HostId: h2.Id} 169 So(t1.Insert(), ShouldBeNil) 170 So(t2.Insert(), ShouldBeNil) 171 172 Convey("hosts with running tasks that are completed should be returned", func() { 173 stuckHosts, err := CheckStuckHosts() 174 So(err, ShouldBeNil) 175 So(len(stuckHosts), ShouldEqual, 1) 176 So(stuckHosts[0].Host, ShouldEqual, h2.Id) 177 So(stuckHosts[0].RunningTask, ShouldEqual, t2.Id) 178 So(stuckHosts[0].TaskStatus, ShouldEqual, evergreen.TaskFailed) 179 So(stuckHosts[0].Error(), ShouldEqual, 180 fmt.Sprintf("host h2 has a running task t2 with complete status %s", evergreen.TaskFailed)) 181 }) 182 183 }) 184 }