summaryrefslogtreecommitdiff
path: root/internal/task/currentattempt_test.go
blob: 76661d80fb9ae3fc7afcb8e4dc2793f7b8af03c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package task

import (
	"errors"
	"testing"
)

type fakeLookup struct {
	tasks map[string]*Task
}

func newFakeLookup() *fakeLookup {
	return &fakeLookup{tasks: make(map[string]*Task)}
}

func (f *fakeLookup) GetTask(id string) (*Task, error) {
	t, ok := f.tasks[id]
	if !ok {
		return nil, errors.New("not found")
	}
	return t, nil
}

func (f *fakeLookup) ListDependents(taskID string) ([]*Task, error) {
	var out []*Task
	for _, t := range f.tasks {
		for _, d := range t.DependsOn {
			if d == taskID {
				out = append(out, t)
				break
			}
		}
	}
	return out, nil
}

func TestCurrentAttempt_NoFixAttempt_ReturnsAnchorItself(t *testing.T) {
	lookup := newFakeLookup()
	lookup.tasks["a"] = &Task{ID: "a"}

	got, err := CurrentAttempt(lookup, "a")
	if err != nil {
		t.Fatalf("CurrentAttempt: %v", err)
	}
	if got.ID != "a" {
		t.Errorf("got %q, want a", got.ID)
	}
}

func TestCurrentAttempt_OneFixAttempt_ResolvesToIt(t *testing.T) {
	lookup := newFakeLookup()
	lookup.tasks["a"] = &Task{ID: "a", ParentTaskID: "parent-1"}
	lookup.tasks["a-fix1"] = &Task{ID: "a-fix1", ParentTaskID: "parent-1", DependsOn: []string{"a"}}

	got, err := CurrentAttempt(lookup, "a")
	if err != nil {
		t.Fatalf("CurrentAttempt: %v", err)
	}
	if got.ID != "a-fix1" {
		t.Errorf("got %q, want a-fix1", got.ID)
	}
}

func TestCurrentAttempt_ChainOfFixAttempts_ResolvesToTip(t *testing.T) {
	lookup := newFakeLookup()
	lookup.tasks["a"] = &Task{ID: "a", ParentTaskID: "parent-1"}
	lookup.tasks["a-fix1"] = &Task{ID: "a-fix1", ParentTaskID: "parent-1", DependsOn: []string{"a"}}
	lookup.tasks["a-fix2"] = &Task{ID: "a-fix2", ParentTaskID: "parent-1", DependsOn: []string{"a-fix1"}}

	got, err := CurrentAttempt(lookup, "a")
	if err != nil {
		t.Fatalf("CurrentAttempt: %v", err)
	}
	if got.ID != "a-fix2" {
		t.Errorf("got %q, want a-fix2 (tip of the chain)", got.ID)
	}

	// Resolving from an intermediate link in the chain also lands on the tip.
	got, err = CurrentAttempt(lookup, "a-fix1")
	if err != nil {
		t.Fatalf("CurrentAttempt: %v", err)
	}
	if got.ID != "a-fix2" {
		t.Errorf("resolving from a-fix1: got %q, want a-fix2", got.ID)
	}
}

// TestCurrentAttempt_DependentWithDifferentParent_NotTreatedAsFixAttempt
// proves a task that depends on "a" but has a DIFFERENT ParentTaskID (e.g.
// an unrelated Evaluator task depending on a Builder for scheduling reasons)
// must not be mistaken for a's fix attempt.
func TestCurrentAttempt_DependentWithDifferentParent_NotTreatedAsFixAttempt(t *testing.T) {
	lookup := newFakeLookup()
	lookup.tasks["a"] = &Task{ID: "a", ParentTaskID: "parent-1"}
	lookup.tasks["unrelated"] = &Task{ID: "unrelated", ParentTaskID: "", DependsOn: []string{"a"}}

	got, err := CurrentAttempt(lookup, "a")
	if err != nil {
		t.Fatalf("CurrentAttempt: %v", err)
	}
	if got.ID != "a" {
		t.Errorf("got %q, want a (unrelated dependent must not be treated as a fix attempt)", got.ID)
	}
}

// TestCurrentAttempt_DependentWithMultipleDependsOn_NotTreatedAsFixAttempt
// proves a fix attempt has exactly one DependsOn entry (the task it
// supersedes); a task depending on "a" among several dependencies (e.g. an
// Arbitration task depending on all 4 Evaluators) must not be mistaken for
// a's fix attempt.
func TestCurrentAttempt_DependentWithMultipleDependsOn_NotTreatedAsFixAttempt(t *testing.T) {
	lookup := newFakeLookup()
	lookup.tasks["a"] = &Task{ID: "a", ParentTaskID: "parent-1"}
	lookup.tasks["multi-dep"] = &Task{ID: "multi-dep", ParentTaskID: "parent-1", DependsOn: []string{"a", "b"}}

	got, err := CurrentAttempt(lookup, "a")
	if err != nil {
		t.Fatalf("CurrentAttempt: %v", err)
	}
	if got.ID != "a" {
		t.Errorf("got %q, want a", got.ID)
	}
}

func TestCurrentAttempt_UnknownAnchor_ReturnsError(t *testing.T) {
	lookup := newFakeLookup()
	if _, err := CurrentAttempt(lookup, "does-not-exist"); err == nil {
		t.Error("expected an error for an unknown anchor ID")
	}
}