123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- import boto3
- import pytest
- from mock import patch
- from backend.lambdas.jobs.stats_updater import update_stats
- pytestmark = [pytest.mark.unit, pytest.mark.jobs]
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_successful_queries(table):
- resp = update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "QuerySucceeded",
- "EventData": {
- "Statistics": {
- "DataScannedInBytes": 10,
- "EngineExecutionTimeInMillis": 100,
- }
- },
- }
- ],
- )
- table.update_item.assert_called_with(
- Key={
- "Id": "job123",
- "Sk": "job123",
- },
- ConditionExpression="#Id = :Id AND #Sk = :Sk",
- UpdateExpression="set #qt = if_not_exists(#qt, :z) + :qt, "
- "#qs = if_not_exists(#qs, :z) + :qs, "
- "#qf = if_not_exists(#qf, :z) + :qf, "
- "#qb = if_not_exists(#qb, :z) + :qb, "
- "#qm = if_not_exists(#qm, :z) + :qm, "
- "#ou = if_not_exists(#ou, :z) + :ou, "
- "#os = if_not_exists(#os, :z) + :os, "
- "#of = if_not_exists(#of, :z) + :of, "
- "#or = if_not_exists(#or, :z) + :or",
- ExpressionAttributeNames={
- "#Id": "Id",
- "#Sk": "Sk",
- "#qt": "TotalQueryCount",
- "#qs": "TotalQuerySucceededCount",
- "#qf": "TotalQueryFailedCount",
- "#qb": "TotalQueryScannedInBytes",
- "#qm": "TotalQueryTimeInMillis",
- "#ou": "TotalObjectUpdatedCount",
- "#os": "TotalObjectUpdateSkippedCount",
- "#of": "TotalObjectUpdateFailedCount",
- "#or": "TotalObjectRollbackFailedCount",
- },
- ExpressionAttributeValues={
- ":Id": "job123",
- ":Sk": "job123",
- ":qt": 1,
- ":qs": 1,
- ":qf": 0,
- ":qb": 10,
- ":qm": 100,
- ":ou": 0,
- ":os": 0,
- ":of": 0,
- ":or": 0,
- ":z": 0,
- },
- ReturnValues="ALL_NEW",
- )
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_failed_queries(table):
- resp = update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "QueryFailed",
- "EventData": {},
- }
- ],
- )
- table.update_item.assert_called_with(
- Key={
- "Id": "job123",
- "Sk": "job123",
- },
- ConditionExpression="#Id = :Id AND #Sk = :Sk",
- UpdateExpression="set #qt = if_not_exists(#qt, :z) + :qt, "
- "#qs = if_not_exists(#qs, :z) + :qs, "
- "#qf = if_not_exists(#qf, :z) + :qf, "
- "#qb = if_not_exists(#qb, :z) + :qb, "
- "#qm = if_not_exists(#qm, :z) + :qm, "
- "#ou = if_not_exists(#ou, :z) + :ou, "
- "#os = if_not_exists(#os, :z) + :os, "
- "#of = if_not_exists(#of, :z) + :of, "
- "#or = if_not_exists(#or, :z) + :or",
- ExpressionAttributeNames={
- "#Id": "Id",
- "#Sk": "Sk",
- "#qt": "TotalQueryCount",
- "#qs": "TotalQuerySucceededCount",
- "#qf": "TotalQueryFailedCount",
- "#qb": "TotalQueryScannedInBytes",
- "#qm": "TotalQueryTimeInMillis",
- "#ou": "TotalObjectUpdatedCount",
- "#os": "TotalObjectUpdateSkippedCount",
- "#of": "TotalObjectUpdateFailedCount",
- "#or": "TotalObjectRollbackFailedCount",
- },
- ExpressionAttributeValues={
- ":Id": "job123",
- ":Sk": "job123",
- ":qt": 1,
- ":qs": 0,
- ":qf": 1,
- ":qb": 0,
- ":qm": 0,
- ":ou": 0,
- ":os": 0,
- ":of": 0,
- ":or": 0,
- ":z": 0,
- },
- ReturnValues="ALL_NEW",
- )
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_successful_updates(table):
- resp = update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "ObjectUpdated",
- "EventData": {},
- }
- ],
- )
- table.update_item.assert_called_with(
- Key={"Id": "job123", "Sk": "job123"},
- ConditionExpression="#Id = :Id AND #Sk = :Sk",
- UpdateExpression="set #qt = if_not_exists(#qt, :z) + :qt, "
- "#qs = if_not_exists(#qs, :z) + :qs, "
- "#qf = if_not_exists(#qf, :z) + :qf, "
- "#qb = if_not_exists(#qb, :z) + :qb, "
- "#qm = if_not_exists(#qm, :z) + :qm, "
- "#ou = if_not_exists(#ou, :z) + :ou, "
- "#os = if_not_exists(#os, :z) + :os, "
- "#of = if_not_exists(#of, :z) + :of, "
- "#or = if_not_exists(#or, :z) + :or",
- ExpressionAttributeNames={
- "#Id": "Id",
- "#Sk": "Sk",
- "#qt": "TotalQueryCount",
- "#qs": "TotalQuerySucceededCount",
- "#qf": "TotalQueryFailedCount",
- "#qb": "TotalQueryScannedInBytes",
- "#qm": "TotalQueryTimeInMillis",
- "#ou": "TotalObjectUpdatedCount",
- "#os": "TotalObjectUpdateSkippedCount",
- "#of": "TotalObjectUpdateFailedCount",
- "#or": "TotalObjectRollbackFailedCount",
- },
- ExpressionAttributeValues={
- ":Id": "job123",
- ":Sk": "job123",
- ":qt": 0,
- ":qs": 0,
- ":qf": 0,
- ":qb": 0,
- ":qm": 0,
- ":ou": 1,
- ":os": 0,
- ":of": 0,
- ":or": 0,
- ":z": 0,
- },
- ReturnValues="ALL_NEW",
- )
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_failed_updates(table):
- resp = update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "ObjectUpdateFailed",
- "EventData": {},
- }
- ],
- )
- table.update_item.assert_called_with(
- Key={"Id": "job123", "Sk": "job123"},
- ConditionExpression="#Id = :Id AND #Sk = :Sk",
- UpdateExpression="set #qt = if_not_exists(#qt, :z) + :qt, "
- "#qs = if_not_exists(#qs, :z) + :qs, "
- "#qf = if_not_exists(#qf, :z) + :qf, "
- "#qb = if_not_exists(#qb, :z) + :qb, "
- "#qm = if_not_exists(#qm, :z) + :qm, "
- "#ou = if_not_exists(#ou, :z) + :ou, "
- "#os = if_not_exists(#os, :z) + :os, "
- "#of = if_not_exists(#of, :z) + :of, "
- "#or = if_not_exists(#or, :z) + :or",
- ExpressionAttributeNames={
- "#Id": "Id",
- "#Sk": "Sk",
- "#qt": "TotalQueryCount",
- "#qs": "TotalQuerySucceededCount",
- "#qf": "TotalQueryFailedCount",
- "#qb": "TotalQueryScannedInBytes",
- "#qm": "TotalQueryTimeInMillis",
- "#ou": "TotalObjectUpdatedCount",
- "#os": "TotalObjectUpdateSkippedCount",
- "#of": "TotalObjectUpdateFailedCount",
- "#or": "TotalObjectRollbackFailedCount",
- },
- ExpressionAttributeValues={
- ":Id": "job123",
- ":Sk": "job123",
- ":qt": 0,
- ":qs": 0,
- ":qf": 0,
- ":qb": 0,
- ":qm": 0,
- ":ou": 0,
- ":os": 0,
- ":of": 1,
- ":or": 0,
- ":z": 0,
- },
- ReturnValues="ALL_NEW",
- )
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_skipped_updates(table):
- resp = update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "ObjectUpdateSkipped",
- "EventData": {},
- }
- ],
- )
- table.update_item.assert_called_with(
- Key={"Id": "job123", "Sk": "job123"},
- ConditionExpression="#Id = :Id AND #Sk = :Sk",
- UpdateExpression="set #qt = if_not_exists(#qt, :z) + :qt, "
- "#qs = if_not_exists(#qs, :z) + :qs, "
- "#qf = if_not_exists(#qf, :z) + :qf, "
- "#qb = if_not_exists(#qb, :z) + :qb, "
- "#qm = if_not_exists(#qm, :z) + :qm, "
- "#ou = if_not_exists(#ou, :z) + :ou, "
- "#os = if_not_exists(#os, :z) + :os, "
- "#of = if_not_exists(#of, :z) + :of, "
- "#or = if_not_exists(#or, :z) + :or",
- ExpressionAttributeNames={
- "#Id": "Id",
- "#Sk": "Sk",
- "#qt": "TotalQueryCount",
- "#qs": "TotalQuerySucceededCount",
- "#qf": "TotalQueryFailedCount",
- "#qb": "TotalQueryScannedInBytes",
- "#qm": "TotalQueryTimeInMillis",
- "#ou": "TotalObjectUpdatedCount",
- "#os": "TotalObjectUpdateSkippedCount",
- "#of": "TotalObjectUpdateFailedCount",
- "#or": "TotalObjectRollbackFailedCount",
- },
- ExpressionAttributeValues={
- ":Id": "job123",
- ":Sk": "job123",
- ":qt": 0,
- ":qs": 0,
- ":qf": 0,
- ":qb": 0,
- ":qm": 0,
- ":ou": 0,
- ":os": 1,
- ":of": 0,
- ":or": 0,
- ":z": 0,
- },
- ReturnValues="ALL_NEW",
- )
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_failed_rollbacks(table):
- resp = update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "ObjectRollbackFailed",
- "EventData": {},
- }
- ],
- )
- table.update_item.assert_called_with(
- Key={"Id": "job123", "Sk": "job123"},
- ConditionExpression="#Id = :Id AND #Sk = :Sk",
- UpdateExpression="set #qt = if_not_exists(#qt, :z) + :qt, "
- "#qs = if_not_exists(#qs, :z) + :qs, "
- "#qf = if_not_exists(#qf, :z) + :qf, "
- "#qb = if_not_exists(#qb, :z) + :qb, "
- "#qm = if_not_exists(#qm, :z) + :qm, "
- "#ou = if_not_exists(#ou, :z) + :ou, "
- "#os = if_not_exists(#os, :z) + :os, "
- "#of = if_not_exists(#of, :z) + :of, "
- "#or = if_not_exists(#or, :z) + :or",
- ExpressionAttributeNames={
- "#Id": "Id",
- "#Sk": "Sk",
- "#qt": "TotalQueryCount",
- "#qs": "TotalQuerySucceededCount",
- "#qf": "TotalQueryFailedCount",
- "#qb": "TotalQueryScannedInBytes",
- "#qm": "TotalQueryTimeInMillis",
- "#ou": "TotalObjectUpdatedCount",
- "#os": "TotalObjectUpdateSkippedCount",
- "#of": "TotalObjectUpdateFailedCount",
- "#or": "TotalObjectRollbackFailedCount",
- },
- ExpressionAttributeValues={
- ":Id": "job123",
- ":Sk": "job123",
- ":qt": 0,
- ":qs": 0,
- ":qf": 0,
- ":qb": 0,
- ":qm": 0,
- ":ou": 0,
- ":os": 0,
- ":of": 0,
- ":or": 1,
- ":z": 0,
- },
- ReturnValues="ALL_NEW",
- )
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_multiple_events(table):
- resp = update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "QuerySucceeded",
- "EventData": {
- "Statistics": {
- "DataScannedInBytes": 10,
- "EngineExecutionTimeInMillis": 100,
- }
- },
- },
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "ObjectUpdated",
- "EventData": {},
- },
- ],
- )
- table.update_item.assert_called_with(
- Key={"Id": "job123", "Sk": "job123"},
- ConditionExpression="#Id = :Id AND #Sk = :Sk",
- UpdateExpression="set #qt = if_not_exists(#qt, :z) + :qt, "
- "#qs = if_not_exists(#qs, :z) + :qs, "
- "#qf = if_not_exists(#qf, :z) + :qf, "
- "#qb = if_not_exists(#qb, :z) + :qb, "
- "#qm = if_not_exists(#qm, :z) + :qm, "
- "#ou = if_not_exists(#ou, :z) + :ou, "
- "#os = if_not_exists(#os, :z) + :os, "
- "#of = if_not_exists(#of, :z) + :of, "
- "#or = if_not_exists(#or, :z) + :or",
- ExpressionAttributeNames={
- "#Id": "Id",
- "#Sk": "Sk",
- "#qt": "TotalQueryCount",
- "#qs": "TotalQuerySucceededCount",
- "#qf": "TotalQueryFailedCount",
- "#qb": "TotalQueryScannedInBytes",
- "#qm": "TotalQueryTimeInMillis",
- "#ou": "TotalObjectUpdatedCount",
- "#os": "TotalObjectUpdateSkippedCount",
- "#of": "TotalObjectUpdateFailedCount",
- "#or": "TotalObjectRollbackFailedCount",
- },
- ExpressionAttributeValues={
- ":Id": "job123",
- ":Sk": "job123",
- ":qt": 1,
- ":qs": 1,
- ":qf": 0,
- ":qb": 10,
- ":qm": 100,
- ":ou": 1,
- ":os": 0,
- ":of": 0,
- ":or": 0,
- ":z": 0,
- },
- ReturnValues="ALL_NEW",
- )
- @patch("backend.lambdas.jobs.stats_updater.ddb")
- @patch("backend.lambdas.jobs.stats_updater.table")
- def test_it_handles_already_failed_jobs(table, ddb):
- e = boto3.client("dynamodb").exceptions.ConditionalCheckFailedException
- ddb.meta.client.exceptions.ConditionalCheckFailedException = e
- table.update_item.side_effect = e({}, "ConditionalCheckFailedException")
- update_stats(
- "job123",
- [
- {
- "Id": "job123",
- "Sk": "123456",
- "Type": "JobEvent",
- "CreatedAt": 123.0,
- "EventName": "QuerySucceeded",
- "EventData": {
- "Statistics": {
- "DataScannedInBytes": 10,
- "EngineExecutionTimeInMillis": 100,
- }
- },
- }
- ],
- )
- table.update_item.assert_called()
|