Files
kportal/internal/ui/httplog_state_test.go
T
lukaszraczylo 96ae1d45e0 style: Extract UI constants and refactor main view rendering (#30)
- [x] Add golangci-lint configuration with gocritic ifElseChain disabled
- [x] Rename error variables to avoid shadowing (createErr, watcherErr, watchErr, etc.)
- [x] Replace `interface{}` with `any` type alias throughout codebase
- [x] Add package-level documentation comments to all internal packages
- [x] Reorder struct fields alphabetically for consistency
- [x] Extract UI constants (terminal dimensions, column widths, colors) to constants.go
- [x] Refactor BubbleTeaUI main view rendering into smaller helper functions
- [x] Simplify nested conditionals and improve code clarity
- [x] Add `isForwardDisabled()` helper method to BubbleTeaUI
- [x] Update file permissions from 0644 to 0600 in config tests
- [x] Add `#nosec` comments and error suppression where appropriate
- [x] Improve test table struct field ordering for readability
- [x] Fix resource parsing in AddForward using strings.SplitN
- [x] Add comprehensive tests for new UI helper functions and constants
2026-01-13 09:37:45 +00:00

230 lines
7.6 KiB
Go

package ui
import (
"testing"
"github.com/stretchr/testify/assert"
)
// TestNewHTTPLogState tests the constructor
func TestNewHTTPLogState(t *testing.T) {
state := newHTTPLogState("forward-123", "my-service")
assert.Equal(t, "forward-123", state.forwardID)
assert.Equal(t, "my-service", state.forwardAlias)
assert.NotNil(t, state.entries)
assert.Empty(t, state.entries)
assert.True(t, state.autoScroll)
assert.Equal(t, HTTPLogFilterNone, state.filterMode)
assert.Empty(t, state.filterText)
assert.False(t, state.filterActive)
}
// TestHTTPLogState_GetFilteredEntries_NoFilter tests filtering with no filter
func TestHTTPLogState_GetFilteredEntries_NoFilter(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "POST", Path: "/api/orders", StatusCode: 201},
{Method: "GET", Path: "/health", StatusCode: 200},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 3)
}
// TestHTTPLogState_GetFilteredEntries_FiltersZeroStatusCode tests that entries without status codes are filtered
func TestHTTPLogState_GetFilteredEntries_FiltersZeroStatusCode(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "GET", Path: "/streaming", StatusCode: 0}, // No status (in-progress or error)
{Method: "POST", Path: "/api/orders", StatusCode: 201},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 2)
assert.Equal(t, "/api/users", filtered[0].Path)
assert.Equal(t, "/api/orders", filtered[1].Path)
}
// TestHTTPLogState_GetFilteredEntries_Non200Filter tests non-2xx filter
func TestHTTPLogState_GetFilteredEntries_Non200Filter(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.filterMode = HTTPLogFilterNon200
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "GET", Path: "/api/error", StatusCode: 500},
{Method: "POST", Path: "/api/orders", StatusCode: 201},
{Method: "GET", Path: "/api/notfound", StatusCode: 404},
{Method: "PUT", Path: "/api/redirect", StatusCode: 301},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 3)
assert.Equal(t, 500, filtered[0].StatusCode)
assert.Equal(t, 404, filtered[1].StatusCode)
assert.Equal(t, 301, filtered[2].StatusCode)
}
// TestHTTPLogState_GetFilteredEntries_ErrorsFilter tests 4xx/5xx filter
func TestHTTPLogState_GetFilteredEntries_ErrorsFilter(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.filterMode = HTTPLogFilterErrors
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "GET", Path: "/api/error", StatusCode: 500},
{Method: "POST", Path: "/api/orders", StatusCode: 201},
{Method: "GET", Path: "/api/notfound", StatusCode: 404},
{Method: "PUT", Path: "/api/redirect", StatusCode: 301},
{Method: "GET", Path: "/api/bad", StatusCode: 400},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 3)
assert.Equal(t, 500, filtered[0].StatusCode)
assert.Equal(t, 404, filtered[1].StatusCode)
assert.Equal(t, 400, filtered[2].StatusCode)
}
// TestHTTPLogState_GetFilteredEntries_TextFilter tests text filtering
func TestHTTPLogState_GetFilteredEntries_TextFilter(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.filterText = "users"
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "GET", Path: "/api/users/123", StatusCode: 200},
{Method: "POST", Path: "/api/orders", StatusCode: 201},
{Method: "GET", Path: "/health", StatusCode: 200},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 2)
assert.Equal(t, "/api/users", filtered[0].Path)
assert.Equal(t, "/api/users/123", filtered[1].Path)
}
// TestHTTPLogState_GetFilteredEntries_TextFilterCaseInsensitive tests case-insensitive text filtering
func TestHTTPLogState_GetFilteredEntries_TextFilterCaseInsensitive(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.filterText = "API"
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "GET", Path: "/Api/Orders", StatusCode: 200},
{Method: "GET", Path: "/health", StatusCode: 200},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 2)
}
// TestHTTPLogState_GetFilteredEntries_TextFilterByMethod tests filtering by HTTP method
func TestHTTPLogState_GetFilteredEntries_TextFilterByMethod(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.filterText = "POST"
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "POST", Path: "/api/orders", StatusCode: 201},
{Method: "POST", Path: "/api/items", StatusCode: 201},
{Method: "PUT", Path: "/api/update", StatusCode: 200},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 2)
assert.Equal(t, "POST", filtered[0].Method)
assert.Equal(t, "POST", filtered[1].Method)
}
// TestHTTPLogState_GetFilteredEntries_CombinedFilters tests combining mode and text filters
func TestHTTPLogState_GetFilteredEntries_CombinedFilters(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.filterMode = HTTPLogFilterErrors
state.filterText = "api"
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "GET", Path: "/api/error", StatusCode: 500},
{Method: "GET", Path: "/health", StatusCode: 500}, // Error but doesn't match text
{Method: "GET", Path: "/api/notfound", StatusCode: 404},
}
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 2)
assert.Equal(t, "/api/error", filtered[0].Path)
assert.Equal(t, "/api/notfound", filtered[1].Path)
}
// TestHTTPLogState_GetFilteredEntries_EmptyResult tests when no entries match
func TestHTTPLogState_GetFilteredEntries_EmptyResult(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
state.filterText = "nonexistent"
state.entries = []HTTPLogEntry{
{Method: "GET", Path: "/api/users", StatusCode: 200},
{Method: "POST", Path: "/api/orders", StatusCode: 201},
}
filtered := state.getFilteredEntries()
assert.Empty(t, filtered)
}
// TestHTTPLogState_GetFilterModeLabel tests filter mode labels
func TestHTTPLogState_GetFilterModeLabel(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
tests := []struct {
expected string
mode HTTPLogFilterMode
}{
{mode: HTTPLogFilterNone, expected: "All"},
{mode: HTTPLogFilterText, expected: "Text"},
{mode: HTTPLogFilterNon200, expected: "Non-2xx"},
{mode: HTTPLogFilterErrors, expected: "Errors (4xx/5xx)"},
}
for _, tt := range tests {
state.filterMode = tt.mode
assert.Equal(t, tt.expected, state.getFilterModeLabel())
}
}
// TestHTTPLogState_FilterModeValues tests filter mode constants are correct
func TestHTTPLogState_FilterModeValues(t *testing.T) {
// Ensure the modes are sequential for cycling to work correctly
assert.Equal(t, HTTPLogFilterMode(0), HTTPLogFilterNone)
assert.Equal(t, HTTPLogFilterMode(1), HTTPLogFilterText)
assert.Equal(t, HTTPLogFilterMode(2), HTTPLogFilterNon200)
assert.Equal(t, HTTPLogFilterMode(3), HTTPLogFilterErrors)
}
// TestHTTPLogState_LargeEntrySet tests filtering performance with many entries
func TestHTTPLogState_LargeEntrySet(t *testing.T) {
state := newHTTPLogState("fwd", "alias")
// Add 1000 entries
for i := 0; i < 1000; i++ {
code := 200
if i%10 == 0 {
code = 500
}
state.entries = append(state.entries, HTTPLogEntry{
Method: "GET",
Path: "/api/test",
StatusCode: code,
})
}
// Filter should work correctly
state.filterMode = HTTPLogFilterErrors
filtered := state.getFilteredEntries()
assert.Len(t, filtered, 100) // 10% are errors
}