/* Sets up the global variables needed by the whole package. This should be invoked by the main tegu function (main/tegu.go). CAUTION: this is not implemented as an init() function as we must pass information from the main to here. */ func Initialise(cfg_fname *string, ver *string, nwch chan *ipc.Chmsg, rmch chan *ipc.Chmsg, rmluch chan *ipc.Chmsg, osifch chan *ipc.Chmsg, fqch chan *ipc.Chmsg, amch chan *ipc.Chmsg) (err error) { err = nil def_log_dir := "." log_dir := &empty_str nw_ch = nwch rmgr_ch = rmch rmgrlu_ch = rmluch osif_ch = osifch fq_ch = fqch am_ch = amch if ver != nil { version = *ver } tegu_sheep = bleater.Mk_bleater(1, os.Stderr) // the main (parent) bleater used by libraries and as master 'volume' control tegu_sheep.Set_prefix("tegu") pid = os.Getpid() // used to keep reservation names unique across invocations tklr = ipc.Mk_tickler(30) // shouldn't need more than 30 different tickle spots tklr.Add_spot(2, rmgr_ch, REQ_NOOP, nil, 1) // a quick burst tickle to prevent a long block if the first goroutine to schedule a tickle schedules a long wait if cfg_fname != nil { cfg_data, err = config.Parse2strs(nil, *cfg_fname) // capture config data as strings -- referenced as cfg_data["sect"]["key"] if err != nil { err = fmt.Errorf("unable to parse config file %s: %s", *cfg_fname, err) return } if p := cfg_data["default"]["shell"]; p != nil { shell_cmd = *p } if p := cfg_data["default"]["verbose"]; p != nil { tegu_sheep.Set_level(uint(clike.Atoi(*p))) } if log_dir = cfg_data["default"]["log_dir"]; log_dir == nil { log_dir = &def_log_dir } } else { cfg_data = nil } tegu_sheep.Add_child(gizmos.Get_sheep()) // since we don't directly initialise the gizmo environment we ask for its sheep if *log_dir != "stderr" { // if overriden in config lfn := tegu_sheep.Mk_logfile_nm(log_dir, 86400) tegu_sheep.Baa(1, "switching to log file: %s", *lfn) tegu_sheep.Append_target(*lfn, false) // switch bleaters to the log file rather than stderr go tegu_sheep.Sheep_herder(log_dir, 86400) // start the function that will roll the log now and again } return }
func TestIpc(t *testing.T) { req := ipc.Mk_chmsg() if req == nil { fmt.Fprintf(os.Stderr, "unable to create a request\n") t.Fail() return } start_ts := time.Now().Unix() fmt.Fprintf(os.Stderr, "this test runs for 60 seconds and will generate updates periodically....\n") req.Response_ch = nil // use it to keep compiler happy data := "data for tickled bit" ch := make(chan *ipc.Chmsg, 10) // allow 10 messages to queue on the channel // to test non-blocking aspect, set to 1 test should run longer than 60 seconds tklr := ipc.Mk_tickler(6) // allow max of 6 ticklers; we test 'full' error at end tklr.Add_spot(35, ch, 30, &data, 0) // will automatically start the tickler tklr.Add_spot(20, ch, 20, &data, 0) tklr.Add_spot(15, ch, 15, &data, 0) id, err := tklr.Add_spot(10, ch, 10, &data, 0) // nick the id so we can drop it later _, err = tklr.Add_spot(10, ch, 1, &data, 2) // should drive type 1 only twice; 10s apart if err != nil { fmt.Fprintf(os.Stderr, "unable to add tickle spot: %s\n", err) t.Fail() return } fmt.Fprintf(os.Stderr, "type 10 and type 1 written every 10 seconds; type 1 only written twice\n") fmt.Fprintf(os.Stderr, "type 10 will be dropped after 35 seconds\n") fmt.Fprintf(os.Stderr, "type 15 will appear every 15 seconds\n") fmt.Fprintf(os.Stderr, "type 20 will appear every 20 seconds\n") fmt.Fprintf(os.Stderr, "type 30 will appear every 35 seconds\n") limited_count := 0 for count := 0; count < 2; { req = <-ch // wait for tickle fmt.Fprintf(os.Stderr, "got a tickle: @%ds type=%d count=%d\n", time.Now().Unix()-start_ts, req.Msg_type, count) if req.Msg_type == 30 { if count == 0 { fmt.Fprintf(os.Stderr, "dropping type 10 from list; no more type 10 should appear\n") tklr.Drop_spot(id) // drop the 10s tickler after first 30 second one pops } count++ // count updated only at 30s point } if req.Msg_type == 1 { if limited_count > 1 { fmt.Fprintf(os.Stderr, "limited count tickle was driven more than twice [FAIL]\n") t.Fail() } limited_count++ } if req.Msg_type == 10 && count > 0 { fmt.Fprintf(os.Stderr, "req 10 driven after it was dropped [FAIL]\n") t.Fail() } } tklr.Stop() // when we get here there should only be three active ticklers in the list, so we should be // able to add 3 before we get a full error. // add more spots until we max out to test the error logic in tickle err = nil for i := 0; i < 3 && err == nil; i++ { _, err = tklr.Add_spot(20, ch, 20, &data, 0) if err != nil { fmt.Fprintf(os.Stderr, "early failure when adding more: i=%d %s\n", i, err) t.Fail() return } } // the table should be full (6 active ticklers now) and this should return an error _, err = tklr.Add_spot(10, ch, 10, &data, 0) if err != nil { fmt.Fprintf(os.Stderr, "test to over fill the table resulted in the expected error: %s [OK]\n", err) } else { fmt.Fprintf(os.Stderr, "adding a 7th tickle spot didn't cause an error and should have [FAIL]\n") t.Fail() } }