1212import requests
1313
1414from datacustomcode .deploy import (
15+ DataObject ,
16+ DataObjectField ,
1517 DloPermission ,
1618 DmoPermission ,
1719 Permissions ,
@@ -985,6 +987,37 @@ def test_get_config_empty_permission_raises(self, mock_file):
985987 with pytest .raises (ValueError ):
986988 get_config ("/test/dir" )
987989
990+ @patch (
991+ "builtins.open" ,
992+ new_callable = mock_open ,
993+ read_data = (
994+ '{"sdkVersion": "0.1.14", "entryPoint": "entrypoint.py", '
995+ '"dataspace": "default", '
996+ '"permissions": {"read": {"dmo": ["ssot__Account__dlm"]}, '
997+ '"write": {"dmo": ["Account_DMO_Test__dlm"]}}, '
998+ '"dataObjects": [{'
999+ '"name": "Account_DMO_Test__dlm", '
1000+ '"label": "Account DMO Test", '
1001+ '"type": "dataModelObject", '
1002+ '"category": "profile", '
1003+ '"fields": [{"name": "Id__c", "label": "Account Id", '
1004+ '"dataType": "text", "isPrimaryKey": true, '
1005+ '"keyQualifierFieldName": "KQ_Id1__c"}]'
1006+ "}]}"
1007+ ),
1008+ )
1009+ def test_get_config_dmo_with_data_objects (self , mock_file ):
1010+ """config.json parses the optional dataObjects schema for DMO writes."""
1011+ result = get_config ("/test/dir" )
1012+ assert isinstance (result , DataTransformConfig )
1013+ assert result .dataObjects is not None
1014+ assert len (result .dataObjects ) == 1
1015+ obj = result .dataObjects [0 ]
1016+ assert obj .name == "Account_DMO_Test__dlm"
1017+ assert obj .category == "profile"
1018+ assert obj .fields [0 ].dataType == "text"
1019+ assert obj .fields [0 ].keyQualifierFieldName == "KQ_Id1__c"
1020+
9881021
9891022class TestCreateDataTransform :
9901023 @patch ("datacustomcode.deploy.get_config" )
@@ -1059,6 +1092,23 @@ def test_create_data_transform_dmo(self, mock_make_api_call, mock_get_config):
10591092 read = DmoPermission (dmo = ["input_dmo__dlm" ]),
10601093 write = DmoPermission (dmo = ["output_dmo__dlm" ]),
10611094 ),
1095+ dataObjects = [
1096+ DataObject (
1097+ name = "output_dmo__dlm" ,
1098+ label = "Output DMO" ,
1099+ type = "dataModelObject" ,
1100+ category = "profile" ,
1101+ fields = [
1102+ DataObjectField (
1103+ name = "Id__c" ,
1104+ label = "Id" ,
1105+ dataType = "text" ,
1106+ isPrimaryKey = True ,
1107+ keyQualifierFieldName = "KQ_Id1__c" ,
1108+ )
1109+ ],
1110+ )
1111+ ],
10621112 )
10631113 mock_make_api_call .return_value = {"id" : "transform_id" }
10641114
@@ -1104,6 +1154,23 @@ def test_create_data_transform_multiple_dmos(
11041154 read = DmoPermission (dmo = ["in1__dlm" , "in2__dlm" ]),
11051155 write = DmoPermission (dmo = ["out__dlm" ]),
11061156 ),
1157+ dataObjects = [
1158+ DataObject (
1159+ name = "out__dlm" ,
1160+ label = "Out" ,
1161+ type = "dataModelObject" ,
1162+ category = "profile" ,
1163+ fields = [
1164+ DataObjectField (
1165+ name = "Id__c" ,
1166+ label = "Id" ,
1167+ dataType = "text" ,
1168+ isPrimaryKey = True ,
1169+ keyQualifierFieldName = "KQ_Id1__c" ,
1170+ )
1171+ ],
1172+ )
1173+ ],
11071174 )
11081175 mock_make_api_call .return_value = {"id" : "transform_id" }
11091176
@@ -1125,6 +1192,167 @@ def test_create_data_transform_multiple_dmos(
11251192 }
11261193 }
11271194
1195+ @patch ("datacustomcode.deploy.get_config" )
1196+ @patch ("datacustomcode.deploy._make_api_call" )
1197+ def test_create_data_transform_dmo_emits_output_data_objects (
1198+ self , mock_make_api_call , mock_get_config
1199+ ):
1200+ """DMO transforms include outputDataObjects with transformed field names."""
1201+ access_token = AccessTokenResponse (
1202+ access_token = "test_token" , instance_url = "https://instance.example.com"
1203+ )
1204+ metadata = CodeExtensionMetadata (
1205+ name = "test_package" ,
1206+ version = "1.0.0" ,
1207+ description = "DMO with schema" ,
1208+ computeType = "CPU_M" ,
1209+ codeType = "script" ,
1210+ )
1211+
1212+ data_transform_config = DataTransformConfig (
1213+ sdkVersion = "0.1.14" ,
1214+ entryPoint = "entrypoint.py" ,
1215+ dataspace = "default" ,
1216+ permissions = Permissions (
1217+ read = DmoPermission (dmo = ["ssot__Account__dlm" ]),
1218+ write = DmoPermission (dmo = ["Account_DMO_Test__dlm" ]),
1219+ ),
1220+ dataObjects = [
1221+ DataObject (
1222+ name = "Account_DMO_Test__dlm" ,
1223+ label = "Account DMO Test" ,
1224+ type = "dataModelObject" ,
1225+ category = "profile" ,
1226+ fields = [
1227+ DataObjectField (
1228+ name = "Id__c" ,
1229+ label = "Account Id" ,
1230+ dataType = "text" ,
1231+ isPrimaryKey = True ,
1232+ keyQualifierFieldName = "KQ_Id1__c" ,
1233+ ),
1234+ DataObjectField (
1235+ name = "KQ_Id1__c" ,
1236+ label = "Key Qualifier Account Id" ,
1237+ dataType = "text" ,
1238+ isPrimaryKey = False ,
1239+ keyQualifierFieldName = None ,
1240+ ),
1241+ DataObjectField (
1242+ name = "Description__c" ,
1243+ label = "Account Description" ,
1244+ dataType = "text" ,
1245+ isPrimaryKey = False ,
1246+ keyQualifierFieldName = None ,
1247+ ),
1248+ ],
1249+ )
1250+ ],
1251+ )
1252+ mock_make_api_call .return_value = {"id" : "transform_id" }
1253+
1254+ create_data_transform (
1255+ "/test/dir" , access_token , metadata , data_transform_config
1256+ )
1257+
1258+ request_body = mock_make_api_call .call_args [1 ]["json" ]
1259+ assert request_body ["definition" ]["outputDataObjects" ] == [
1260+ {
1261+ "category" : "profile" ,
1262+ "fields" : [
1263+ {
1264+ "isPrimaryKey" : True ,
1265+ "keyQualifierField" : "KQ_Id1__c" ,
1266+ "label" : "Account Id" ,
1267+ "name" : "Id__c" ,
1268+ "type" : "text" ,
1269+ },
1270+ {
1271+ "isPrimaryKey" : False ,
1272+ "label" : "Key Qualifier Account Id" ,
1273+ "name" : "KQ_Id1__c" ,
1274+ "type" : "text" ,
1275+ },
1276+ {
1277+ "isPrimaryKey" : False ,
1278+ "label" : "Account Description" ,
1279+ "name" : "Description__c" ,
1280+ "type" : "text" ,
1281+ },
1282+ ],
1283+ "label" : "Account DMO Test" ,
1284+ "name" : "Account_DMO_Test__dlm" ,
1285+ "type" : "dataModelObject" ,
1286+ }
1287+ ]
1288+
1289+ @patch ("datacustomcode.deploy.get_config" )
1290+ @patch ("datacustomcode.deploy._make_api_call" )
1291+ def test_create_data_transform_dlo_omits_output_data_objects (
1292+ self , mock_make_api_call , mock_get_config
1293+ ):
1294+ """DLO transforms must not include outputDataObjects in the payload."""
1295+ access_token = AccessTokenResponse (
1296+ access_token = "test_token" , instance_url = "https://instance.example.com"
1297+ )
1298+ metadata = CodeExtensionMetadata (
1299+ name = "dlo_job" ,
1300+ version = "1.0.0" ,
1301+ description = "DLO job" ,
1302+ computeType = "CPU_M" ,
1303+ codeType = "script" ,
1304+ )
1305+
1306+ data_transform_config = DataTransformConfig (
1307+ sdkVersion = "1.0.0" ,
1308+ entryPoint = "entrypoint.py" ,
1309+ dataspace = "test_dataspace" ,
1310+ permissions = Permissions (
1311+ read = DloPermission (dlo = ["input_dlo" ]),
1312+ write = DloPermission (dlo = ["output_dlo" ]),
1313+ ),
1314+ )
1315+ mock_make_api_call .return_value = {"id" : "transform_id" }
1316+
1317+ create_data_transform (
1318+ "/test/dir" , access_token , metadata , data_transform_config
1319+ )
1320+
1321+ request_body = mock_make_api_call .call_args [1 ]["json" ]
1322+ assert "outputDataObjects" not in request_body ["definition" ]
1323+
1324+ @patch ("datacustomcode.deploy.get_config" )
1325+ @patch ("datacustomcode.deploy._make_api_call" )
1326+ def test_create_data_transform_dmo_missing_data_objects_raises (
1327+ self , mock_make_api_call , mock_get_config
1328+ ):
1329+ """DMO transforms without dataObjects raise a clear error."""
1330+ access_token = AccessTokenResponse (
1331+ access_token = "test_token" , instance_url = "https://instance.example.com"
1332+ )
1333+ metadata = CodeExtensionMetadata (
1334+ name = "dmo_no_schema" ,
1335+ version = "1.0.0" ,
1336+ description = "DMO no schema" ,
1337+ computeType = "CPU_M" ,
1338+ codeType = "script" ,
1339+ )
1340+
1341+ data_transform_config = DataTransformConfig (
1342+ sdkVersion = "1.0.0" ,
1343+ entryPoint = "entrypoint.py" ,
1344+ dataspace = "test_dataspace" ,
1345+ permissions = Permissions (
1346+ read = DmoPermission (dmo = ["input_dmo__dlm" ]),
1347+ write = DmoPermission (dmo = ["output_dmo__dlm" ]),
1348+ ),
1349+ )
1350+
1351+ with pytest .raises (ValueError , match = "dataObjects" ):
1352+ create_data_transform (
1353+ "/test/dir" , access_token , metadata , data_transform_config
1354+ )
1355+
11281356
11291357class TestDeployFull :
11301358 @patch ("datacustomcode.deploy.get_config" )
0 commit comments