You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
требует особого testing pattern (draft campaign tree) и не может быть проверена тем же способом, что standalone-ресурсы;
принципиально не автоматизируется (ads moderate, suspend/resume на активных кампаниях).
Перед закрытием milestone 0.3.0 и заявлением о 100% coverage нужен структурный план: что покрываем через live-тесты на disposable draft, что требует других подходов, а что честно оставляем manual-only.
создаётся через campaigns add с --start-date в будущем;
Status=DRAFT, State=OFF;
не обслуживает трафик, не тратит деньги, не попадает в аукцион;
можно удалить без последствий (campaigns delete).
Ограничения черновика:
пока Status=DRAFT — suspend/resume меняют State внутри уже активной кампании, поэтому на DRAFT вернут валидную ошибку или no-op (это смоук-тест payload, не lifecycle-тест);
archive/unarchive логически применимы к любой кампании, но архивация draft бессмысленна;
ads moderate существует только для объявлений и отправляет их в модерацию — односторонняя операция, автоматизировать нельзя;
установка bids на черновом keyword безопасна (не вступает в силу до активации), это хороший смоук-тест.
Disposable draft pattern (из tests/test_integration_live_write.py)
create draft campaign (Status=DRAFT, State=OFF, start-date in future)
→ create nested resource inside draft (adgroup/ad/keyword/...)
→ verify CLI round-trip
→ delete nested (optional, cascade by campaign delete)
→ delete campaign (cascade cleanup)
finally:
ensure campaign is deleted even on test failure
Обязательные правила для всех live-тестов (уже соблюдаются в PR #57 для root-фикстуры):
требовать YANDEX_DIRECT_LIVE_WRITE=1;
принимать только свои собственные созданные ID;
cleanup в finally;
никогда не вызывать moderate;
никогда не трогать существующие кампании пользователя.
Категория 1: МОЖНО через disposable draft
1.1 Standalone assets (не требуют draft campaign вообще)
1.3 Smoke-тесты на draft: suspend/resume и аналоги
На draft suspend/resume меняют State — ожидаем либо валидную ошибку "cannot change state in DRAFT", либо no-op. Оба исхода подтверждают что CLI правильно собирает payload.
keywords suspend/resume
audiencetargets suspend/resume
dynamicads suspend/resume
smartadtargets suspend/resume
ads suspend/resume/archive/unarchive на draft ad
Это не lifecycle-покрытие, а регрессионный guard CLI-payload. Заявлять о полном покрытии suspend/resume flow нельзя — нужна отдельная ручная проверка.
Категория 2: НЕЛЬЗЯ через draft
2.1 Односторонние операции (нельзя откатить)
Команда
Почему нельзя на draft
Альтернатива
ads moderate
Отправляет в модерацию → Status=MODERATION → может уйти в ACCEPTED и начать показы. Без удаления объявления отката нет.
Ручная проверка на тестовой кампании, которую потом удалить. Никогда не автоматизировать.
2.2 Требуют активной кампании (не draft)
suspend/resume на объектах со статусом ACCEPTED меняют live traffic. На draft возвращают ошибку (это в категории 1.3). Полноценный lifecycle — только ручная проверка.
Команда
Проблема
Подход
campaigns suspend on ACCEPTED
меняет live traffic
manual
campaigns resume on SUSPENDED
то же
manual
ads suspend on ACCEPTED
меняет показы
manual
ads resume on SUSPENDED
то же
manual
ads archive on ACCEPTED
меняет доступность
manual
ads unarchive on archived
то же
manual
2.3 Тратят деньги на существующих объектах
Правило: никогда не передавать в live-тест ID существующего keyword/campaign/ad пользователя. На disposable draft keyword все set-bids безопасны (категория 1.2).
Команды с риском при применении к чужим ID:
bids set --keyword-id <existing>
keywordbids set --keyword-id <existing>
bidmodifiers set --modifier-id <existing>
dynamicads set-bids --target-id <existing>
audiencetargets set-bids --target-id <existing>
smartadtargets set-bids --target-id <existing>
2.4 Требуют агентский контекст
agencyclients * работает только для агентских аккаунтов (без агентства — 403).
Команда
Риск
Подход
agencyclients get
безопасно (read-only)
add TestReadOnlyAgencyClients с graceful skip если 403
agencyclients add
создаёт нового клиента под агентством
manual
agencyclients update
меняет контакты клиента
manual
agencyclients delete
удаляет клиента
manual
agencyclients add-passport-organization
связывает паспортную организацию, двусторонняя операция
direct_cli/commands/strategies.py, direct_cli/commands/dynamicfeedadtargets.py, direct_cli/cli.py, unit + integration tests
7
tests/MANUAL_COVERAGE.md (новый)
Риски
Деньги: draft кампании не тратят бюджет, но ошибка (случайный existing ID) — деньги пользователя. Все fixtures принимают только созданные в своём run ID.
Rate limits: много кассет в rewrite-режиме могут исчерпать лимиты. Записывать порциями (--record-mode=rewrite -k <selected>).
Cleanup failure: если finally не сработал — остаётся draft campaign. Периодический ручной sweep через campaigns get --limit 100 + удаление всех с префиксом direct-cli-live-test-*.
Открытые вопросы
Scope первого PR: одним большим PR от Фазы 1 до Фазы 5 или дробить? Рекомендация: дробить — каждая фаза самодостаточна.
Conftest для live-fixtures: отдельный tests/live_conftest.py или inline в test_integration_live_write.py? Рекомендация: inline до > 6 тестов, потом вынести.
Агентский аккаунт: есть ли тестовый агентский аккаунт для Фазы 1 пункта TestReadOnlyAgencyClients? Без него — всегда skip.
Проблема
CLI содержит 29 модулей команд, но реальное покрытие тестами неравномерное. Часть команд:
leads,turbopages,businesses,advideos,agencyclients);ads moderate,suspend/resumeна активных кампаниях).Перед закрытием milestone 0.3.0 и заявлением о 100% coverage нужен структурный план: что покрываем через live-тесты на disposable draft, что требует других подходов, а что честно оставляем manual-only.
Что такое "черновик" (draft) в Яндекс.Директ
Из WSDL (
tests/wsdl_cache/campaigns.xml,tests/wsdl_cache/ads.xml):DRAFT,MODERATION,ACCEPTED,REJECTEDOFF,ON,SUSPENDED,CONVERTEDDRAFT,MODERATION,PREACCEPTED,ACCEPTED,REJECTEDDraft campaign (как в PR #57):
campaigns addс--start-dateв будущем;Status=DRAFT,State=OFF;campaigns delete).Ограничения черновика:
Status=DRAFT—suspend/resumeменяют State внутри уже активной кампании, поэтому на DRAFT вернут валидную ошибку или no-op (это смоук-тест payload, не lifecycle-тест);archive/unarchiveлогически применимы к любой кампании, но архивация draft бессмысленна;ads moderateсуществует только для объявлений и отправляет их в модерацию — односторонняя операция, автоматизировать нельзя;Disposable draft pattern (из
tests/test_integration_live_write.py)Обязательные правила для всех live-тестов (уже соблюдаются в PR #57 для root-фикстуры):
YANDEX_DIRECT_LIVE_WRITE=1;finally;moderate;Категория 1: МОЖНО через disposable draft
1.1 Standalone assets (не требуют draft campaign вообще)
sitelinks add/get/deleteadimages add/get/deletevcards add/get/deleteadextensions add/get/deleteretargeting add/update/deletenegativekeywordsharedsets add/update/deletefeeds add/update/deleteadvideos add/get--urlили--video-datacreatives add --video-id/get1.2 Nested inside draft campaign
Требуют fixture chain:
live_draft_campaign → live_draft_adgroup → live_draft_keyword/ad.adgroups add/update/deleteads add/update/delete(TEXT_AD)keywords add/update/deletekeywords archive/unarchivebids setbids set-autokeywordbids setkeywordbids set-autobidmodifiers add/set/deleteaudiencetargets add/deletedynamicads add/update/deleteDYNAMIC_TEXT_CAMPAIGN+DYNAMIC_TEXT_AD_GROUPsmartadtargets add/update/deleteSMART_CAMPAIGN+SMART_AD_GROUPsmartadtargets set-bidsdynamicads set-bidsaudiencetargets set-bidscampaigns archive/unarchive1.3 Smoke-тесты на draft:
suspend/resumeи аналогиНа draft
suspend/resumeменяют State — ожидаем либо валидную ошибку"cannot change state in DRAFT", либо no-op. Оба исхода подтверждают что CLI правильно собирает payload.keywords suspend/resumeaudiencetargets suspend/resumedynamicads suspend/resumesmartadtargets suspend/resumeads suspend/resume/archive/unarchiveна draft adЭто не lifecycle-покрытие, а регрессионный guard CLI-payload. Заявлять о полном покрытии suspend/resume flow нельзя — нужна отдельная ручная проверка.
Категория 2: НЕЛЬЗЯ через draft
2.1 Односторонние операции (нельзя откатить)
ads moderateStatus=MODERATION→ может уйти вACCEPTEDи начать показы. Без удаления объявления отката нет.2.2 Требуют активной кампании (не draft)
suspend/resumeна объектах со статусомACCEPTEDменяют live traffic. На draft возвращают ошибку (это в категории 1.3). Полноценный lifecycle — только ручная проверка.campaigns suspendon ACCEPTEDcampaigns resumeon SUSPENDEDads suspendon ACCEPTEDads resumeon SUSPENDEDads archiveon ACCEPTEDads unarchiveon archived2.3 Тратят деньги на существующих объектах
Правило: никогда не передавать в live-тест ID существующего keyword/campaign/ad пользователя. На disposable draft keyword все
set-bidsбезопасны (категория 1.2).Команды с риском при применении к чужим ID:
bids set --keyword-id <existing>keywordbids set --keyword-id <existing>bidmodifiers set --modifier-id <existing>dynamicads set-bids --target-id <existing>audiencetargets set-bids --target-id <existing>smartadtargets set-bids --target-id <existing>2.4 Требуют агентский контекст
agencyclients *работает только для агентских аккаунтов (без агентства — 403).agencyclients getTestReadOnlyAgencyClientsс graceful skip если 403agencyclients addagencyclients updateagencyclients deleteagencyclients add-passport-organizationagencyclients add-passport-organization-member --notification2.5 Отсутствуют в CLI (блокирует #54)
strategies add/archive/get/unarchive/updatedynamicfeedadtargets add/delete/get/resume/setBids/suspendРекомендованный порядок работы (по фазам)
Фаза 1 — read-only добор (нулевой риск, можно прямо сейчас)
Добавить в
tests/test_integration.py:TestReadOnlyLeads—leads getс graceful skip если нет campaigns;TestReadOnlyTurbopages—turbopages get;TestReadOnlyBusinesses—businesses get;TestReadOnlyAdVideos—advideos get;TestReadOnlyAgencyClients—agencyclients getс graceful skip если 403.Закрывает гэп "команда написана, но никогда не вызывалась".
Фаза 2 — standalone draft assets (низкий риск)
Расширить
tests/test_integration_live_write.py:TestLiveWriteSitelinksDraft(закрывает категорию A часть test: roadmap for write integration beyond current Yandex sandbox limits #28);TestLiveWriteAdImagesDraft(закрывает категорию A часть test: roadmap for write integration beyond current Yandex sandbox limits #28);TestLiveWriteAdVideosDraft;TestLiveWriteCreativesDraft(chain advideo → creative).Фаза 3 — nested inside draft campaign (категория A из #28)
Базовая fixture chain:
live_draft_campaign → live_draft_adgroup → live_draft_ad/keyword.Классы:
TestLiveWriteAdGroupsDraftTestLiveWriteAdsDraft(add/update/delete; не moderate)TestLiveWriteKeywordsDraftTestLiveWriteBidsDraftTestLiveWriteKeywordBidsDraftTestLiveWriteAudienceTargetsDraftФаза 4 — нестандартные типы кампаний (категория B из #28)
TestLiveWriteDynamicAdsDraftчерезDYNAMIC_TEXT_CAMPAIGNTestLiveWriteSmartAdTargetsDraftчерезSMART_CAMPAIGNФаза 5 — suspend/resume smoke-тесты на draft
Покрыть
ads/keywords/audiencetargets/dynamicads/smartadtargetssuspend/resumeна draft-объектах. Регрессионный guard CLI-payload.Фаза 6 — CLI gap из #54 (новые команды)
Реализовать
strategiesиdynamicfeedadtargetsвdirect_cli/commands/, затем применить Фазы 2–5 к новым командам.Фаза 7 — manual-only, не автоматизировать
Создать
tests/MANUAL_COVERAGE.md:ads moderate— manual;campaigns/ads suspend/resume/archive/unarchiveна существующих объектах — manual;agencyclients add/update/delete+ passport-org operations — manual;bidmodifiers/bids/keywordbids/*_set_bidsна существующих объектах — запрещено.Честный документированный gap.
Файлы по фазам
tests/test_integration.py(+5 классов),tests/cassettes/test_integration/tests/test_integration_live_write.py(+4 класса) + fixtures + cassettestests/test_integration_live_write.py(+6 классов) + chain fixturestests/test_integration_live_write.py(+2 класса)tests/test_integration_live_write.py(+5 smoke classes)direct_cli/commands/strategies.py,direct_cli/commands/dynamicfeedadtargets.py,direct_cli/cli.py, unit + integration teststests/MANUAL_COVERAGE.md(новый)Риски
--record-mode=rewrite -k <selected>).YANDEX_DIRECT_TOKENиYANDEX_DIRECT_LOGIN. Шаблон в PR test: add guarded live-write draft tier and expand coverage audit #57.finallyне сработал — остаётся draft campaign. Периодический ручной sweep черезcampaigns get --limit 100+ удаление всех с префиксомdirect-cli-live-test-*.Открытые вопросы
tests/live_conftest.pyили inline вtest_integration_live_write.py? Рекомендация: inline до > 6 тестов, потом вынести.TestReadOnlyAgencyClients? Без него — всегда skip.Связанные
strategies,dynamicfeedadtargets)🤖 Generated with Claude Code