Skip to content

feat(google-ads): upgrade SDK to 2.0.0, add full unit + integration test suite#317

Open
Shubhank-Jonnada wants to merge 7 commits into
masterfrom
feat/google-ads-sdk-upgrade-v2
Open

feat(google-ads): upgrade SDK to 2.0.0, add full unit + integration test suite#317
Shubhank-Jonnada wants to merge 7 commits into
masterfrom
feat/google-ads-sdk-upgrade-v2

Conversation

@Shubhank-Jonnada
Copy link
Copy Markdown
Contributor

@Shubhank-Jonnada Shubhank-Jonnada commented May 5, 2026

Summary

  • SDK 2.0.0 migration: Updated google_ads.py and requirements.txt to use autohive-integrations-sdk~=2.0.0. Action handlers return the SDK2 IntegrationResult shape with ActionResult / ActionError as appropriate.
  • Auth alignment fix: Google Ads config.json uses platform OAuth. The integration now reads the platform OAuth credentials.access_token from context.auth and builds the Google Ads SDK client from that access token. ADWORDS_DEVELOPER_TOKEN remains server-side API configuration, not a user auth field. ADWORDS_CLIENT_ID / ADWORDS_CLIENT_SECRET are no longer required by the tests or source import path.
  • Import-time env cleanup: Removed import-time .env loading / required env var reads from google_ads.py, so tests and runtime failures happen at action execution time instead of module import.
  • Full test rewrite: Replaced the single legacy test_google_ads.py with focused unit test modules covering every action in the integration.
  • Modern live integration tests: test_google_ads_integration.py now uses the shared env_credentials + make_context pattern, platform OAuth-shaped ctx.auth, a token extraction recipe, and safe read-only command first.

Test coverage

Module Actions covered
test_google_ads_accounts_unit.py get_accessible_accounts
test_google_ads_campaigns_unit.py retrieve_campaign_metrics, create_campaign, update_campaign, remove_campaign
test_google_ads_ad_groups_unit.py retrieve_ad_group_metrics, create_ad_group, update_ad_group, remove_ad_group
test_google_ads_ads_unit.py retrieve_ad_metrics, create_responsive_search_ad, update_ad, remove_ad
test_google_ads_keywords_unit.py retrieve_keyword_metrics, add_keywords, update_keyword, remove_keyword
test_google_ads_keyword_planner_unit.py generate_keyword_ideas, generate_keyword_historical_metrics, generate_keyword_forecast
test_google_ads_search_terms_unit.py retrieve_search_terms, get_active_ad_urls
test_google_ads_helpers_unit.py add_negative_keywords_to_campaign, add_negative_keywords_to_ad_group
test_google_ads_integration.py Read-only live smoke coverage plus destructive lifecycle tests behind destructive marker

Live test auth requirements

Required for read-only live tests:

  • GOOGLE_ADS_ACCESS_TOKEN — platform OAuth access token
  • ADWORDS_DEVELOPER_TOKEN — Google Ads API developer token
  • GOOGLE_ADS_LOGIN_CUSTOMER_ID — manager/MCC account ID without dashes
  • GOOGLE_ADS_CUSTOMER_ID — customer account ID without dashes

Optional for destructive tests:

  • GOOGLE_ADS_TEST_CAMPAIGN_ID
  • GOOGLE_ADS_TEST_AD_GROUP_ID

Safe read-only command:

pytest google-ads/tests/test_google_ads_integration.py -m "integration and not destructive"

Destructive command, only for safe test accounts:

pytest google-ads/tests/test_google_ads_integration.py -m "integration and destructive"

Test plan

  • python -m pytest google-ads/tests -m unit -q — 149 passed
  • python -m pytest google-ads/tests/test_google_ads_integration.py -m "integration and not destructive" -q — 17 skipped without live credentials, 5 destructive deselected
  • python -m pytest google-ads/ -q — 149 passed
  • python ../autohive-integrations-tooling/scripts/validate_integration.py google-ads — passed with one existing scope warning for https://www.googleapis.com/auth/adwords
  • python ../autohive-integrations-tooling/scripts/check_code.py google-ads — passed

…unit + integration coverage (#)

- Bump autohive-integrations-sdk to 2.0.0 in requirements.txt
- Update google_ads.py: fix ValidationError in retrieve_campaign_metrics,
  align all action handlers with SDK 2.0.0 execute_action return contract
  (IntegrationResult with .type / .result.data / .result.message)
- Replace single monolithic test file with 9 focused test modules:
    test_google_ads_accounts_unit.py
    test_google_ads_campaigns_unit.py
    test_google_ads_ad_groups_unit.py
    test_google_ads_ads_unit.py
    test_google_ads_keywords_unit.py
    test_google_ads_keyword_planner_unit.py
    test_google_ads_search_terms_unit.py
    test_google_ads_helpers_unit.py
    test_google_ads_integration.py  (live, skipped in CI)
- 149 unit tests, all passing
- Integration test fixture uses GOOGLE_ADS_ACCESS_TOKEN directly
  (no refresh token needed), mirroring the google-sheets SDK v2 pattern
- Add run_live_readonly.py standalone script for quick manual smoke tests
- Remove legacy tests/context.py and tests/test_google_ads.py
@Shubhank-Jonnada
Copy link
Copy Markdown
Contributor Author

Shubhank-Jonnada commented May 5, 2026

Why we couldn't live-test all actions

We attempted live integration tests against the real Google Ads API using a short-lived access token. The token authenticated successfully, but the developer token is currently approved for test accounts only (DEVELOPER_TOKEN_NOT_APPROVED) — a Google Ads API access tier restriction, not a code issue.

What passed live:

  • retrieve_campaign_metrics — returned real data successfully

What was blocked by the API (not code):

  • get_accessible_accountsPERMISSION_DENIED
  • retrieve_ad_group_metricsPERMISSION_DENIED
  • retrieve_ad_metricsPERMISSION_DENIED
  • retrieve_search_termsPERMISSION_DENIED
  • get_active_ad_urlsPERMISSION_DENIED
  • generate_keyword_ideasPERMISSION_DENIED
  • generate_keyword_historical_metricsPERMISSION_DENIED

What covers the gap:
All 17 actions have thorough unit tests with mocked Google Ads client responses covering happy paths, auth errors, missing required fields, API exceptions, and edge cases — 149 tests, all passing. The integration test file is fully wired and ready once the developer token is upgraded to Basic or Standard access via the Google Ads API Center.

How to run live tests once the developer token is approved
export GOOGLE_ADS_ACCESS_TOKEN="ya29.a0..."
export ADWORDS_DEVELOPER_TOKEN="<token>"
export GOOGLE_ADS_LOGIN_CUSTOMER_ID="<mcc_id>"
export GOOGLE_ADS_CUSTOMER_ID="<client_id>"
pytest google-ads/tests/test_google_ads_integration.py -m integration -v

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

🔍 Integration Validation Results

Commit: 0694a3441f2c7779b7db5706eaafcbd1cfb7dc9f · Merge branch 'master' into feat/google-ads-sdk-upgrade-v2
Updated: 2026-05-11T23:20:48Z

Changed directories: google-ads

Check Result
Structure ⚠️ Passed with warnings
Code ✅ Passed
Tests ✅ Passed
README ✅ Passed
Version ✅ Passed
⚠️ Structure Check output
Validating 1 integration(s)...

============================================================
Integration: google-ads
============================================================

Warnings (1):
  ⚠️ Potentially unused scopes (please verify): https://www.googleapis.com/auth/adwords

============================================================
SUMMARY
============================================================
Integrations validated: 1
Total errors: 0
Total warnings: 1

⚠️ Validation passed with warnings - please review
✅ Code Check output

[notice] A new release of pip is available: 26.0.1 -> 26.1.1
[notice] To update, run: pip install --upgrade pip
----------------------------------------
Checking: google-ads
----------------------------------------

📦 Installing dependencies...

🐍 Checking Python syntax...
   ✅ Syntax OK

📥 Checking imports...
   ✅ Imports OK

📄 Checking JSON files...
   ✅ JSON files OK

🔍 Linting with ruff...
   ✅ Lint OK

🎨 Checking formatting with ruff...
   ✅ Formatting OK

🔒 Scanning for security issues with bandit...
   ✅ Security OK

🛡️ Checking dependencies for vulnerabilities with pip-audit...
   ✅ Dependencies OK

🔗 Checking config-code sync...
   ✅ Config-code sync OK

🔄 Checking fetch patterns...
   ✅ Fetch patterns OK

========================================
✅ CODE CHECK PASSED
========================================
✅ Tests Check output

Integration    Tests  Coverage        Status
--------------------------------------------
google-ads   149/149       84%      ✅ Passed
--------------------------------------------
Total        149/149            ✅ All passed

✅ Tests passed: google-ads
✅ README Check output
========================================
✅ README CHECK PASSED
========================================
✅ Version Check output
✅ google-ads: 2.0.0 → 3.0.0 (major bump)

========================================
✅ VERSION CHECK PASSED
========================================

Comment thread google-ads/tests/test_google_ads_integration.py Fixed
Shubhank-Jonnada and others added 5 commits May 6, 2026 10:03
… 2.1.0

- Fix E402 imports in run_live_readonly.py (moved to top)
- Fix E501 long lines in test_google_ads_ad_groups_unit.py and run_live_readonly.py
- Remove unused patch import from test_google_ads_integration.py
- Add nosec B105 to bandit false positives (PASS symbol, placeholder check)
- Run ruff format across all test files
- Bump config.json version 2.0.1 → 2.1.0 (minor: new actions added)
- Refactor _validate_auth_and_inputs -> _validate_auth (auth only)
- Each handler now explicitly accesses inputs["login_customer_id"] and
  inputs["customer_id"] directly, making them visible to the code checker
- Change inputs.get() to inputs[] for all truly required fields per config.json
  (campaign_name, budget_amount_micros, campaign_id, ad_group_name, ad_group_id,
   keywords, criterion_id, ad_id, headlines, descriptions, final_url,
   campaign_ids/ad_group_ids in retrieve_keyword_metrics, date_ranges in
   retrieve_ad_group/ad/search_terms)
- Remove redundant manual validation guards that are now handled by SDK schema
@TheRealAgentK
Copy link
Copy Markdown
Collaborator

Updated this PR with the final SDK2/auth cleanup pass.

What changed:

  • Aligned source and tests with the integration config: Google Ads is platform OAuth, so tests now use GOOGLE_ADS_ACCESS_TOKEN and platform-shaped ctx.auth (auth_type: PlatformOauth2, credentials.access_token).
  • Kept ADWORDS_DEVELOPER_TOKEN as Google Ads API/server-side config, not as user auth.
  • Removed import-time env var failures from google_ads.py; auth/config errors now happen during action execution.
  • Modernized the live integration test harness around the shared env_credentials + make_context pattern and documented the safe read-only command first.
  • Removed the now-unused python-dotenv dependency.

Validation run locally:

  • python -m pytest google-ads/tests -m unit -q — 149 passed
  • python -m pytest google-ads/tests/test_google_ads_integration.py -m "integration and not destructive" -q — skipped without live creds, destructive tests deselected
  • python -m pytest google-ads/ -q — 149 passed
  • validate_integration.py google-ads — passed with the existing Google Ads scope warning
  • check_code.py google-ads — passed

Copy link
Copy Markdown
Collaborator

@TheRealAgentK TheRealAgentK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-approved to remove the block, needs 3rd party review and then e-2-e test runs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants