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  }