-
Notifications
You must be signed in to change notification settings - Fork 137
Adds Configurable property for action breakdowns #260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 13 commits
2a4ba5d
41d8312
489fc49
e6fadfb
3c3e477
89b2ec4
982dd63
fa7a2e2
7c4e89e
1c118fe
2ca7fcf
58fd486
ee0c3e1
16af03c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -813,6 +813,23 @@ def __iter__(self): | |||||
| "primary-keys": ['hourly_stats_aggregated_by_advertiser_time_zone']}, | ||||||
| } | ||||||
|
|
||||||
| def parse_action_breakdowns(breakdown_str): | ||||||
| if not breakdown_str: | ||||||
| return ALL_ACTION_BREAKDOWNS | ||||||
| if not isinstance(breakdown_str, str): | ||||||
| LOGGER.warning("action_breakdowns must be a string, got %s", type(breakdown_str)) | ||||||
| return ALL_ACTION_BREAKDOWNS | ||||||
|
|
||||||
| selected_breakdowns = [] | ||||||
| act_breakdowns = [b.strip().lower() for b in breakdown_str.split(',')] | ||||||
| for breakdown in act_breakdowns: | ||||||
| if not breakdown: # Skip empty strings | ||||||
| continue | ||||||
| if breakdown in ALL_ACTION_BREAKDOWNS and breakdown not in selected_breakdowns: | ||||||
| selected_breakdowns.append(breakdown) | ||||||
| else: | ||||||
| LOGGER.warning("Invalid action breakdown %s", breakdown) | ||||||
| return selected_breakdowns if selected_breakdowns else ALL_ACTION_BREAKDOWNS | ||||||
|
|
||||||
| def initialize_stream(account, catalog_entry, state): # pylint: disable=too-many-return-statements | ||||||
|
|
||||||
|
|
@@ -821,7 +838,7 @@ def initialize_stream(account, catalog_entry, state): # pylint: disable=too-many | |||||
|
|
||||||
| if name in INSIGHTS_BREAKDOWNS_OPTIONS: | ||||||
| return AdsInsights(name, account, stream_alias, catalog_entry, state=state, | ||||||
| options=INSIGHTS_BREAKDOWNS_OPTIONS[name]) | ||||||
| options=INSIGHTS_BREAKDOWNS_OPTIONS[name], action_breakdowns=CONFIG["action_breakdowns"]) | ||||||
|
||||||
| options=INSIGHTS_BREAKDOWNS_OPTIONS[name], action_breakdowns=CONFIG["action_breakdowns"]) | |
| options=INSIGHTS_BREAKDOWNS_OPTIONS[name], action_breakdowns=CONFIG.get("action_breakdowns", ALL_ACTION_BREAKDOWNS)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be updated
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| import unittest | ||
| from tap_facebook import parse_action_breakdowns, ALL_ACTION_BREAKDOWNS | ||
|
|
||
|
|
||
| class TestParseActionBreakdowns(unittest.TestCase): | ||
| """Test suite for parse_action_breakdowns function""" | ||
|
|
||
| def test_none_returns_all_breakdowns(self): | ||
| """Test that None input returns all default breakdowns""" | ||
| result = parse_action_breakdowns(None) | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
| self.assertEqual(len(result), 3) | ||
|
|
||
| def test_empty_string_returns_all_breakdowns(self): | ||
| """Test that empty string returns all default breakdowns""" | ||
| result = parse_action_breakdowns("") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
| self.assertEqual(len(result), 3) | ||
|
|
||
| def test_non_string_type_returns_all_breakdowns(self): | ||
| """Test that non-string types return all default breakdowns with warning""" | ||
| result = parse_action_breakdowns(123) | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| result = parse_action_breakdowns(['action_type']) | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| result = parse_action_breakdowns({'breakdown': 'action_type'}) | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
Comment on lines
+20
to
+29
|
||
|
|
||
| def test_single_valid_breakdown(self): | ||
| """Test parsing a single valid breakdown""" | ||
| result = parse_action_breakdowns("action_type") | ||
| self.assertEqual(result, ['action_type']) | ||
| self.assertEqual(len(result), 1) | ||
|
|
||
| def test_multiple_valid_breakdowns(self): | ||
| """Test parsing multiple valid breakdowns""" | ||
| result = parse_action_breakdowns("action_type,action_destination") | ||
| self.assertEqual(result, ['action_type', 'action_destination']) | ||
| self.assertEqual(len(result), 2) | ||
|
|
||
| def test_all_valid_breakdowns(self): | ||
| """Test parsing all three valid breakdowns""" | ||
| result = parse_action_breakdowns("action_type,action_target_id,action_destination") | ||
| self.assertEqual(result, ['action_type', 'action_target_id', 'action_destination']) | ||
| self.assertEqual(len(result), 3) | ||
|
|
||
| def test_whitespace_handling(self): | ||
| """Test that whitespace is properly stripped""" | ||
| result = parse_action_breakdowns(" action_type , action_destination ") | ||
| self.assertEqual(result, ['action_type', 'action_destination']) | ||
|
|
||
| result = parse_action_breakdowns(" action_type , action_target_id ") | ||
| self.assertEqual(result, ['action_type', 'action_target_id']) | ||
|
|
||
| def test_case_insensitivity(self): | ||
| """Test that input is case-insensitive""" | ||
| result = parse_action_breakdowns("ACTION_TYPE,Action_Destination") | ||
| self.assertEqual(result, ['action_type', 'action_destination']) | ||
|
|
||
| result = parse_action_breakdowns("ACTION_TARGET_ID") | ||
| self.assertEqual(result, ['action_target_id']) | ||
|
|
||
| def test_mixed_valid_and_invalid(self): | ||
| """Test parsing mix of valid and invalid breakdowns""" | ||
| result = parse_action_breakdowns("action_type,invalid_breakdown,action_destination") | ||
| self.assertEqual(result, ['action_type', 'action_destination']) | ||
| self.assertEqual(len(result), 2) | ||
|
|
||
| result = parse_action_breakdowns("invalid1,action_type,invalid2") | ||
| self.assertEqual(result, ['action_type']) | ||
|
Comment on lines
+65
to
+72
|
||
|
|
||
| def test_all_invalid_returns_all_breakdowns(self): | ||
| """Test that all invalid values returns default breakdowns""" | ||
| result = parse_action_breakdowns("invalid1,invalid2,invalid3") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| result = parse_action_breakdowns("foo,bar,baz") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| def test_empty_values_skipped(self): | ||
| """Test that empty values from comma-separation are skipped""" | ||
| result = parse_action_breakdowns("action_type,,action_destination") | ||
| self.assertEqual(result, ['action_type', 'action_destination']) | ||
|
|
||
| result = parse_action_breakdowns(",action_type,") | ||
| self.assertEqual(result, ['action_type']) | ||
|
|
||
| result = parse_action_breakdowns(",,action_type,,") | ||
| self.assertEqual(result, ['action_type']) | ||
|
|
||
| def test_only_commas_returns_all_breakdowns(self): | ||
| """Test that only commas returns default breakdowns""" | ||
| result = parse_action_breakdowns(",,,") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| def test_duplicate_breakdowns(self): | ||
| """Test handling of duplicate breakdown values""" | ||
| result = parse_action_breakdowns("action_type,action_type,action_destination") | ||
| # Should not include duplicates since deduplication is performed | ||
| self.assertEqual(result, ['action_type', 'action_destination']) | ||
|
|
||
| def test_whitespace_only_string(self): | ||
| """Test whitespace-only string is treated as empty""" | ||
| result = parse_action_breakdowns(" ") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| result = parse_action_breakdowns("\t\n") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| def test_partial_match_not_accepted(self): | ||
| """Test that partial matches are not accepted""" | ||
| result = parse_action_breakdowns("action_typ") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| result = parse_action_breakdowns("action_type_extra") | ||
| self.assertEqual(result, ALL_ACTION_BREAKDOWNS) | ||
|
|
||
| def test_order_preserved(self): | ||
| """Test that order of valid breakdowns is preserved""" | ||
| result = parse_action_breakdowns("action_destination,action_type") | ||
| self.assertEqual(result, ['action_destination', 'action_type']) | ||
|
|
||
| result = parse_action_breakdowns("action_target_id,action_destination,action_type") | ||
| self.assertEqual(result, ['action_target_id', 'action_destination', 'action_type']) | ||
|
||
Uh oh!
There was an error while loading. Please reload this page.