from datetime import date from unittest.mock import patch import pytest from external_api.base.clients.delphi_client import AdsPerformanceResponse from tests.performance.utils import metrics_result, total_metrics_result, stub_snowflake_response from utils.snowflake.metrics.schema import MetricsFilters from models import models, Campaign from tests import BaseTestCase, mock_for_user from tests.performance.fixtures.performance_metrics_fixture import fixture from tests.performance.utils import mock_from_json from tests.test_utils import FixtureLoader user1Mock = mock_for_user(1, "dev-marketing-user-1@example.com", "sme-dna|5cf0091d6c91d310fe6fcdc6") user2Mock = mock_for_user(2, "dev-marketing-user-2@example.com", "sme-dna|3po0091d6c91ty670fe6ftryf") async def mocked_metrics_for_artists(*args, **kwargs): return mock_from_json(AdsPerformanceResponse, "performance/fixtures/artists_ads_performance_metrics.json") async def mocked_metrics_for_projects(*args, **kwargs): return mock_from_json(AdsPerformanceResponse, "performance/fixtures/projects_ads_performance_metrics.json") async def mocked_metrics_for_campaigns(*args, **kwargs): return mock_from_json(AdsPerformanceResponse, "performance/fixtures/campaigns_ads_performance_metrics.json") class TestPerformanceMetrics(BaseTestCase): url = "/performance/metrics" def setUp(self): super().setUp() FixtureLoader(models=models).import_as_sql(fixture) @patch("auth.atlas.atlas_token_decoder.jwt.decode", user1Mock.jwt_decode) @patch("models.mixins.searchable.SearchableMixin.search") @patch("external_api.base.clients.delphi_client.DelphiClient.get_ads_performance", new=mocked_metrics_for_artists) def test_get_artists_metrics(self, search): response = self.execute_get( self.url + "/artists", headers=self.headers, query_string={ "startDate": "2020-10-05", "endDate": "2020-10-10", "labels": [4, 5], "provider": 1, "fields": [16, 26, 39, 40, 63], }, ) self.assertEqual(200, response.status_code) items = response.json["items"] self.assertIs(list, type(items)) self.assertEqual(3, len(items)) self.assertEqual( items[0], { "entityId": "GRAS_2010", "fields": { "12": None, "13": None, "16": 390.34, "17": 580, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 178964, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 1125000, "73": 1125000, "74": 0.12345, "75": 1125000, "76": 0.12345, "77": 1125000, "78": 1125000, "79": 1125000, "80": 1125000, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.12345, }, "name": "TestAtrist", "metadata": None, }, ) self.assertEqual( items[1], { "entityId": "GRAS_2040", "fields": { "12": None, "13": None, "16": 8.186809, "17": 13, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 780, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 79, "73": 8, "74": 0.12388, "75": 1125000, "76": 0.12345, "77": 1, "78": 7, "79": 9, "80": 45, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.34567, }, "name": "artist2", "metadata": None, }, ) self.assertEqual( items[2], { "entityId": "GRAS_2060", "fields": { "12": None, "13": None, "16": 8.186809, "17": 13, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 780, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 199, "73": 18, "74": 0.988, "75": 234567, "76": 0.2345, "77": 15, "78": 27, "79": 922, "80": 4455, "82": 0.12345, "83": 0.3345, "84": 0.2345, "85": 0.1, }, "name": "UpdateArtist", "metadata": None, }, ) self.assertEqual( response.json["totalFields"], { "12": None, "13": None, "16": 390.34, "17": 580, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 178964, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 1125000, "73": 1125000, "74": 0.12345, "75": 1125000, "76": 0.12345, "77": 1125000, "78": 1125000, "79": 1125000, "80": 1125000, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.12345, }, ) self.assert_all() @patch("auth.atlas.atlas_token_decoder.jwt.decode", user1Mock.jwt_decode) @patch("models.mixins.searchable.SearchableMixin.search") @patch("external_api.base.clients.delphi_client.DelphiClient.get_ads_performance", new=mocked_metrics_for_projects) def test_get_projects_metrics(self, search): response = self.execute_get( self.url + "/projects", headers=self.headers, query_string={ "startDate": "2020-12-10", "endDate": "2020-12-15", "labels": [4, 5], "provider": 1, "fields": [16, 26, 39, 40, 63], }, ) self.assertEqual(200, response.status_code) items = response.json["items"] self.assertIs(list, type(items)) self.assertEqual(2, len(items)) self.assertEqual( items[0], { "entityId": "500", "fields": { "12": None, "13": None, "16": 390.34, "17": 580, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 178964, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "49": "2020-10-13", "50": "2020-12-31", "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 6789, "73": 9876, "74": 0.67345, "75": 877, "76": 0.4567, "77": 98766, "78": 6, "79": 45, "80": 33, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.12345, }, "name": "test_project_500", "metadata": { "canApproveCampaigns": True, "hasPendingCampaigns": True, "isConfidential": False, "projectId": 500, }, }, ) self.assertEqual( items[1], { "entityId": "503", "fields": { "12": None, "13": None, "16": 8.186809, "17": 13, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 780, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "49": "2018-04-28", "50": "2021-01-31", "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 4567, "73": 77, "74": 0.67345, "75": 877, "76": 0.4567, "77": 98766, "78": 6, "79": 45, "80": 33, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.12345, }, "name": "test_project_502", "metadata": { "hasPendingCampaigns": False, "canApproveCampaigns": True, "projectId": 503, "isConfidential": False, }, }, ) self.assertEqual( response.json["totalFields"], { "12": None, "13": None, "16": 390.34, "17": 580, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 178964, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 6789, "73": 9876, "74": 0.67345, "75": 877, "76": 0.4567, "77": 98766, "78": 6, "79": 45, "80": 33, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.12345, }, ) self.assert_all() @patch("auth.atlas.atlas_token_decoder.jwt.decode", user1Mock.jwt_decode) @patch("models.mixins.searchable.SearchableMixin.search") @patch("external_api.base.clients.delphi_client.DelphiClient.get_ads_performance", new=mocked_metrics_for_campaigns) def test_get_campaigns_metrics(self, search): response = self.execute_get( self.url + "/campaigns", headers=self.headers, query_string={ "startDate": "2020-11-10", "endDate": "2020-12-15", "labels": [4, 5], "provider": 1, "fields": [16, 26, 39, 40, 63], }, ) self.assertEqual(200, response.status_code) items = response.json["items"] self.assertIs(list, type(items)) self.assertEqual(2, len(items)) self.assertEqual( items[0], { "entityId": "google_65838578", "fields": { "12": None, "13": None, "16": 7.435426, "17": 17, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 1120, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "49": "2020-09-14", "50": "2020-09-24", "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 1125000, "73": 1125000, "74": 0.12345, "75": 1125000, "76": 0.12345, "77": 1125000, "78": 1125000, "79": 1125000, "80": 1125000, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.12345, }, "metadata": {"campaignId": 5, "isPending": False, "projectId": 500}, "name": "test_campaign_5", }, ) self.assertEqual( items[1], { "entityId": "google_56748930", "fields": { "12": None, "13": None, "16": 179.34999999999997, "17": 299, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 132393, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "49": "2020-10-14", "50": "2020-12-31", "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 79, "73": 8, "74": 0.12388, "75": 1125000, "76": 0.12345, "77": 1, "78": 7, "79": 9, "80": 45, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.34567, }, "metadata": {"campaignId": 2, "isPending": False, "projectId": 500}, "name": "test_campaign_2", }, ) self.assertEqual( response.json["totalFields"], { "12": None, "13": None, "16": 7.435426, "17": 17, "18": None, "19": None, "2": None, "20": None, "21": None, "22": None, "23": None, "26": 0, "27": None, "28": None, "30": None, "32": None, "33": None, "35": 0, "36": None, "37": 0.0, "38": None, "39": 0.0, "40": 1120, "41": 0.0, "42": None, "43": None, "44": None, "47": None, "51": None, "59": None, "6": 0, "60": None, "61": None, "63": 0.0, "64": 0.0, "68": None, "69": None, "70": None, "72": 1125000, "73": 1125000, "74": 0.12345, "75": 1125000, "76": 0.12345, "77": 1125000, "78": 1125000, "79": 1125000, "80": 1125000, "82": 0.12345, "83": 0.12345, "84": 0.12345, "85": 0.12345, }, ) self.assert_all() @patch("auth.atlas.atlas_token_decoder.jwt.decode", user1Mock.jwt_decode) @patch("performance.services.performance_metrics_service.default_fetcher") @patch("models.mixins.searchable.SearchableMixin.search") @pytest.mark.skip(reason="Add tests after release") def test_get_unassigned_campaigns_metrics(self, search, fetcher_producer): def verify_filters(param: MetricsFilters): self.soft_assert_equal(param.dates.start, date(2020, 11, 10)) self.soft_assert_equal(param.dates.end, date(2020, 12, 15)) items = [ metrics_result(entity_id=56748930, spend=240), metrics_result(entity_id=65838578, video_views=100, start_date=date(2020, 12, 11)), metrics_result(entity_id=99665533, video_views=20, start_date=date(2020, 11, 11)), ] total_counter = total_metrics_result(entities_count=3, spend=102, video_views=98) stub_snowflake_response(fetcher_producer, verify_filters, items, total_counter) search.return_value = [10, 30, 50] response = self.execute_get( self.url + "/unassigned-campaigns", headers=self.headers, query_string={ "startDate": "2020-11-10", "endDate": "2020-12-15", "labels": [4, 5], "provider": 1, "fields": [16, 26, 39, 40, 63], }, ) search.assert_called_once_with(expression="test", fields=[Campaign.name]) self.assertEqual(200, response.status_code) items = response.json["items"] self.assertIs(list, type(items)) self.assertEqual(3, len(items)) self.assertEqual( items[0], { "entityId": "56748930", "fields": {"16": 240, "26": 123, "39": 34.6, "40": 11, "63": 34.7}, "name": "test_campaign_2", "metadata": {"campaignId": 2, "projectId": 500, "isPending": False}, }, ) self.assertEqual( items[1], { "entityId": "65838578", "fields": {"16": 20.5, "26": 100, "39": 34.6, "40": 11, "63": 34.7}, "name": "test_campaign_5", "metadata": {"campaignId": 5, "projectId": 500, "isPending": False}, }, ) self.assertEqual( items[2], { "entityId": "99665533", "fields": {"16": 20.5, "26": 20, "39": 34.6, "40": 11, "63": 34.7}, "name": "test_campaign_7", "metadata": {"campaignId": 7, "projectId": 502, "isPending": False}, }, ) self.assertEqual(response.json["totalFields"], {"16": 102, "26": 98, "39": 34.6, "40": 11, "63": 34.7}) self.assertEqual(response.json["total"], 3) self.assertEqual(response.json["limit"], 20) self.assertEqual(response.json["offset"], 0) self.assert_all() @patch("auth.atlas.atlas_token_decoder.jwt.decode", user1Mock.jwt_decode) @patch("performance.services.performance_metrics_service.default_fetcher") @patch("models.mixins.searchable.SearchableMixin.search") @pytest.mark.skip(reason="Add tests after release") def test_get_project_metrics(self, search, fetcher_producer): def verify_filters(param: MetricsFilters): self.soft_assert_equal(param.dates.start, date(2007, 1, 1)) self.soft_assert_equal(param.dates.end, date(2008, 12, 15)) items = [ metrics_result(entity_id=100, spend=240), metrics_result(entity_id=200, video_views=100, start_date=date(2020, 12, 11)), metrics_result(entity_id=300, video_views=20, start_date=date(2020, 11, 11)), ] total_counter = total_metrics_result(entities_count=3, spend=102, video_views=98) stub_snowflake_response(fetcher_producer, verify_filters, items, total_counter) search.return_value = [10, 30, 50] response = self.execute_get( "/projects/500/metrics", headers=self.headers, query_string={"startDate": "2007-01-01", "endDate": "2008-12-15", "fields": [16, 26, 39, 40, 63]}, ) self.assertEqual(200, response.status_code) items = response.json["items"] self.assertIs(list, type(items)) self.assertEqual(3, len(items)) self.assertEqual( items[0], { "entityId": "100", "fields": {"16": 240, "26": 123, "39": 34.6, "40": 11, "63": 34.7}, "name": "Phase 1", "metadata": None, }, ) self.assertEqual( items[1], { "entityId": "200", "fields": {"16": 20.5, "26": 100, "39": 34.6, "40": 11, "63": 34.7}, "name": "Phase 2", "metadata": None, }, ) self.assertEqual( items[2], { "entityId": "300", "fields": {"16": 20.5, "26": 20, "39": 34.6, "40": 11, "63": 34.7}, "name": "Phase 3", "metadata": None, }, ) self.assertEqual(response.json["totalFields"], {"16": 102, "26": 98, "39": 34.6, "40": 11, "63": 34.7}) self.assertEqual(response.json["total"], 3) self.assertEqual(response.json["limit"], 20) self.assertEqual(response.json["offset"], 0) self.assert_all() @patch("auth.atlas.atlas_token_decoder.jwt.decode", user2Mock.jwt_decode) @patch("models.mixins.searchable.SearchableMixin.search") @patch("external_api.base.clients.delphi_client.DelphiClient.get_ads_performance", new=mocked_metrics_for_projects) def test_get_project_metrics_for_user_with_no_access_should_return_403(self, search): response = self.execute_get( "/projects/500/media-plans/42/metrics", headers=self.headers, query_string={"startDate": "2007-01-01", "endDate": "2008-12-15", "fields": [16, 26, 39, 40, 63]}, ) self.assertEqual(403, response.status_code) self.assert_all()