Skip to content
quarry Artifact [d3c2843cc7]
Login

Artifact [d3c2843cc7]

Artifact d3c2843cc750050956db6fef631fb1265b811127cfbb3992d9ee951b89ecc7b3:


package api

import (
	"context"
	"errors"
	"testing"

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

// A run and its log come back by id or short prefix: one try per step,
// a retried step's failing first try included, with tail keeping the
// last lines of each.
func TestARunAndItsLogComeBackByPrefix(t *testing.T) {
	runs := map[string]CIRun{
		"1b82c372a6e6aaaa": {RunID: "1b82c372a6e6aaaa", Checkin: "c1", Status: "failed"},
		"1b82c372ffff0000": {RunID: "1b82c372ffff0000", Checkin: "c2", Status: "completed"},
	}
	log := []ci.LogChunk{
		{Step: "test", Attempt: 1, Stream: "out", Data: "=== RUN TestA"},
		{Step: "test", Attempt: 1, Stream: "out", Data: "--- FAIL: TestA\nFAIL\n"},
		{Step: "test", Attempt: 1, Stream: "marker", Data: "failed"},
		{Step: "test", Attempt: 2, Stream: "out", Data: "ok\n"},
		{Step: "build", Attempt: 1, Stream: "out", Data: "built\n"},
	}
	d := Deps{Version: "v",
		Repos: NewRepos(map[string]*Repo{"test": {Zit: &zitcli.Client{}}}),
		CIRunByPrefix: func(repo, prefix string) (CIRun, bool, bool, error) {
			var found []CIRun
			for id, r := range runs {
				if len(prefix) <= len(id) && id[:len(prefix)] == prefix {
					found = append(found, r)
				}
			}
			if len(found) != 1 {
				return CIRun{}, false, len(found) > 1, nil
			}
			return found[0], true, false, nil
		},
		CILog: func(repo, runID string) ([]ci.LogChunk, bool, error) {
			if runID != "1b82c372a6e6aaaa" {
				return nil, false, nil
			}
			return log, true, nil
		},
	}
	r := ops.NewRegistry()
	if err := RegisterAll(r, d); err != nil {
		t.Fatal(err)
	}
	ctx := ops.WithUser(context.Background(), "alice")

	out, err := r.Invoke(ctx, "ci.run.get", ciRunIn{Repo: "test", RunID: "1B82C372A6E6"})
	if err != nil || out.(ciRunOut).Run.RunID != "1b82c372a6e6aaaa" {
		t.Errorf("FAIL: a run by a prefix read %+v, %v", out, err)
	}
	if _, err := r.Invoke(ctx, "ci.run.get", ciRunIn{Repo: "test", RunID: "1b82c372"}); !errors.Is(err, ops.ErrInvalid) {
		t.Errorf("FAIL: a prefix naming two runs answered %v", err)
	}
	if _, err := r.Invoke(ctx, "ci.run.get", ciRunIn{Repo: "test", RunID: "dead"}); !errors.Is(err, ops.ErrNotFound) {
		t.Errorf("FAIL: no such run answered %v", err)
	}

	out, err = r.Invoke(ctx, "ci.run.log", ciRunLogIn{Repo: "test", RunID: "1b82c372a6e6"})
	if err != nil {
		t.Fatal(err)
	}
	lo := out.(ciRunLogOut)
	if !lo.Held || len(lo.Steps) != 3 {
		t.Fatalf("FAIL: the log held %v with %d tries: %+v", lo.Held, len(lo.Steps), lo.Steps)
	}
	if s := lo.Steps[0]; s.Step != "test" || s.Attempt != 1 || !s.Failed || s.Lines != 3 {
		t.Errorf("FAIL: the failing first try reads %+v", s)
	}
	if s := lo.Steps[1]; s.Attempt != 2 || s.Failed {
		t.Errorf("FAIL: the passing retry reads %+v", s)
	}

	out, _ = r.Invoke(ctx, "ci.run.log", ciRunLogIn{Repo: "test", RunID: "1b82c372a6e6", Step: "test", Tail: 2})
	lo = out.(ciRunLogOut)
	if len(lo.Steps) != 2 || lo.Steps[0].Text != "--- FAIL: TestA\nFAIL\n" || lo.Steps[0].Lines != 3 {
		t.Errorf("FAIL: step and tail read %+v", lo.Steps)
	}

	out, _ = r.Invoke(ctx, "ci.run.log", ciRunLogIn{Repo: "test", RunID: "1b82c372ffff"})
	if lo := out.(ciRunLogOut); lo.Held || lo.Steps == nil || len(lo.Steps) != 0 {
		t.Errorf("FAIL: a run with no log read %+v", lo)
	}
}