Skip to content

Commit e7cc0d9

Browse files
committed
POC conformance test suite
1 parent 933f2a0 commit e7cc0d9

File tree

1 file changed

+224
-0
lines changed

1 file changed

+224
-0
lines changed

test/poc_conformance_test.go

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
//go:build conformance
2+
// +build conformance
3+
4+
/*
5+
This serves as a POC for conformance test suite design including functionality,
6+
behavioural and fields population.
7+
It mocks the "black-box" execution of TaskRuns and PipelineRuns utilizing the
8+
Tekton clients to mock the controller of a conformant vendor service.
9+
10+
Please use the following for triggering the test:
11+
go test -v -tags=conformance -count=1 ./test -run ^TestConformance
12+
13+
The next step will be to integrate this test as POC with v2 API.
14+
*/
15+
16+
package test
17+
18+
import (
19+
"context"
20+
"fmt"
21+
"testing"
22+
23+
v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
24+
"github.com/tektoncd/pipeline/test/parse"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/client-go/kubernetes/scheme"
27+
knativetest "knative.dev/pkg/test"
28+
"knative.dev/pkg/test/helpers"
29+
"sigs.k8s.io/yaml"
30+
)
31+
32+
const (
33+
TaskRunInputType = "TaskRun"
34+
PipelineRunInputType = "PipelineRun"
35+
)
36+
37+
func TestConformanceShouldProvideTaskResult(t *testing.T) {
38+
inputYAML := fmt.Sprintf(`
39+
apiVersion: tekton.dev/v1
40+
kind: TaskRun
41+
metadata:
42+
name: %s
43+
spec:
44+
taskSpec:
45+
params:
46+
- name: multiplicand
47+
description: the first operand
48+
default: %s
49+
- name: multipliper
50+
description: the second operand
51+
default: %s
52+
results:
53+
- name: product
54+
description: the product of the first and second operand
55+
steps:
56+
- name: add
57+
image: alpine
58+
env:
59+
- name: OP1
60+
value: $(params.multiplicand)
61+
- name: OP2
62+
value: $(params.multipliper)
63+
command: ["/bin/sh", "-c"]
64+
args:
65+
- echo -n $((${OP1}*${OP2})) | tee $(results.product.path);
66+
`, helpers.ObjectNameForTest(t), "3", "5")
67+
68+
// Black box execution of Pipeline CRDs that should be implemented by Vendor service
69+
outputYAML, err := ProcessAndSendToTekton(inputYAML, TaskRunInputType, t)
70+
if err != nil {
71+
t.Fatalf("Vendor service failed processing inputYAML: %s", err)
72+
}
73+
74+
// Parse and validate output YAML
75+
resolvedTR := parse.MustParseV1TaskRun(t, outputYAML)
76+
if len(resolvedTR.Status.Results) != 1 {
77+
t.Errorf("Expect vendor service to provide 1 result but not")
78+
}
79+
80+
if resolvedTR.Status.Results[0].Value.StringVal != "15" {
81+
t.Errorf("Not producing correct result :%s", resolvedTR.Status.Results[0].Value.StringVal)
82+
}
83+
}
84+
85+
func TestConformanceShouldHonorTaskRunTimeout(t *testing.T) {
86+
expectedFailedStatus := true
87+
inputYAML := fmt.Sprintf(`
88+
apiVersion: tekton.dev/v1
89+
kind: TaskRun
90+
metadata:
91+
name: %s
92+
spec:
93+
timeout: 15s
94+
taskSpec:
95+
steps:
96+
- image: busybox
97+
command: ['/bin/sh']
98+
args: ['-c', 'sleep 15001']
99+
`, helpers.ObjectNameForTest(t))
100+
101+
// Black box execution of Pipeline CRDs that should be implemented by Vendor service
102+
outputYAML, err := ProcessAndSendToTekton(inputYAML, TaskRunInputType, t, expectedFailedStatus)
103+
if err != nil {
104+
t.Fatalf("Vendor service failed processing inputYAML: %s", err)
105+
}
106+
107+
// Parse and validate output YAML
108+
resolvedTR := parse.MustParseV1TaskRun(t, outputYAML)
109+
if len(resolvedTR.Status.Conditions) != 1 {
110+
t.Errorf("Expect vendor service to populate 1 Condition but no")
111+
}
112+
113+
if resolvedTR.Status.Conditions[0].Type != "Succeeded" {
114+
t.Errorf("Expect vendor service to populate Condition `Succeeded` but got: %s", resolvedTR.Status.Conditions[0].Type)
115+
}
116+
117+
if resolvedTR.Status.Conditions[0].Status != "False" {
118+
t.Errorf("Expect vendor service to populate Condition `False` but got: %s", resolvedTR.Status.Conditions[0].Status)
119+
}
120+
121+
if resolvedTR.Status.Conditions[0].Reason != "TaskRunTimeout" {
122+
t.Errorf("Expect vendor service to populate Condition Reason `TaskRunTimeout` but got: %s", resolvedTR.Status.Conditions[0].Reason)
123+
}
124+
}
125+
126+
func TestConformanceShouldPopulateConditions(t *testing.T) {
127+
inputYAML := fmt.Sprintf(`
128+
apiVersion: tekton.dev/v1
129+
kind: TaskRun
130+
metadata:
131+
name: %s
132+
spec:
133+
taskSpec:
134+
steps:
135+
- name: add
136+
image: ubuntu
137+
script:
138+
echo Hello world!
139+
`, helpers.ObjectNameForTest(t))
140+
141+
// Black box execution of Pipeline CRDs that should be implemented by Vendor service
142+
outputYAML, err := ProcessAndSendToTekton(inputYAML, TaskRunInputType, t)
143+
if err != nil {
144+
t.Fatalf("Vendor service failed processing inputYAML: %s", err)
145+
}
146+
147+
// Parse and validate output YAML
148+
resolvedTR := parse.MustParseV1TaskRun(t, outputYAML)
149+
if len(resolvedTR.Status.Conditions) != 1 {
150+
t.Errorf("Expect vendor service to populate 1 Condition but no")
151+
}
152+
153+
if resolvedTR.Status.Conditions[0].Type != "Succeeded" {
154+
t.Errorf("Expect vendor service to populate Condition `Succeeded` but got: %s", resolvedTR.Status.Conditions[0].Type)
155+
}
156+
157+
if resolvedTR.Status.Conditions[0].Status != "True" {
158+
t.Errorf("Expect vendor service to populate Condition `True` but got: %s", resolvedTR.Status.Conditions[0].Status)
159+
}
160+
}
161+
162+
// ProcessAndSendToTekton takes in vanilla Tekton PipelineRun and TaskRun, waits for the object to succeed and outputs the final PipelineRun and TaskRun with status.
163+
// The parameters are inputYAML and its Primitive type {PipelineRun, TaskRun}
164+
// And the return values will be the output YAML string and errors.
165+
func ProcessAndSendToTekton(inputYAML, primitiveType string, customInputs ...interface{}) (string, error) {
166+
// Handle customInputs
167+
var t *testing.T
168+
var expectRunToFail bool
169+
for _, customInput := range customInputs {
170+
if ci, ok := customInput.(*testing.T); ok {
171+
t = ci
172+
}
173+
if ci, ok := customInput.(bool); ok {
174+
expectRunToFail = ci
175+
}
176+
}
177+
178+
return mockTektonPipelineController(t, inputYAML, primitiveType, expectRunToFail)
179+
}
180+
181+
// mockTektonPipelineController fakes the behaviour of a vendor service by utilizing the Tekton test infrastructure.
182+
// For the POC, it uses the Tetkon clients to Create, Wait for and Get the expected TaskRun.
183+
func mockTektonPipelineController(t *testing.T, inputYAML, primitiveType string, expectRunToFail bool) (string, error) {
184+
ctx := context.Background()
185+
ctx, cancel := context.WithCancel(ctx)
186+
defer cancel()
187+
c, namespace := setup(ctx, t)
188+
189+
knativetest.CleanupOnInterrupt(func() { tearDown(ctx, t, c, namespace) }, t.Logf)
190+
defer tearDown(ctx, t, c, namespace)
191+
192+
// Parse inputYAML, parse.MustParseTaskRun
193+
var tr v1.TaskRun
194+
if _, _, err := scheme.Codecs.UniversalDeserializer().Decode([]byte(inputYAML), nil, &tr); err != nil {
195+
return "", fmt.Errorf("must parse YAML (%s): %v", inputYAML, err)
196+
}
197+
198+
// Create TaskRun via TaskRunClient
199+
trResolved, err := c.V1TaskRunClient.Create(ctx, &tr, metav1.CreateOptions{})
200+
if err != nil {
201+
return "", fmt.Errorf("Failed to create TaskRun `%v`: %w", trResolved, err)
202+
}
203+
204+
var caf ConditionAccessorFn
205+
caf = Succeed(trResolved.Name)
206+
if expectRunToFail {
207+
caf = Failed(trResolved.Name)
208+
}
209+
if err := WaitForTaskRunState(ctx, c, trResolved.Name, caf, "WaitTaskRunDone", v1Version); err != nil {
210+
return "", fmt.Errorf("Error waiting for TaskRun to finish: %s", err)
211+
}
212+
213+
// Retrieve the TaskRun via TaskRunClient
214+
trGot, err := c.V1TaskRunClient.Get(ctx, trResolved.Name, metav1.GetOptions{})
215+
if err != nil {
216+
return "", fmt.Errorf("Failed to get TaskRun `%s`: %s", trGot.Name, err)
217+
}
218+
219+
outputYAML, err := yaml.Marshal(trGot)
220+
if err != nil {
221+
return "", err
222+
}
223+
return string(outputYAML[:]), nil
224+
}

0 commit comments

Comments
 (0)