|
30 | 30 | from dapr.conf import settings |
31 | 31 | from dapr.clients.grpc._helpers import to_bytes |
32 | 32 | from dapr.clients.grpc._request import TransactionalStateOperation, ConversationInput |
| 33 | +from dapr.clients.grpc._jobs import Job |
33 | 34 | from dapr.clients.grpc._state import StateOptions, Consistency, Concurrency, StateItem |
34 | 35 | from dapr.clients.grpc._crypto import EncryptOptions, DecryptOptions |
35 | 36 | from dapr.clients.grpc._response import ( |
36 | 37 | ConfigurationItem, |
37 | 38 | ConfigurationWatcher, |
38 | 39 | ConfigurationResponse, |
| 40 | + DaprResponse, |
39 | 41 | UnlockResponseStatus, |
40 | 42 | ) |
41 | 43 |
|
@@ -1164,6 +1166,218 @@ async def test_converse_alpha1_error_handling(self): |
1164 | 1166 | self.assertTrue('Invalid argument' in str(context.exception)) |
1165 | 1167 | await dapr.close() |
1166 | 1168 |
|
| 1169 | + # |
| 1170 | + # Tests for Jobs API (Alpha) - Async |
| 1171 | + # |
| 1172 | + |
| 1173 | + async def test_schedule_job_alpha1_success(self): |
| 1174 | + """Test successful async job scheduling.""" |
| 1175 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1176 | + job = Job(name='async-test-job', schedule='@every 1m') |
| 1177 | + |
| 1178 | + # Schedule the job |
| 1179 | + response = await dapr.schedule_job_alpha1(job) |
| 1180 | + |
| 1181 | + # Verify response type |
| 1182 | + self.assertIsInstance(response, DaprResponse) |
| 1183 | + |
| 1184 | + # Verify job was stored in fake server |
| 1185 | + self.assertIn('async-test-job', self._fake_dapr_server.jobs) |
| 1186 | + stored_job = self._fake_dapr_server.jobs['async-test-job'] |
| 1187 | + self.assertEqual(stored_job.name, 'async-test-job') |
| 1188 | + self.assertEqual(stored_job.schedule, '@every 1m') |
| 1189 | + self.assertEqual(stored_job.overwrite, False) |
| 1190 | + # Verify data field is always set (even if empty) |
| 1191 | + self.assertTrue(stored_job.HasField('data')) |
| 1192 | + |
| 1193 | + await dapr.close() |
| 1194 | + |
| 1195 | + async def test_schedule_job_alpha1_success_with_data(self): |
| 1196 | + """Test successful async job scheduling with data payload.""" |
| 1197 | + from google.protobuf.any_pb2 import Any as GrpcAny |
| 1198 | + |
| 1199 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1200 | + |
| 1201 | + # Create job data |
| 1202 | + data = GrpcAny() |
| 1203 | + data.value = b'{"message": "Hello from async job!", "priority": "high"}' |
| 1204 | + |
| 1205 | + job = Job( |
| 1206 | + name='async-test-job-with-data', schedule='@every 2m', data=data, repeats=3, ttl='10m' |
| 1207 | + ) |
| 1208 | + |
| 1209 | + # Schedule the job |
| 1210 | + response = await dapr.schedule_job_alpha1(job) |
| 1211 | + |
| 1212 | + # Verify response type |
| 1213 | + self.assertIsInstance(response, DaprResponse) |
| 1214 | + |
| 1215 | + # Verify job was stored in fake server with all data |
| 1216 | + self.assertIn('async-test-job-with-data', self._fake_dapr_server.jobs) |
| 1217 | + stored_job = self._fake_dapr_server.jobs['async-test-job-with-data'] |
| 1218 | + self.assertEqual(stored_job.name, 'async-test-job-with-data') |
| 1219 | + self.assertEqual(stored_job.schedule, '@every 2m') |
| 1220 | + self.assertEqual(stored_job.repeats, 3) |
| 1221 | + self.assertEqual(stored_job.ttl, '10m') |
| 1222 | + self.assertEqual(stored_job.overwrite, False) |
| 1223 | + |
| 1224 | + # Verify data field contains the payload |
| 1225 | + self.assertTrue(stored_job.HasField('data')) |
| 1226 | + self.assertEqual( |
| 1227 | + stored_job.data.value, b'{"message": "Hello from async job!", "priority": "high"}' |
| 1228 | + ) |
| 1229 | + |
| 1230 | + await dapr.close() |
| 1231 | + |
| 1232 | + async def test_schedule_job_alpha1_validation_error(self): |
| 1233 | + """Test async validation error in job scheduling.""" |
| 1234 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1235 | + |
| 1236 | + # Test empty job name - this should be caught by client validation |
| 1237 | + with self.assertRaises(ValueError): |
| 1238 | + job = Job(name='', schedule='@every 1m') |
| 1239 | + await dapr.schedule_job_alpha1(job) |
| 1240 | + |
| 1241 | + # Test missing schedule and due_time - this should be caught by client validation |
| 1242 | + with self.assertRaises(ValueError): |
| 1243 | + job = Job(name='async-test-job') |
| 1244 | + await dapr.schedule_job_alpha1(job) |
| 1245 | + |
| 1246 | + await dapr.close() |
| 1247 | + |
| 1248 | + async def test_schedule_jobs_error_handling(self): |
| 1249 | + """Test async error handling for Jobs API using fake server's exception mechanism.""" |
| 1250 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1251 | + |
| 1252 | + # Set up fake server to raise an exception on next call |
| 1253 | + error_status = status_pb2.Status( |
| 1254 | + code=code_pb2.INTERNAL, message='Simulated async server error' |
| 1255 | + ) |
| 1256 | + self._fake_dapr_server.raise_exception_on_next_call(error_status) |
| 1257 | + |
| 1258 | + # Try to schedule a job - should raise DaprGrpcError |
| 1259 | + job = Job(name='async-error-test', schedule='@every 1m') |
| 1260 | + with self.assertRaises(DaprGrpcError): |
| 1261 | + await dapr.schedule_job_alpha1(job) |
| 1262 | + |
| 1263 | + await dapr.close() |
| 1264 | + |
| 1265 | + async def test_get_job_alpha1_success(self): |
| 1266 | + """Test successful async job retrieval.""" |
| 1267 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1268 | + |
| 1269 | + # First schedule a job |
| 1270 | + original_job = Job(name='async-get-test-job', schedule='@every 1m', repeats=5, ttl='1h') |
| 1271 | + await dapr.schedule_job_alpha1(original_job) |
| 1272 | + |
| 1273 | + # Now retrieve it |
| 1274 | + retrieved_job = await dapr.get_job_alpha1('async-get-test-job') |
| 1275 | + |
| 1276 | + # Verify response |
| 1277 | + self.assertIsInstance(retrieved_job, Job) |
| 1278 | + self.assertEqual(retrieved_job.name, 'async-get-test-job') |
| 1279 | + self.assertEqual(retrieved_job.schedule, '@every 1m') |
| 1280 | + self.assertEqual(retrieved_job.repeats, 5) |
| 1281 | + self.assertEqual(retrieved_job.ttl, '1h') |
| 1282 | + self.assertEqual(retrieved_job.overwrite, False) |
| 1283 | + |
| 1284 | + await dapr.close() |
| 1285 | + |
| 1286 | + async def test_get_job_alpha1_validation_error(self): |
| 1287 | + """Test async validation error in job retrieval.""" |
| 1288 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1289 | + |
| 1290 | + with self.assertRaises(ValueError): |
| 1291 | + await dapr.get_job_alpha1('') |
| 1292 | + |
| 1293 | + await dapr.close() |
| 1294 | + |
| 1295 | + async def test_get_job_alpha1_not_found(self): |
| 1296 | + """Test async getting a job that doesn't exist.""" |
| 1297 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1298 | + |
| 1299 | + # Setup server to raise an exception |
| 1300 | + self._fake_dapr_server.raise_exception_on_next_call( |
| 1301 | + status_pb2.Status(code=code_pb2.NOT_FOUND, message='Job not found') |
| 1302 | + ) |
| 1303 | + |
| 1304 | + with self.assertRaises(DaprGrpcError): |
| 1305 | + await dapr.get_job_alpha1('async-non-existent-job') |
| 1306 | + |
| 1307 | + await dapr.close() |
| 1308 | + |
| 1309 | + async def test_delete_job_alpha1_success(self): |
| 1310 | + """Test successful async job deletion.""" |
| 1311 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1312 | + |
| 1313 | + # First schedule a job |
| 1314 | + job = Job(name='async-delete-test-job', schedule='@every 1m') |
| 1315 | + await dapr.schedule_job_alpha1(job) |
| 1316 | + |
| 1317 | + # Verify job exists |
| 1318 | + self.assertIn('async-delete-test-job', self._fake_dapr_server.jobs) |
| 1319 | + |
| 1320 | + # Delete the job |
| 1321 | + response = await dapr.delete_job_alpha1('async-delete-test-job') |
| 1322 | + |
| 1323 | + # Verify response |
| 1324 | + self.assertIsInstance(response, DaprResponse) |
| 1325 | + |
| 1326 | + # Verify job was removed from fake server |
| 1327 | + self.assertNotIn('async-delete-test-job', self._fake_dapr_server.jobs) |
| 1328 | + |
| 1329 | + await dapr.close() |
| 1330 | + |
| 1331 | + async def test_delete_job_alpha1_validation_error(self): |
| 1332 | + """Test async validation error in job deletion.""" |
| 1333 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1334 | + |
| 1335 | + with self.assertRaises(ValueError): |
| 1336 | + await dapr.delete_job_alpha1('') |
| 1337 | + |
| 1338 | + await dapr.close() |
| 1339 | + |
| 1340 | + async def test_job_lifecycle(self): |
| 1341 | + """Test complete async job lifecycle: schedule → get → delete.""" |
| 1342 | + from google.protobuf.any_pb2 import Any as GrpcAny |
| 1343 | + |
| 1344 | + dapr = DaprGrpcClientAsync(f'{self.scheme}localhost:{self.grpc_port}') |
| 1345 | + |
| 1346 | + # Create job with data |
| 1347 | + data = GrpcAny() |
| 1348 | + data.value = b'{"lifecycle": "test"}' |
| 1349 | + |
| 1350 | + job = Job( |
| 1351 | + name='async-lifecycle-job', |
| 1352 | + schedule='@every 5m', |
| 1353 | + data=data, |
| 1354 | + repeats=10, |
| 1355 | + ttl='30m', |
| 1356 | + overwrite=True, |
| 1357 | + ) |
| 1358 | + |
| 1359 | + # 1. Schedule the job |
| 1360 | + schedule_response = await dapr.schedule_job_alpha1(job) |
| 1361 | + self.assertIsInstance(schedule_response, DaprResponse) |
| 1362 | + |
| 1363 | + # 2. Get the job and verify all fields |
| 1364 | + retrieved_job = await dapr.get_job_alpha1('async-lifecycle-job') |
| 1365 | + self.assertEqual(retrieved_job.name, 'async-lifecycle-job') |
| 1366 | + self.assertEqual(retrieved_job.schedule, '@every 5m') |
| 1367 | + self.assertEqual(retrieved_job.repeats, 10) |
| 1368 | + self.assertEqual(retrieved_job.ttl, '30m') |
| 1369 | + self.assertTrue(retrieved_job.overwrite) |
| 1370 | + self.assertEqual(retrieved_job.data.value, b'{"lifecycle": "test"}') |
| 1371 | + |
| 1372 | + # 3. Delete the job |
| 1373 | + delete_response = await dapr.delete_job_alpha1('async-lifecycle-job') |
| 1374 | + self.assertIsInstance(delete_response, DaprResponse) |
| 1375 | + |
| 1376 | + # 4. Verify job is gone |
| 1377 | + self.assertNotIn('async-lifecycle-job', self._fake_dapr_server.jobs) |
| 1378 | + |
| 1379 | + await dapr.close() |
| 1380 | + |
1167 | 1381 |
|
1168 | 1382 | if __name__ == '__main__': |
1169 | 1383 | unittest.main() |
0 commit comments