88import time
99import unittest
1010
11- from azure .cli .testsdk import ScenarioTest , ResourceGroupPreparer , live_only
11+ from azure .cli .testsdk import ScenarioTest , ResourceGroupPreparer
1212from azure .cli .testsdk .decorators import serial_test
1313
1414LOCATION = "eastus"
2525
2626# No tidy up of tests required. The resource group is automatically removed
2727#
28- # Cache Tests are failing due issues in the environment, no way to test until fixed re enable when fixed
29- #
3028# As a refactoring consideration for the future, consider use of authoring patterns described here
3129# https://github.com/Azure/azure-cli/blob/dev/doc/authoring_tests.md#sample-5-get-more-from-resourcegrouppreparer
3230#
3331# -----------------------------------------------------------------------------
3432# How to run these tests
3533# -----------------------------------------------------------------------------
36- # All cache tests are decorated with @live_only(), so they are skipped unless
37- # AZURE_TEST_RUN_LIVE is set. `test_create_delete_cache` additionally requires
38- # ANF_ALLOW_INTERACTIVE=1 because it pauses for an engineer to perform two
39- # manual on-prem (CVO) peering steps; it polls cacheState as the sync signal
40- # and prints copy-pasteable commands to STDERR.
34+ # These tests use the standard record/playback model. The cassette files under
35+ # `recordings/` capture the ARM/RP request/response traffic so the tests can
36+ # be replayed in CI without any Azure access or human interaction.
37+ #
38+ # Playback (default, no env vars):
39+ # - No Azure access required.
40+ # - The interactive on-prem (CVO) peering pause is suppressed; the recorded
41+ # cacheState transitions are replayed instantly so the polling loop
42+ # terminates without sleeping.
4143#
42- # IMPORTANT: pass `-s` (a.k.a. `--capture=no`) to pytest so the on-prem
43- # instruction blocks written to stderr are shown in real time. Without `-s`
44- # pytest will buffer the output and you won't see the commands until the test
45- # ends (long after the engineer needed them).
44+ # pytest -vv \
45+ # src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_cache_commands.py
4646#
47- # PowerShell (Windows) - run the full interactive create/delete flow:
47+ # Recording (re-record cassettes against a real subscription):
48+ # - Set AZURE_TEST_RUN_LIVE=True to talk to ARM.
49+ # - For `test_create_delete_cache` ALSO set ANF_ALLOW_INTERACTIVE=1 because
50+ # the test pauses for an engineer to perform two manual on-prem (CVO)
51+ # peering steps; it polls cacheState as the sync signal and prints
52+ # copy-pasteable commands to STDERR. Without ANF_ALLOW_INTERACTIVE the
53+ # interactive test self-skips when running live.
54+ # - Pass `-s` (a.k.a. `--capture=no`) to pytest so the instruction blocks
55+ # written to stderr are shown in real time; otherwise pytest buffers them.
56+ #
57+ # PowerShell (Windows) - re-record the full interactive create/delete flow:
4858#
4959# $env:AZURE_TEST_RUN_LIVE = "True"
5060# $env:ANF_ALLOW_INTERACTIVE = "1"
5161# pytest -s -vv `
5262# src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_cache_commands.py::AzureNetAppFilesCacheServiceScenarioTest::test_create_delete_cache
5363#
54- # PowerShell - run all live cache tests except the interactive one
55- # (leave ANF_ALLOW_INTERACTIVE unset so the interactive test is skipped ):
64+ # PowerShell - re-record all live cache tests except the interactive one
65+ # (leave ANF_ALLOW_INTERACTIVE unset so the interactive test self-skips ):
5666#
5767# $env:AZURE_TEST_RUN_LIVE = "True"
5868# Remove-Item Env:ANF_ALLOW_INTERACTIVE -ErrorAction SilentlyContinue
6575# pytest -s -vv \
6676# src/azure-cli/azure/cli/command_modules/netappfiles/tests/latest/test_cache_commands.py::AzureNetAppFilesCacheServiceScenarioTest::test_create_delete_cache
6777#
68- # Via azdev (also live):
78+ # Via azdev (live re-record ):
6979#
7080# $env:AZURE_TEST_RUN_LIVE = "True"
7181# $env:ANF_ALLOW_INTERACTIVE = "1"
7282# azdev test test_create_delete_cache --live --pytest-args "-s -vv"
7383#
7484# Useful pytest flags:
75- # -s / --capture=no show stderr/stdout live (REQUIRED for the interactive test)
85+ # -s / --capture=no show stderr/stdout live (REQUIRED when recording the
86+ # interactive test)
7687# -vv verbose test names + full assert diffs
7788# -k <expr> filter by test name substring
7889# --log-cli-level=INFO show CLI logging in real time
@@ -148,12 +159,15 @@ def _wait_for_cache_state(self, account_name, pool_name, cache_name, target_stat
148159 last_state = cache .get ('cacheState' ) or cache .get ('properties' , {}).get ('cacheState' )
149160 if last_state in target_states :
150161 return cache
151- if self .is_live or self .in_recording :
162+ if self .in_recording :
163+ # Live or first-time recording: wait between polls.
152164 time .sleep (interval )
153165 else :
154- # In playback we never reach here (test is @live_only), but
155- # avoid a hot loop just in case.
156- break
166+ # Playback: every recorded `cache show` response is consumed
167+ # in order from the cassette. If we have not yet hit a target
168+ # state, advance immediately to consume the next recorded
169+ # response without sleeping.
170+ continue
157171 self .fail ("Timed out after %ds waiting for cacheState in %s; last observed state: %r" %
158172 (timeout , sorted (target_states ), last_state ))
159173
@@ -222,13 +236,18 @@ def _emit_engineer_instructions(passphrases_object, step):
222236 sys .stderr .write (block )
223237 sys .stderr .flush ()
224238
225- @live_only ()
226- @unittest .skipUnless (
227- os .environ .get (INTERACTIVE_ENV_VAR ) == "1" ,
228- "Requires manual on-prem (CVO) peering steps; set %s=1 to run." % INTERACTIVE_ENV_VAR )
229239 @serial_test ()
230240 @ResourceGroupPreparer (name_prefix = 'cli_netappfiles_test_cache_' , additional_tags = {'owner' : 'cli_test' })
231241 def test_create_delete_cache (self ):
242+ # In playback we replay the recorded cassette and never need a human;
243+ # in record/live we require the engineer to opt in to the manual
244+ # on-prem (CVO) peering steps so scheduled live pipelines don't hang
245+ # for up to an hour waiting for human input.
246+ if self .in_recording and os .environ .get (INTERACTIVE_ENV_VAR ) != "1" :
247+ self .skipTest (
248+ "Requires manual on-prem (CVO) peering steps when recording; "
249+ "set %s=1 to run live." % INTERACTIVE_ENV_VAR )
250+
232251 account_name = self .create_random_name (prefix = 'cli-acc-' , length = 24 )
233252 pool_name = self .create_random_name (prefix = 'cli-pool-' , length = 24 )
234253 cache_name = self .create_random_name (prefix = 'cli-cache-' , length = 24 )
@@ -251,15 +270,19 @@ def test_create_delete_cache(self):
251270 "az netappfiles cache list-peering-passphrase -g {rg} -a %s -p %s -c %s" %
252271 (account_name , pool_name , cache_name )).get_output_in_json ()
253272 assert passphrases_object is not None
254- self ._emit_engineer_instructions (passphrases_object , step = "cluster" )
273+ # Only pause for the engineer when actually talking to ARM. In playback
274+ # the recorded responses already reflect the post-peering cache state.
275+ if self .in_recording :
276+ self ._emit_engineer_instructions (passphrases_object , step = "cluster" )
255277
256278 # 3) Engineer pastes the cluster peering command + passphrase on CVO.
257279 # The service advances cacheState to VserverPeeringOfferSent on success.
258280 self ._wait_for_cache_state (account_name , pool_name , cache_name ,
259281 target_states = {"VserverPeeringOfferSent" })
260282
261283 # 4) Surface the vserver peering command for the second on-prem step.
262- self ._emit_engineer_instructions (passphrases_object , step = "vserver" )
284+ if self .in_recording :
285+ self ._emit_engineer_instructions (passphrases_object , step = "vserver" )
263286
264287 # 5) Engineer pastes the vserver peering command on CVO.
265288 # The cache should now drive itself to a terminal state.
@@ -333,7 +356,6 @@ def test_create_delete_cache_with_wait(self):
333356 (account_name , pool_name )).get_output_in_json ()
334357 assert len (cache_list ) == 0
335358
336- @live_only ()
337359 @ResourceGroupPreparer (name_prefix = 'cli_netappfiles_test_cache_' , additional_tags = {'owner' : 'cli_test' })
338360 def test_list_caches (self ):
339361 account_name = self .create_random_name (prefix = 'cli-acc-' , length = 24 )
@@ -375,7 +397,6 @@ def test_list_caches(self):
375397 # - `az netappfiles cache list-peering-passphrase`
376398 # - `az netappfiles cache reset-smb-password`
377399
378- @live_only ()
379400 @ResourceGroupPreparer (name_prefix = 'cli_netappfiles_test_cache_' , additional_tags = {'owner' : 'cli_test' })
380401 def test_cache_pool_change (self ):
381402 account_name = self .create_random_name (prefix = 'cli-acc-' , length = 24 )
0 commit comments