Skip to content
quarry Artifact [555a276a33]
Login

Artifact [555a276a33]

Artifact 555a276a33f83ec976b7a6ba65f571f03122da8bc45d02e1393b18562a9b4847:


package web

import (
	"net/url"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/ci"
)

func chunk(n int, data string) ci.LogChunk {
	return ci.LogChunk{Seq: n, Stream: "out", Data: data}
}

// Filtering a log has one job, and a collapsed step hiding the only
// match is that job failing. So a filter opens what it kept and closes
// what it emptied, regardless of how the step ended.
func TestFilterOpensTheStepsThatStillHaveLines(t *testing.T) {
	v := &ciRunView{Steps: []ciStepView{
		{ID: "test", State: "pass", Chunks: []ci.LogChunk{
			chunk(1, "ok  internal/web  11.8s"), chunk(2, "PASS")}},
		{ID: "build", State: "pass", Chunks: []ci.LogChunk{chunk(3, "go build ./...")}},
	}}
	v.applyLogView("BUILD", false) // case-insensitive: readers do not shout

	if v.Total != 3 {
		t.Errorf("Total = %d, want every line counted before filtering", v.Total)
	}
	if v.Matched != 1 {
		t.Errorf("Matched = %d, want 1", v.Matched)
	}
	if v.Steps[0].Open || len(v.Steps[0].Chunks) != 0 {
		t.Error("a step the filter emptied is still open")
	}
	if !v.Steps[1].Open {
		t.Error("the step holding the only match is collapsed — the filter hid what it found")
	}
	if !v.Filtering() {
		t.Error("Filtering() is false while a filter is set")
	}
}

// Expand-all opens everything, including the steps a filter emptied —
// it is the reader saying "show me the shape of the whole run".
func TestExpandAllOpensEveryStep(t *testing.T) {
	v := &ciRunView{Steps: []ciStepView{{ID: "a"}, {ID: "b"}}}
	v.applyLogView("", true)
	for _, st := range v.Steps {
		if !st.Open {
			t.Errorf("step %s stayed closed under open=all", st.ID)
		}
	}
}

// The stream has to push the view the reader is actually looking at.
// Without the query the first push replaced a filtered log with the
// whole thing, which reads as the filter spontaneously clearing.
func TestStreamKeepsTheReadersFilter(t *testing.T) {
	q := url.Values{"q": {"go test"}, "open": {"all"}}
	got := logViewQuery(q)
	if !strings.Contains(got, "q=go+test") || !strings.Contains(got, "open=all") {
		t.Errorf("logViewQuery(%v) = %q, which drops the reader's view", q, got)
	}
	// Round-trips: what the stream is handed parses back to the same view.
	parsed, err := url.ParseQuery(strings.TrimPrefix(got, "?"))
	if err != nil {
		t.Fatal(err)
	}
	if f, open := logViewOf(parsed); f != "go test" || !open {
		t.Errorf("round trip lost the view: %q %v", f, open)
	}
	// An unfiltered page adds nothing, so the common URL stays clean.
	if logViewQuery(url.Values{}) != "" {
		t.Error("an unfiltered view still decorates the stream URL")
	}
}