package server import ( "fmt" "net/http/httptest" "strings" "testing" "time" ) func testClients() ([]*Client, map[int64]int64) { now := time.Now().Unix() var cs []*Client sizes := map[int64]int64{} for i := 1; i <= 30; i++ { c := &Client{ID: int64(i), Domain: fmt.Sprintf("srv%02d.example.com", i), Name: fmt.Sprintf("srv%02d", i), StaleHours: 26, LastBackupAt: now - int64(i)*60, CreatedAt: now} sizes[c.ID] = int64(i) * 1000 cs = append(cs, c) } cs[0].Name = "Нидерланды" // srv01 cs[1].LastBackupAt = 0 // srv02 — never cs[2].LastErrorAt = now // srv03 — fail cs[3].Disabled = true // srv04 — off cs[4].LastBackupAt = now - 100*3600 // srv05 — stale return cs, sizes } func view(t *testing.T, rawQuery string) *clientsView { t.Helper() cs, sizes := testClients() r := httptest.NewRequest("GET", "/?"+rawQuery, nil) return buildClientsView(parseClientsQuery(r), cs, sizes) } func TestClientsSearchFilter(t *testing.T) { v := view(t, "q=нидер") if v.Found != 1 || v.Rows[0].Domain != "srv01.example.com" { t.Fatalf("поиск по названию: %d", v.Found) } if v := view(t, "q=SRV1"); v.Found != 10 { // srv10..srv19 t.Fatalf("поиск без учёта регистра: %d", v.Found) } v = view(t, "status=fail") if v.Found != 1 || v.Rows[0].Domain != "srv03.example.com" { t.Fatalf("фильтр fail: %+v", v.Found) } chips := map[string]int{} for _, c := range v.Chips { chips[c.Key] = c.Count } if chips[""] != 30 || chips["never"] != 1 || chips["off"] != 1 || chips["stale"] != 1 || chips["ok"] != 26 { t.Fatalf("счётчики: %v", chips) } } func TestClientsSortAndPaging(t *testing.T) { v := view(t, "") if v.Found != 30 || len(v.Rows) != 25 || v.Rows[0].Domain != "srv01.example.com" || v.Next == "" { t.Fatalf("первая страница: found=%d rows=%d", v.Found, len(v.Rows)) } v = view(t, "page=2") if len(v.Rows) != 5 || v.From != 26 || v.To != 30 || v.Prev == "" || v.Next != "" { t.Fatalf("вторая страница: %+v", v) } if v := view(t, "page=99"); v.Query.Page != 2 { t.Fatalf("страница за пределами: %d", v.Query.Page) } v = view(t, "sort=size&per=10") if v.Rows[0].Domain != "srv30.example.com" || len(v.Rows) != 10 { t.Fatalf("размер по убыванию по умолчанию: %s", v.Rows[0].Domain) } if v := view(t, "sort=size&dir=asc"); v.Rows[0].Domain != "srv01.example.com" { t.Fatalf("размер по возрастанию: %s", v.Rows[0].Domain) } if v := view(t, "sort=status"); v.Rows[0].StatusClass != "fail" { t.Fatalf("сортировка по статусу: %s", v.Rows[0].StatusClass) } // повторный клик по текущей колонке меняет направление if u := view(t, "sort=size").Query.SortURL("size"); !strings.Contains(u, "dir=asc") { t.Fatalf("SortURL: %s", u) } // фильтр сохраняется в ссылках пагинации if u := view(t, "q=srv&status=ok").Query.PageURL(2); !strings.Contains(u, "q=srv") || !strings.Contains(u, "status=ok") { t.Fatalf("PageURL: %s", u) } }