diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go index a445a3a..2eb58ba 100644 --- a/test/e2e/main_test.go +++ b/test/e2e/main_test.go @@ -166,7 +166,7 @@ func TestE2E(t *testing.T) { } if err := waitFor("send-log row to reach status=sent", 30*time.Second, 500*time.Millisecond, func() (bool, error) { - rows, err := sc.panel.sendLogRows(senderDomain) + rows, err := sc.panel.sendLogRows(senderDomain, "") if err != nil { return false, err } diff --git a/test/e2e/negative_test.go b/test/e2e/negative_test.go index e44a283..f8e09b9 100644 --- a/test/e2e/negative_test.go +++ b/test/e2e/negative_test.go @@ -2,7 +2,6 @@ package e2e import ( "fmt" - "strings" "testing" "time" ) @@ -54,11 +53,11 @@ func testLevel2RateLimit(t *testing.T, sc *scenario) { } if err := waitFor("a rejected row for l2app in the send log", 15*time.Second, 500*time.Millisecond, func() (bool, error) { - rows, err := sc.panel.sendLogRows(senderDomain) + rows, err := sc.panel.sendLogRows(senderDomain, login) if err != nil { return false, err } - if strings.Contains(rows, "l2app") && containsCell(rows, "rejected") { + if containsCell(rows, "rejected") { return true, nil } return false, fmt.Errorf("no rejected row for l2app yet") diff --git a/test/e2e/panel_client.go b/test/e2e/panel_client.go index 066a46f..edf6efd 100644 --- a/test/e2e/panel_client.go +++ b/test/e2e/panel_client.go @@ -189,9 +189,17 @@ func (c *panelClient) setRateLimit(path, allowedIP string, maxMessages, windowSe } // sendLogRows returns the raw /deliveries/rows HTML fragment, filtered to one -// domain, for polling a row's status without parsing full HTML into structs. -func (c *panelClient) sendLogRows(domain string) (string, error) { - _, body, err := c.get("/deliveries/rows?domain=" + url.QueryEscape(domain)) +// domain and optionally to one application login, for polling a row's status +// without parsing full HTML into structs. The application is a filter rather +// than something to search the returned rows for: the log's columns identify a +// message (time, from, to, subject, status) and the sending application is only +// named on a row's own /deliveries/{id} page. +func (c *panelClient) sendLogRows(domain, app string) (string, error) { + q := url.Values{"domain": {domain}} + if app != "" { + q.Set("app", app) + } + _, body, err := c.get("/deliveries/rows?" + q.Encode()) return body, err } @@ -202,15 +210,18 @@ func (c *panelClient) status() (*http.Response, error) { return resp, err } -// applicationID scrapes an application's numeric id off its domain page row, -// keyed by login — needed to build /applications/{id}/ratelimit, which the -// add-application response (just the login/password) does not carry. +// applicationID scrapes an application's numeric id off its block on the domain +// page, keyed by login — needed to build /applications/{id}/ratelimit, which the +// add-application response (just the login/password) does not carry. The id is +// taken from the first action posted under that login, whichever it is, so +// reordering the block's controls does not break the scrape; only the login +// heading itself is anchored on. func (c *panelClient) applicationID(domainID, login string) (string, error) { _, body, err := c.get("/domains/" + domainID) if err != nil { return "", err } - pattern := `(?s)
` + regexp.QuoteMeta(login) + `
.*?/applications/(\d+)/` m := regexp.MustCompile(pattern).FindStringSubmatch(body) if m == nil { return "", fmt.Errorf("could not find application id for login %q", login)