1111import pytest
1212import requests
1313
14+ from jsonschema .exceptions import ValidationError
1415from airbyte_cdk .sources .declarative .checks .check_stream import CheckStream
1516from airbyte_cdk .sources .streams .http import HttpStream
1617from airbyte_cdk .sources .declarative .concurrent_declarative_source import (
@@ -343,52 +344,97 @@ def parse_response(self, response: requests.Response, **kwargs) -> Iterable[Mapp
343344 "name" : "static_stream" ,
344345 "primary_key" : "id" ,
345346 "schema_loader" : {
346- "type" : "InlineSchemaLoader" ,
347- "schema" : {
348- "$schema" : "http://json-schema.org/schema#" ,
349- "properties" : {
350- "id" : {"type" : "integer" },
351- "name" : {"type" : "string" },
352- },
353- "type" : "object" ,
347+ "type" : "InlineSchemaLoader" ,
348+ "schema" : {
349+ "$schema" : "http://json-schema.org/schema#" ,
350+ "properties" : {
351+ "id" : {"type" : "integer" },
352+ "name" : {"type" : "string" },
354353 },
355- }
354+ "type" : "object" ,
355+ },
356+ }
356357 }
357358 ]
358359}
359360
360361
361362@pytest .mark .parametrize (
362- "check_component" ,
363+ "check_component, expected_result, expectation, response_code, expected_messages " ,
363364 [
364- pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ]}},
365+ pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ]}}, True , False , 200 ,
366+ [{"id" : 1 , "name" : "static_1" }, {"id" : 2 , "name" : "static_2" }],
365367 id = "test_check_only_static_streams" ),
366368 pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ],
367369 "dynamic_streams_check_configs" : [
368370 {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "http_dynamic_stream" ,
369- "stream_count" : 1 }]}}, id = "test_check_static_streams_and_http_dynamic_stream" ),
371+ "stream_count" : 1 }]}}, True , False , 200 , [],
372+ id = "test_check_static_streams_and_http_dynamic_stream" ),
370373 pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ],
371374 "dynamic_streams_check_configs" : [
372375 {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "dynamic_stream_1" ,
373- "stream_count" : 1 }]}}, id = "test_check_static_streams_and_config_dynamic_stream" ),
374- pytest .param ({"check" : {"type" : "CheckStream" , "dynamic_streams_check_configs" : [{"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "dynamic_stream_1" ,
375- "stream_count" : 1 }, {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "http_dynamic_stream" }]}},
376+ "stream_count" : 1 }]}}, True , False , 200 , [],
377+ id = "test_check_static_streams_and_config_dynamic_stream" ),
378+ pytest .param ({"check" : {"type" : "CheckStream" , "dynamic_streams_check_configs" : [
379+ {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "dynamic_stream_1" ,
380+ "stream_count" : 1 }, {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "http_dynamic_stream" }]}},
381+ True , False , 200 , [],
376382 id = "test_check_http_dynamic_stream_and_config_dynamic_stream" ),
377383 pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ],
378384 "dynamic_streams_check_configs" : [
379385 {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "dynamic_stream_1" ,
380386 "stream_count" : 1 },
381- {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "http_dynamic_stream" }]}},
387+ {"type" : "DynamicStreamCheckConfig" ,
388+ "dynamic_stream_name" : "http_dynamic_stream" }]}}, True , False , 200 , [],
382389 id = "test_check_static_streams_and_http_dynamic_stream_and_config_dynamic_stream" ),
390+ pytest .param (
391+ {"check" : {"type" : "CheckStream" , "stream_names" : ["non_existent_stream" ]}},
392+ False ,
393+ True , 200 , [],
394+ id = "test_non_existent_static_stream"
395+ ),
396+ pytest .param (
397+ {"check" : {"type" : "CheckStream" , "dynamic_streams_check_configs" : [
398+ {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "unknown_dynamic_stream" ,
399+ "stream_count" : 1 }]}}
400+ ,
401+ False ,
402+ False , 200 , [],
403+ id = "test_non_existent_dynamic_stream"
404+ ),
405+ pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ]}}, False , False , 404 ,
406+ ["Not found. The requested resource was not found on the server." ],
407+ id = "test_stream_unavailable_unhandled_error" ),
408+ pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ]}}, False , False , 403 ,
409+ ["Forbidden. You don't have permission to access this resource." ],
410+ id = "test_stream_unavailable_handled_error" ),
411+ pytest .param ({"check" : {"type" : "CheckStream" , "stream_names" : ["static_stream" ]}}, False , False , 401 ,
412+ ["Unauthorized. Please ensure you are authenticated correctly." ],
413+ id = "test_stream_unauthorized_error" ),
414+ pytest .param ({"check" : {"type" : "CheckStream" , "dynamic_streams_check_configs" : [
415+ {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "dynamic_stream_1" ,
416+ "stream_count" : 1 }, {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "http_dynamic_stream" }]}},
417+ False , False , 404 , ["Not found. The requested resource was not found on the server." ],
418+ id = "test_dynamic_stream_unavailable_unhandled_error" ),
419+ pytest .param ({"check" : {"type" : "CheckStream" , "dynamic_streams_check_configs" : [
420+ {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "dynamic_stream_1" ,
421+ "stream_count" : 1 }, {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "http_dynamic_stream" }]}},
422+ False , False , 403 , ["Forbidden. You don't have permission to access this resource." ],
423+ id = "test_dynamic_stream_unavailable_handled_error" ),
424+ pytest .param ({"check" : {"type" : "CheckStream" , "dynamic_streams_check_configs" : [
425+ {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "dynamic_stream_1" ,
426+ "stream_count" : 1 }, {"type" : "DynamicStreamCheckConfig" , "dynamic_stream_name" : "http_dynamic_stream" }]}},
427+ False , False , 401 , ["Unauthorized. Please ensure you are authenticated correctly." ],
428+ id = "test_dynamic_stream_unauthorized_error" ),
383429 ],
384430)
385- def test_check_stream (check_component ):
431+ def test_check_stream1 (check_component , expected_result , expectation , response_code , expected_messages ):
386432 manifest = {** deepcopy (_MANIFEST_WITHOUT_CHECK_COMPONENT ), ** check_component }
387433
388434 with HttpMocker () as http_mocker :
389435 static_stream_request = HttpRequest (url = "https://api.test.com/static" )
390436 static_stream_response = HttpResponse (
391- body = json .dumps ([{ "id" : 1 , "name" : "static_1" }, { "id" : 2 , "name" : "static_2" }])
437+ body = json .dumps (expected_messages ), status_code = response_code
392438 )
393439 http_mocker .get (static_stream_request , static_stream_response )
394440
@@ -399,11 +445,11 @@ def test_check_stream(check_component):
399445 http_mocker .get (items_request , items_response )
400446
401447 item_request = HttpRequest (url = "https://api.test.com/items/1" )
402- item_response = HttpResponse (body = json .dumps ([] ), status_code = 200 )
448+ item_response = HttpResponse (body = json .dumps (expected_messages ), status_code = response_code )
403449 http_mocker .get (item_request , item_response )
404450
405451 item_request = HttpRequest (url = "https://api.test.com/items/3" )
406- item_response = HttpResponse (body = json .dumps ([] ), status_code = 200 )
452+ item_response = HttpResponse (body = json .dumps (expected_messages ), status_code = response_code )
407453 http_mocker .get (item_request , item_response )
408454
409455 source = ConcurrentDeclarativeSource (
@@ -412,14 +458,32 @@ def test_check_stream(check_component):
412458 catalog = None ,
413459 state = None ,
414460 )
461+ if expectation :
462+ with pytest .raises (ValueError ):
463+ source .check_connection (logger , _CONFIG )
464+ else :
465+ stream_is_available , reason = source .check_connection (logger , _CONFIG )
415466
416- stream_is_available , reason = source . check_connection ( logger , _CONFIG )
467+ assert stream_is_available == expected_result
417468
418- assert stream_is_available
469+
470+ def test_check_stream_missing_fields ():
471+ """Test if ValueError is raised when dynamic_streams_check_configs is missing required fields."""
472+ manifest = {** deepcopy (_MANIFEST_WITHOUT_CHECK_COMPONENT ),
473+ ** {"check" : {"type" : "CheckStream" ,
474+ "dynamic_streams_check_configs" : [{"type" : "DynamicStreamCheckConfig" }]}}}
475+ with pytest .raises (ValidationError ):
476+ source = ConcurrentDeclarativeSource (
477+ source_config = manifest ,
478+ config = _CONFIG ,
479+ catalog = None ,
480+ state = None ,
481+ )
419482
420483
421484def test_check_stream_only_type_provided ():
422- manifest = {** deepcopy (_MANIFEST_WITHOUT_CHECK_COMPONENT ), ** {"check" : {"type" : "CheckStream" }}}
485+ manifest = {** deepcopy (_MANIFEST_WITHOUT_CHECK_COMPONENT ),
486+ ** {"check" : {"type" : "CheckStream" }}}
423487 source = ConcurrentDeclarativeSource (
424488 source_config = manifest ,
425489 config = _CONFIG ,
0 commit comments