github.com/orofarne/hammy@v0.0.0-20130409105742-374fadfd6ecb/src/hammy/spexecuter_test.go (about) 1 package hammy 2 3 import ( 4 "testing" 5 "os" 6 "os/exec" 7 "fmt" 8 "time" 9 ) 10 11 // Source code 12 var testWorker1 = ` 13 package main 14 15 import ( 16 "github.com/ugorji/go-msgpack" 17 "os" 18 "hammy" 19 "log" 20 "time" 21 "fmt" 22 ) 23 24 func main() { 25 dec := msgpack.NewDecoder(os.Stdin, nil) 26 enc := msgpack.NewEncoder(os.Stdout) 27 28 for i := 0; i < 5; i++ { 29 var input hammy.WorkerProcessInput 30 cmd1opt := make(map[string]interface{}) 31 cmd2opt := make(map[string]interface{}) 32 cmd3opt := make(map[string]interface{}) 33 cmd1opt["message"] = "Hello" 34 cmd2opt["message"] = "World" 35 cmd3opt["pid"] = fmt.Sprintf("%d", os.Getpid()) 36 cmdb := hammy.CmdBuffer{ 37 {Cmd: "cmd1", Options: cmd1opt,}, 38 {Cmd: "cmd2", Options: cmd2opt,}, 39 {Cmd: "cmd3", Options: cmd3opt,}, 40 } 41 42 if err := dec.Decode(&input); err != nil { 43 log.Fatalf("Decode error: %#v", err) 44 } 45 46 time.Sleep(100 * time.Millisecond) 47 48 output := hammy.WorkerProcessOutput{ 49 State: input.State, 50 CmdBuffer: &cmdb, 51 } 52 53 if err := enc.Encode(&output); err != nil { 54 log.Fatalf("Encode error: %#v", err) 55 } 56 } 57 } 58 ` 59 60 var testWorker2 = ` 61 package main 62 63 import ( 64 "github.com/ugorji/go-msgpack" 65 "os" 66 "hammy" 67 "log" 68 "time" 69 ) 70 71 func main() { 72 for { 73 var input hammy.WorkerProcessInput 74 cmdb := hammy.CmdBuffer{} 75 76 dec := msgpack.NewDecoder(os.Stdin, nil) 77 enc := msgpack.NewEncoder(os.Stdout) 78 79 if err := dec.Decode(&input); err != nil { 80 log.Fatalf("Decode error: %#v", err) 81 } 82 83 time.Sleep(10 * time.Second) 84 85 output := hammy.WorkerProcessOutput{ 86 State: input.State, 87 CmdBuffer: &cmdb, 88 } 89 90 if err := enc.Encode(&output); err != nil { 91 log.Fatalf("Encode error: %#v", err) 92 } 93 } 94 } 95 ` 96 97 func createTestProgramm(code string) (string, error) { 98 // Files 99 progSourceFile := os.TempDir() + "/hammy_spexecuter_test_subp.go" 100 progFile := os.TempDir() + "/hammy_spexecuter_test_subp" 101 102 // Cretate source file 103 f, err := os.Create(progSourceFile) 104 if err != nil { 105 return "", err 106 } 107 108 defer func() { 109 _ = os.Remove(progSourceFile) 110 }() 111 112 _, err = f.WriteString(code) 113 if err != nil { 114 return "", err 115 } 116 117 err = f.Close() 118 if err != nil { 119 return "", err 120 } 121 122 // Compile programm 123 err = os.Chdir(os.TempDir()) 124 if err != nil { 125 return "", err 126 } 127 128 cmd := exec.Command("go", "build", "-o", progFile, progSourceFile) 129 out, err := cmd.CombinedOutput() 130 if err != nil { 131 err = fmt.Errorf("Error (%v): %s", err, out) 132 return "", err 133 } 134 135 return progFile, nil 136 } 137 138 func TestSPExecuterSimple(t *testing.T) { 139 //t.Logf("GOPATH = %v", os.Getenv("GOPATH")) 140 141 prog, err := createTestProgramm(testWorker1) 142 if err != nil { 143 t.Fatalf("Error creating test programm: %#v", err) 144 } 145 defer func() { 146 os.Remove(prog) 147 }() 148 149 cfg := Config{} 150 cfg.Workers.PoolSize = 1 151 cfg.Workers.CmdLine = prog 152 cfg.Workers.MaxIter = 100 153 cfg.Workers.Timeout = 5 154 155 e := NewSPExecuter(cfg, "test_spexecutrer_instance_1") 156 157 key := "test1" 158 trigger := `sss@^&%GGGkll""''` 159 state := State{} 160 data := IncomingHostData{} 161 162 newState, cmdb, err := e.ProcessTrigger(key, trigger, &state, data) 163 if err != nil { 164 t.Fatalf("ProcessTrigger error: %#v", err) 165 } 166 _ = newState 167 168 if len(*cmdb) != 3 { 169 t.Fatalf("Invalid size of cmdb: %#v", cmdb) 170 } 171 172 if (*cmdb)[0].Cmd != "cmd1" || (*cmdb)[0].Options["message"] != "Hello" || 173 (*cmdb)[1].Cmd != "cmd2" || (*cmdb)[1].Options["message"] != "World" || 174 (*cmdb)[2].Cmd != "cmd3" || (*cmdb)[2].Options["pid"] == "" { 175 t.Errorf("Invalid cmdb: %#v", cmdb) 176 } 177 } 178 179 180 func TestSPExecuterKills(t *testing.T) { 181 //t.Logf("GOPATH = %v", os.Getenv("GOPATH")) 182 183 prog, err := createTestProgramm(testWorker1) 184 if err != nil { 185 t.Fatalf("Error creating test programm: %#v", err) 186 } 187 defer func() { 188 os.Remove(prog) 189 }() 190 191 cfg := Config{} 192 cfg.Workers.PoolSize = 1 193 cfg.Workers.CmdLine = prog 194 cfg.Workers.MaxIter = 3 195 cfg.Workers.Timeout = 5 196 197 e := NewSPExecuter(cfg, "test_spexecutrer_instance_2") 198 199 prevPid := "" 200 pidChanged := false 201 202 for i := 0; i < 5; i++ { 203 key := "test1" 204 trigger := `sss@^&%GGGkll""''` 205 state := State{} 206 data := IncomingHostData{} 207 208 newState, cmdb, err := e.ProcessTrigger(key, trigger, &state, data) 209 if err != nil { 210 t.Fatalf("ProcessTrigger error: %#v", err) 211 } 212 _ = newState 213 214 if len(*cmdb) != 3 { 215 t.Fatalf("Invalid size of cmdb: %#v", cmdb) 216 } 217 218 if (*cmdb)[0].Cmd != "cmd1" || (*cmdb)[0].Options["message"] != "Hello" || 219 (*cmdb)[1].Cmd != "cmd2" || (*cmdb)[1].Options["message"] != "World" || 220 (*cmdb)[2].Cmd != "cmd3" || (*cmdb)[2].Options["pid"] == "" { 221 t.Errorf("Invalid cmdb: %#v", cmdb) 222 } 223 224 newPid := (*cmdb)[2].Options["pid"] 225 if prevPid == "" { 226 prevPid = newPid.(string) 227 } else { 228 if newPid != prevPid { 229 pidChanged = true 230 break 231 } 232 } 233 } 234 235 if !pidChanged { 236 t.Errorf("Pid not changed") 237 } 238 } 239 240 func TestSPExecuterDeads(t *testing.T) { 241 //t.Logf("GOPATH = %v", os.Getenv("GOPATH")) 242 243 prog, err := createTestProgramm(testWorker1) 244 if err != nil { 245 t.Fatalf("Error creating test programm: %#v", err) 246 } 247 defer func() { 248 os.Remove(prog) 249 }() 250 251 cfg := Config{} 252 cfg.Workers.PoolSize = 1 253 cfg.Workers.CmdLine = prog 254 cfg.Workers.MaxIter = 100 255 cfg.Workers.Timeout = 100 256 257 e := NewSPExecuter(cfg, "test_spexecutrer_instance_3") 258 259 prevPid := "" 260 pidChanged := false 261 262 for i := 0; i < 7; i++ { 263 key := "test1" 264 trigger := `sss@^&%GGGkll""''` 265 state := State{} 266 data := IncomingHostData{} 267 268 newState, cmdb, err := e.ProcessTrigger(key, trigger, &state, data) 269 if err != nil { 270 t.Fatalf("ProcessTrigger error: %#v", err) 271 } 272 _ = newState 273 274 if len(*cmdb) != 3 { 275 t.Fatalf("Invalid size of cmdb: %#v", cmdb) 276 } 277 278 if (*cmdb)[0].Cmd != "cmd1" || (*cmdb)[0].Options["message"] != "Hello" || 279 (*cmdb)[1].Cmd != "cmd2" || (*cmdb)[1].Options["message"] != "World" || 280 (*cmdb)[2].Cmd != "cmd3" || (*cmdb)[2].Options["pid"] == "" { 281 t.Errorf("Invalid cmdb: %#v", cmdb) 282 } 283 284 newPid := (*cmdb)[2].Options["pid"] 285 if prevPid == "" { 286 prevPid = newPid.(string) 287 } else { 288 if newPid != prevPid { 289 pidChanged = true 290 } 291 } 292 293 time.Sleep(3 * time.Millisecond) // Without in worker got new task _before_ it's dead... 294 } 295 296 if !pidChanged { 297 t.Errorf("Pid not changed") 298 } 299 } 300 301 func TestSPExecuterTimeout(t *testing.T) { 302 //t.Logf("GOPATH = %v", os.Getenv("GOPATH")) 303 304 prog, err := createTestProgramm(testWorker2) 305 if err != nil { 306 t.Fatalf("Error creating test programm: %#v", err) 307 } 308 defer func() { 309 os.Remove(prog) 310 }() 311 312 cfg := Config{} 313 cfg.Workers.PoolSize = 1 314 cfg.Workers.CmdLine = prog 315 cfg.Workers.MaxIter = 100 316 cfg.Workers.Timeout = 1 317 318 e := NewSPExecuter(cfg, "test_spexecutrer_instance_4") 319 320 key := "test1" 321 trigger := `sss@^&%GGGkll""''` 322 state := State{} 323 data := IncomingHostData{} 324 325 t1 := time.Now() 326 327 _, _, err = e.ProcessTrigger(key, trigger, &state, data) 328 if err == nil { 329 t.Fatalf("ProcessTrigger should fail") 330 } 331 332 if time.Since(t1) > 2*time.Second { 333 t.Fatalf("Too long...") 334 } 335 }