Skip to content

Commit a3f1351

Browse files
Format, copy changes
1 parent 8916fd7 commit a3f1351

File tree

2 files changed

+219
-28
lines changed

2 files changed

+219
-28
lines changed

shared/python/utils.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,29 +1086,31 @@ def _prompt_for_infrastructure_update(rg_name: str) -> tuple[bool, int | None]:
10861086
"""
10871087
print(f'✅ Infrastructure already exists: {rg_name}\n')
10881088
print('🔄 Infrastructure Update Options:\n')
1089-
print(' This infrastructure notebook can update the existing infrastructure. Updates are additive and will:\n')
1089+
print(' This infrastructure notebook can update the existing infrastructure.')
1090+
print(' Updates are additive and will:')
10901091
print(' • Add new APIs and policy fragments defined in the infrastructure')
10911092
print(' • Update existing infrastructure components to match the template')
10921093
print(' • Preserve manually added samples and configurations\n')
10931094

1094-
print('ℹ️ Choose an option:\n')
1095+
print('ℹ️ Choose an option:')
10951096
print(' 1. Update the existing infrastructure (recommended)')
10961097
print(' 2. Use a different index')
1097-
print(' 3. Exit, then delete the existing resource group separately via the clean-up notebook\n')
1098+
print(' 3. Delete the existing resource group first using the clean-up notebook\n')
10981099

10991100
while True:
11001101
choice = input('\nEnter your choice (1, 2, or 3): ').strip()
11011102

11021103
# Default to option 1 if user just presses Enter
1103-
if choice == '1':
1104+
if choice == '1' or not choice:
11041105
return True, None
11051106
elif choice == '2':
11061107
# Option 2: Prompt for a different index
11071108
while True:
11081109
try:
11091110
new_index_str = input('\nEnter the desired index for the infrastructure: ').strip()
11101111
if not new_index_str:
1111-
return False, None
1112+
print('❌ Please enter a valid index number.')
1113+
continue
11121114

11131115
new_index = int(new_index_str)
11141116
if new_index <= 0:
@@ -1118,7 +1120,7 @@ def _prompt_for_infrastructure_update(rg_name: str) -> tuple[bool, int | None]:
11181120
return False, new_index
11191121
except ValueError:
11201122
print('❌ Please enter a valid integer for the index.')
1121-
elif not choice or choice == '3':
1123+
elif choice == '3':
11221124
return False, None
11231125
else:
11241126
print('❌ Invalid choice. Please enter 1, 2, or 3.')
@@ -1523,7 +1525,6 @@ def cleanup_infra_deployments(deployment: INFRASTRUCTURE, indexes: int | list[in
15231525
print_error(f"❌ Exception during cleanup for {deployment.value}-{task['index']}: {str(e)}")
15241526

15251527
# Final summary
1526-
print()
15271528
if failed_count == 0:
15281529
print_ok(f'All {len(indexes_list)} infrastructure cleanups completed successfully!')
15291530
else:

tests/python/test_utils.py

Lines changed: 211 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,11 +1686,19 @@ def test_query_and_select_infrastructure_no_options(monkeypatch):
16861686
monkeypatch.setattr(nb_helper, '_find_infrastructure_instances', lambda x: [])
16871687
monkeypatch.setattr(utils, 'print_info', lambda *args, **kwargs: None)
16881688
monkeypatch.setattr(utils, 'print_warning', lambda *args, **kwargs: None)
1689-
# Mock input to return empty string (simulating user pressing Enter to exit)
1690-
monkeypatch.setattr('builtins.input', lambda prompt: '')
1689+
monkeypatch.setattr(utils, 'print_success', lambda *args, **kwargs: None)
1690+
1691+
# Mock the infrastructure creation to succeed
1692+
def mock_infrastructure_creation(self, bypass_check=True):
1693+
return True
1694+
1695+
monkeypatch.setattr(utils.InfrastructureNotebookHelper, 'create_infrastructure', mock_infrastructure_creation)
16911696

1697+
# When no infrastructures are available, it should automatically create new infrastructure
16921698
result = nb_helper._query_and_select_infrastructure()
1693-
assert result == (None, None)
1699+
1700+
# Expect it to return the desired infrastructure and None index (since 'test-rg' doesn't match the expected pattern)
1701+
assert result == (INFRASTRUCTURE.SIMPLE_APIM, None)
16941702

16951703
def test_query_and_select_infrastructure_single_option(monkeypatch):
16961704
"""Test _query_and_select_infrastructure with a single available option."""
@@ -1818,30 +1826,212 @@ def mock_infrastructure_creation(self, bypass_check=True):
18181826
result = nb_helper._query_and_select_infrastructure()
18191827
assert result == (INFRASTRUCTURE.SIMPLE_APIM, 2)
18201828

1821-
def test_query_and_select_infrastructure_keyboard_interrupt(monkeypatch):
1822-
"""Test _query_and_select_infrastructure when user presses Ctrl+C."""
1823-
nb_helper = utils.NotebookHelper(
1824-
'test-sample', 'test-rg', 'eastus',
1825-
INFRASTRUCTURE.SIMPLE_APIM, [INFRASTRUCTURE.SIMPLE_APIM]
1826-
)
1829+
1830+
# ------------------------------
1831+
# TESTS FOR _prompt_for_infrastructure_update
1832+
# ------------------------------
1833+
1834+
def test_prompt_for_infrastructure_update_option_1(monkeypatch):
1835+
"""Test _prompt_for_infrastructure_update when user selects option 1 (update)."""
1836+
monkeypatch.setattr('builtins.input', lambda prompt: '1')
18271837

1828-
# Mock single result
1829-
def mock_find_instances(infra):
1830-
return [(INFRASTRUCTURE.SIMPLE_APIM, 1)]
1838+
result = utils._prompt_for_infrastructure_update('test-rg')
1839+
assert result == (True, None)
1840+
1841+
def test_prompt_for_infrastructure_update_option_1_default(monkeypatch):
1842+
"""Test _prompt_for_infrastructure_update when user presses Enter (defaults to option 1)."""
1843+
monkeypatch.setattr('builtins.input', lambda prompt: '')
18311844

1832-
monkeypatch.setattr(nb_helper, '_find_infrastructure_instances', mock_find_instances)
1833-
monkeypatch.setattr(utils, 'print_info', lambda *args, **kwargs: None)
1834-
monkeypatch.setattr(utils, 'print_warning', lambda *args, **kwargs: None)
1835-
monkeypatch.setattr(utils, 'get_infra_rg_name', lambda infra, idx: f'apim-infra-{infra.value}-{idx}')
1845+
result = utils._prompt_for_infrastructure_update('test-rg')
1846+
assert result == (True, None)
1847+
1848+
def test_prompt_for_infrastructure_update_option_2_valid_index(monkeypatch):
1849+
"""Test _prompt_for_infrastructure_update when user selects option 2 with valid index."""
1850+
inputs = iter(['2', '5']) # Option 2, then index 5
1851+
monkeypatch.setattr('builtins.input', lambda prompt: next(inputs))
1852+
1853+
result = utils._prompt_for_infrastructure_update('test-rg')
1854+
assert result == (False, 5)
1855+
1856+
def test_prompt_for_infrastructure_update_option_2_invalid_then_valid_index(monkeypatch):
1857+
"""Test _prompt_for_infrastructure_update when user provides invalid index then valid one."""
1858+
inputs = iter(['2', '', '0', '-1', 'abc', '3']) # Option 2, then empty, zero, negative, non-number, finally valid
1859+
monkeypatch.setattr('builtins.input', lambda prompt: next(inputs))
1860+
1861+
result = utils._prompt_for_infrastructure_update('test-rg')
1862+
assert result == (False, 3)
1863+
1864+
def test_prompt_for_infrastructure_update_option_3(monkeypatch):
1865+
"""Test _prompt_for_infrastructure_update when user selects option 3 (delete first)."""
1866+
monkeypatch.setattr('builtins.input', lambda prompt: '3')
1867+
1868+
result = utils._prompt_for_infrastructure_update('test-rg')
1869+
assert result == (False, None)
1870+
1871+
def test_prompt_for_infrastructure_update_invalid_choice_then_valid(monkeypatch):
1872+
"""Test _prompt_for_infrastructure_update with invalid choice followed by valid choice."""
1873+
inputs = iter(['4', '0', 'invalid', '1']) # Invalid choices, then option 1
1874+
monkeypatch.setattr('builtins.input', lambda prompt: next(inputs))
1875+
1876+
result = utils._prompt_for_infrastructure_update('test-rg')
1877+
assert result == (True, None)
1878+
1879+
1880+
# ------------------------------
1881+
# TESTS FOR InfrastructureNotebookHelper.create_infrastructure WITH INDEX RETRY
1882+
# ------------------------------
1883+
1884+
def test_infrastructure_notebook_helper_create_with_index_retry(monkeypatch):
1885+
"""Test InfrastructureNotebookHelper.create_infrastructure with option 2 (different index) retry."""
1886+
from apimtypes import INFRASTRUCTURE, APIM_SKU
1887+
1888+
helper = utils.InfrastructureNotebookHelper('eastus', INFRASTRUCTURE.SIMPLE_APIM, 1, APIM_SKU.BASICV2)
1889+
1890+
# Mock resource group existence to return True initially
1891+
call_count = 0
1892+
def mock_rg_exists(rg_name):
1893+
nonlocal call_count
1894+
call_count += 1
1895+
# First call (index 1) returns True, second call (index 3) returns False
1896+
return call_count == 1
1897+
1898+
# Mock the prompt to return option 2 with index 3
1899+
monkeypatch.setattr(utils, '_prompt_for_infrastructure_update', lambda rg_name: (False, 3))
1900+
monkeypatch.setattr(utils, 'does_resource_group_exist', mock_rg_exists)
1901+
1902+
# Mock subprocess execution to succeed
1903+
class MockProcess:
1904+
def __init__(self, *args, **kwargs):
1905+
self.returncode = 0
1906+
self.stdout = iter(['Mock deployment output\n', 'Success!\n'])
1907+
1908+
def wait(self):
1909+
pass
1910+
1911+
monkeypatch.setattr('subprocess.Popen', MockProcess)
1912+
monkeypatch.setattr(utils, 'find_project_root', lambda: 'c:\\mock\\root')
1913+
1914+
# Mock print functions to avoid output during testing
1915+
monkeypatch.setattr('builtins.print', lambda *args, **kwargs: None)
1916+
1917+
# Should succeed after retrying with index 3
1918+
result = helper.create_infrastructure()
1919+
assert result is True
1920+
assert helper.index == 3 # Verify index was updated
1921+
1922+
def test_infrastructure_notebook_helper_create_with_recursive_retry(monkeypatch):
1923+
"""Test InfrastructureNotebookHelper.create_infrastructure with multiple recursive retries."""
1924+
from apimtypes import INFRASTRUCTURE, APIM_SKU
1925+
1926+
helper = utils.InfrastructureNotebookHelper('eastus', INFRASTRUCTURE.SIMPLE_APIM, 1, APIM_SKU.BASICV2)
1927+
1928+
# Mock resource group existence for multiple indexes
1929+
rg_checks = {}
1930+
def mock_rg_exists(rg_name):
1931+
# Parse index from resource group name
1932+
if 'simple-apim-1' in rg_name:
1933+
return True # Index 1 exists
1934+
elif 'simple-apim-2' in rg_name:
1935+
return True # Index 2 also exists
1936+
else:
1937+
return False # Index 3 doesn't exist
1938+
1939+
# Mock the prompt to first return index 2, then index 3
1940+
prompt_calls = 0
1941+
def mock_prompt(rg_name):
1942+
nonlocal prompt_calls
1943+
prompt_calls += 1
1944+
if prompt_calls == 1:
1945+
return (False, 2) # First retry with index 2
1946+
else:
1947+
return (False, 3) # Second retry with index 3
1948+
1949+
monkeypatch.setattr(utils, '_prompt_for_infrastructure_update', mock_prompt)
1950+
monkeypatch.setattr(utils, 'does_resource_group_exist', mock_rg_exists)
1951+
1952+
# Mock subprocess execution to succeed
1953+
class MockProcess:
1954+
def __init__(self, *args, **kwargs):
1955+
self.returncode = 0
1956+
self.stdout = iter(['Mock deployment output\n'])
1957+
1958+
def wait(self):
1959+
pass
1960+
1961+
monkeypatch.setattr('subprocess.Popen', MockProcess)
1962+
monkeypatch.setattr(utils, 'find_project_root', lambda: 'c:\\mock\\root')
1963+
monkeypatch.setattr('builtins.print', lambda *args, **kwargs: None)
1964+
1965+
# Should succeed after retrying with index 3
1966+
result = helper.create_infrastructure()
1967+
assert result is True
1968+
assert helper.index == 3 # Verify final index
1969+
1970+
def test_infrastructure_notebook_helper_create_user_cancellation(monkeypatch):
1971+
"""Test InfrastructureNotebookHelper.create_infrastructure when user cancels during retry."""
1972+
from apimtypes import INFRASTRUCTURE, APIM_SKU
1973+
import pytest
1974+
1975+
helper = utils.InfrastructureNotebookHelper('eastus', INFRASTRUCTURE.SIMPLE_APIM, 1, APIM_SKU.BASICV2)
1976+
1977+
# Mock resource group to exist (triggering prompt)
1978+
monkeypatch.setattr(utils, 'does_resource_group_exist', lambda rg_name: True)
1979+
1980+
# Mock the prompt to return cancellation (option 3)
1981+
monkeypatch.setattr(utils, '_prompt_for_infrastructure_update', lambda rg_name: (False, None))
18361982
monkeypatch.setattr('builtins.print', lambda *args, **kwargs: None)
18371983

1838-
# Mock user input to raise KeyboardInterrupt
1839-
def mock_input(prompt):
1984+
# Should raise SystemExit when user cancels
1985+
with pytest.raises(SystemExit) as exc_info:
1986+
helper.create_infrastructure()
1987+
1988+
assert "User cancelled deployment" in str(exc_info.value)
1989+
1990+
def test_infrastructure_notebook_helper_create_keyboard_interrupt_during_prompt(monkeypatch):
1991+
"""Test InfrastructureNotebookHelper.create_infrastructure when KeyboardInterrupt occurs during prompt."""
1992+
from apimtypes import INFRASTRUCTURE, APIM_SKU
1993+
import pytest
1994+
1995+
helper = utils.InfrastructureNotebookHelper('eastus', INFRASTRUCTURE.SIMPLE_APIM, 1, APIM_SKU.BASICV2)
1996+
1997+
# Mock resource group to exist (triggering prompt)
1998+
monkeypatch.setattr(utils, 'does_resource_group_exist', lambda rg_name: True)
1999+
2000+
# Mock the prompt to raise KeyboardInterrupt
2001+
def mock_prompt(rg_name):
18402002
raise KeyboardInterrupt()
1841-
monkeypatch.setattr('builtins.input', mock_input)
18422003

1843-
result = nb_helper._query_and_select_infrastructure()
1844-
assert result == (None, None)
2004+
monkeypatch.setattr(utils, '_prompt_for_infrastructure_update', mock_prompt)
2005+
monkeypatch.setattr('builtins.print', lambda *args, **kwargs: None)
2006+
2007+
# Should raise SystemExit when KeyboardInterrupt occurs
2008+
with pytest.raises(SystemExit) as exc_info:
2009+
helper.create_infrastructure()
2010+
2011+
assert "User cancelled deployment" in str(exc_info.value)
2012+
2013+
def test_infrastructure_notebook_helper_create_eof_error_during_prompt(monkeypatch):
2014+
"""Test InfrastructureNotebookHelper.create_infrastructure when EOFError occurs during prompt."""
2015+
from apimtypes import INFRASTRUCTURE, APIM_SKU
2016+
import pytest
2017+
2018+
helper = utils.InfrastructureNotebookHelper('eastus', INFRASTRUCTURE.SIMPLE_APIM, 1, APIM_SKU.BASICV2)
2019+
2020+
# Mock resource group to exist (triggering prompt)
2021+
monkeypatch.setattr(utils, 'does_resource_group_exist', lambda rg_name: True)
2022+
2023+
# Mock the prompt to raise EOFError
2024+
def mock_prompt(rg_name):
2025+
raise EOFError()
2026+
2027+
monkeypatch.setattr(utils, '_prompt_for_infrastructure_update', mock_prompt)
2028+
monkeypatch.setattr('builtins.print', lambda *args, **kwargs: None)
2029+
2030+
# Should raise SystemExit when EOFError occurs
2031+
with pytest.raises(SystemExit) as exc_info:
2032+
helper.create_infrastructure()
2033+
2034+
assert "User cancelled deployment" in str(exc_info.value)
18452035

18462036
def test_deploy_sample_with_infrastructure_selection(monkeypatch):
18472037
"""Test deploy_sample method with infrastructure selection when original doesn't exist."""

0 commit comments

Comments
 (0)