func TestRetryLimit(t *testing.T) { is := is.New(t) err := try.Do(func(attempt int) (bool, error) { return true, errors.New("nope") }) is.OK(err) is.Equal(try.IsMaxRetries(err), true) }
func TestTryDoSuccessful(t *testing.T) { is := is.New(t) callCount := 0 err := try.Do(func(attempt int) (bool, error) { callCount++ return attempt < 5, nil }) is.NoErr(err) is.Equal(callCount, 1) }
func TestTryDoFailed(t *testing.T) { is := is.New(t) theErr := errors.New("something went wrong") callCount := 0 err := try.Do(func(attempt int) (bool, error) { callCount++ return attempt < 5, theErr }) is.Equal(err, theErr) is.Equal(callCount, 5) }
func TestTryExample(t *testing.T) { try.MaxRetries = 20 SomeFunction := func() (string, error) { return "", nil } var value string err := try.Do(func(attempt int) (bool, error) { var err error value, err = SomeFunction() return attempt < 5, err // try 5 times }) if err != nil { log.Fatalln("error:", err) } }
func openInputFile(input string) (*os.File, bool) { var r *os.File if input == "" { r = os.Stdin } else { err := try.Do(func(attempt int) (bool, error) { var err error r, err = os.Open(input) return attempt < 5, err }) if err != nil { Error.Println(err) return nil, false } } return r, true }
func TestTryExamplePanic(t *testing.T) { SomeFunction := func() (string, error) { panic("something went badly wrong") } var value string err := try.Do(func(attempt int) (retry bool, err error) { retry = attempt < 5 // try 5 times defer func() { if r := recover(); r != nil { err = errors.New(fmt.Sprintf("panic: %v", r)) } }() value, err = SomeFunction() return }) if err != nil { //log.Fatalln("error:", err) } }
func openOutputFile(output string) (*os.File, bool) { var w *os.File if output == "" { w = os.Stdout } else { if err := os.MkdirAll(path.Dir(output), 0777); err != nil { Error.Println(err) return nil, false } err := try.Do(func(attempt int) (bool, error) { var err error w, err = os.OpenFile(output, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) return attempt < 5, err }) if err != nil { Error.Println(err) return nil, false } } return w, true }
func TestTryPanics(t *testing.T) { is := is.New(t) theErr := errors.New("something went wrong") callCount := 0 err := try.Do(func(attempt int) (retry bool, err error) { retry = attempt < 5 defer func() { if r := recover(); r != nil { err = errors.New(fmt.Sprintf("panic: %v", r)) } }() callCount++ if attempt > 2 { panic("I don't like three") } err = theErr return }) is.Equal(err.Error(), "panic: I don't like three") is.Equal(callCount, 5) }
func main() { user, pass := getCredentials() cookieJar, _ := cookiejar.New(nil) client := &http.Client{Jar: cookieJar} log.Println("Grabbing XSRF Token") resp, err := client.Get("https://www.hipchat.com/sign_in") if err != nil { log.Fatal(err) } gq := mustParseResponse(resp) xsrf, exists := gq.Find("input[name=xsrf_token]").Attr("value") if !exists { log.Fatal("Can't find xsrf_token") } log.Println("Logging in") resp, err = client.PostForm("https://www.hipchat.com/sign_in", url.Values{ "xsrf_token": {xsrf}, "email": {user}, "password": {pass}, "stay_signed_in": {"1"}, "signin": {"log in"}, }) if err != nil { log.Fatal(err) } gq = mustParseResponse(resp) if gq.Find("div.aui-page-header-main h1").Size() != 1 { log.Fatal("Couldn't find welcome header") } uid, created, err := extractProfileMetadata(gq) if err != nil { log.Fatal(err) } log.Printf("Found user %s created %s", uid, created) domain := resp.Request.URL.Host log.Println("Listing people") // Get first page resp, err = client.Get("https://" + domain + "/people") if err != nil { log.Fatal(err) } gq = mustParseResponse(resp) people := make([]person, 0) // Figure out how many pages there are (the next/prev are links in aui-nav, but page 1 is not a link so just subtract one) pages := gq.Find("ol.aui-nav a").Size() - 1 longestName := 0 for page := 1; page <= pages; page++ { gq.Find("a.name").Each(func(i int, s *goquery.Selection) { attr, exists := s.Attr("href") name := strings.TrimSpace(s.Text()) signup := parseSignupDate(strings.TrimSpace(s.Parent().Parent().SiblingsFiltered("[headers=date-joined]").Text())) if !exists { log.Println("Can't find the href for this item") return } longestName = maxInt(longestName, len(name)) people = append(people, person{ Name: name, ID: strings.TrimPrefix(attr, "/people/show/"), Joined: signup, }) }) if page < pages { log.Printf("Getting people page %d", page+1) resp, err = client.Get("https://" + domain + "/people?p=" + strconv.Itoa(page+1)) if err != nil { log.Fatal(err) } gq = mustParseResponse(resp) } } // Doesn't seem to on windows width, _, _ := terminal.GetSize(0) peopleDigits := len(strconv.Itoa(len(people))) columns := width / (longestName + peopleDigits + 6) if columns < 1 { columns = 1 } peopleDigitsString := strconv.Itoa(peopleDigits) for i, person := range people { index := i + 1 // offset by 1 for input padding := strings.Repeat(".", longestName-len(person.Name)) fmt.Printf("%"+peopleDigitsString+"d:%s%s ", index, padding, person.Name) if index%columns == 0 { fmt.Println("") } } // extra newline for when the columns don't line up if len(people)%columns != 0 { fmt.Println("") } historiesToDelete := promptPeople(len(people)) for _, index := range historiesToDelete { var currentPerson person switch t := index.(type) { case int: currentPerson = people[t] case string: log.Printf("Resolving %s to a user", t) err = func() error { resp, err = client.Get("https://" + domain + "/people/show/" + t) if err != nil { return fmt.Errorf("Can't lookup %s: %s", t, err) } gq, err := goquery.NewDocumentFromResponse(resp) if err != nil { return fmt.Errorf("Can't parse %s: %s", t, err) } name := gq.Find("div.aui-item h2").Text() if name == "" { return fmt.Errorf("Can't find name for %s", t) } _, joined, err := extractProfileMetadata(gq) if err != nil { return err } currentPerson = person{ Name: name, Joined: joined, ID: t, } return nil }() if err != nil { log.Printf("ERR: %s", err) continue } } endDate := created.Add(-1 * 24 * time.Hour) if endDate.Before(currentPerson.Joined) { endDate = currentPerson.Joined } for working := time.Now(); working.After(endDate); working = working.Add(-1 * 24 * time.Hour) { log.Printf("Checking %s @ %s", currentPerson.Name, working.Format("2006-01-02")) err := try.Do(func(attempt int) (bool, error) { if attempt > 1 { time.Sleep(retryInterval * time.Duration(attempt-1) * time.Second) } resp, err = client.Get("https://" + domain + "/history/member/" + currentPerson.ID + working.Format("/2006/01/02")) if err != nil { return attempt < retryLimit, err } doc, err := goquery.NewDocumentFromResponse(resp) if err != nil { return attempt < retryLimit, err } forms := doc.Find("div.delete form") if forms.Size() > 0 { log.Printf("Found %d entries, deleting...", forms.Size()) } forms.Each(func(i int, form *goquery.Selection) { delurl, exists := form.Attr("action") if !exists { log.Fatal("Can't find action for the delete form") } values := url.Values{} form.Find("input").Each(func(i int, input *goquery.Selection) { name, nameExists := input.Attr("name") value, valueExists := input.Attr("value") if nameExists && valueExists { values.Set(name, value) } }) err := try.Do(func(attempt int) (bool, error) { if attempt > 1 { time.Sleep(retryInterval * time.Duration(attempt-1) * time.Second) } _, err := client.PostForm(delurl, values) return attempt < retryLimit, err }) if err != nil { log.Fatalln("Tried", retryLimit, "times to delete post:", err) } }) return attempt < retryLimit, err }) if err != nil { log.Fatalln("Tried", retryLimit, "times to pull day:", err) } } } }