@@ -24,6 +24,22 @@ def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
2424 })
2525"""
2626
27+ composition_script_with_exception = """
28+ from crossplane.function.proto.v1 import run_function_pb2 as fnv1
29+
30+ def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
31+ rsp.desired.resources["bucket"].resource.update({
32+ "apiVersion": "s3.aws.upbound.io/v1beta2",
33+ "kind": "Bucket",
34+ "spec": {
35+ "forProvider": {
36+ "region": "us-east-1"
37+ }
38+ },
39+ })
40+ raise AttributeError
41+ """
42+
2743async_composition_script = """
2844from crossplane.function.proto.v1 import run_function_pb2 as fnv1
2945
@@ -39,6 +55,22 @@ async def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
3955 })
4056"""
4157
58+ async_composition_script_with_exception = """
59+ from crossplane.function.proto.v1 import run_function_pb2 as fnv1
60+
61+ async def compose(req: fnv1.RunFunctionRequest, rsp: fnv1.RunFunctionResponse):
62+ rsp.desired.resources["bucket"].resource.update({
63+ "apiVersion": "s3.aws.upbound.io/v1beta2",
64+ "kind": "Bucket",
65+ "spec": {
66+ "forProvider": {
67+ "region": "us-east-1"
68+ }
69+ },
70+ })
71+ raise AttributeError
72+ """
73+
4274operation_script = """
4375from crossplane.function.proto.v1 import run_function_pb2 as fnv1
4476
@@ -140,6 +172,112 @@ class TestCase:
140172 context = structpb .Struct (),
141173 ),
142174 ),
175+ TestCase (
176+ reason = "Function should fail gracefully when script is missing." ,
177+ req = fnv1 .RunFunctionRequest (
178+ input = resource .dict_to_struct ({}),
179+ ),
180+ want = fnv1 .RunFunctionResponse (
181+ meta = fnv1 .ResponseMeta (ttl = durationpb .Duration (seconds = 60 )),
182+ results = [
183+ {
184+ "message" : "missing script in function input" ,
185+ "severity" : "SEVERITY_FATAL" ,
186+ }
187+ ],
188+ desired = fnv1 .State (),
189+ context = structpb .Struct (),
190+ ),
191+ ),
192+ TestCase (
193+ reason = "Function should fail gracefully when script is empty." ,
194+ req = fnv1 .RunFunctionRequest (
195+ input = resource .dict_to_struct ({"script" : "" }),
196+ ),
197+ want = fnv1 .RunFunctionResponse (
198+ meta = fnv1 .ResponseMeta (ttl = durationpb .Duration (seconds = 60 )),
199+ results = [
200+ {
201+ "message" : "missing script in function input" ,
202+ "severity" : "SEVERITY_FATAL" ,
203+ }
204+ ],
205+ desired = fnv1 .State (),
206+ context = structpb .Struct (),
207+ ),
208+ ),
209+ TestCase (
210+ reason = "Function should fail gracefully when compose script raises"
211+ " an exception." ,
212+ req = fnv1 .RunFunctionRequest (
213+ input = resource .dict_to_struct (
214+ {"script" : composition_script_with_exception }
215+ ),
216+ ),
217+ want = fnv1 .RunFunctionResponse (
218+ meta = fnv1 .ResponseMeta (ttl = durationpb .Duration (seconds = 60 )),
219+ results = [
220+ {
221+ "message" : "Exception: <class 'AttributeError'>, traceback:"
222+ " [' File \" <string>\" , line 14, in compose\\ n'"
223+ "]" ,
224+ "severity" : "SEVERITY_FATAL" ,
225+ }
226+ ],
227+ desired = fnv1 .State (
228+ resources = {
229+ "bucket" : fnv1 .Resource (
230+ resource = resource .dict_to_struct (
231+ {
232+ "apiVersion" : "s3.aws.upbound.io/v1beta2" ,
233+ "kind" : "Bucket" ,
234+ "spec" : {
235+ "forProvider" : {"region" : "us-east-1" }
236+ },
237+ }
238+ )
239+ )
240+ }
241+ ),
242+ context = structpb .Struct (),
243+ ),
244+ ),
245+ TestCase (
246+ reason = "Function should fail gracefully when async compose script"
247+ " raises an exception." ,
248+ req = fnv1 .RunFunctionRequest (
249+ input = resource .dict_to_struct (
250+ {"script" : async_composition_script_with_exception }
251+ ),
252+ ),
253+ want = fnv1 .RunFunctionResponse (
254+ meta = fnv1 .ResponseMeta (ttl = durationpb .Duration (seconds = 60 )),
255+ results = [
256+ {
257+ "message" : "Exception: <class 'AttributeError'>, traceback:"
258+ " [' File \" <string>\" , line 14, in compose\\ n'"
259+ "]" ,
260+ "severity" : "SEVERITY_FATAL" ,
261+ }
262+ ],
263+ desired = fnv1 .State (
264+ resources = {
265+ "bucket" : fnv1 .Resource (
266+ resource = resource .dict_to_struct (
267+ {
268+ "apiVersion" : "s3.aws.upbound.io/v1beta2" ,
269+ "kind" : "Bucket" ,
270+ "spec" : {
271+ "forProvider" : {"region" : "us-east-1" }
272+ },
273+ }
274+ )
275+ )
276+ }
277+ ),
278+ context = structpb .Struct (),
279+ ),
280+ ),
143281 ]
144282
145283 runner = fn .FunctionRunner ()
0 commit comments