Skip to content

Commit 5c66b26

Browse files
author
Vladyslav Yurchenko
committed
Smoke testing. Garbage ignorance. No resources conflicts.
1 parent d4ddd9d commit 5c66b26

File tree

2 files changed

+132
-70
lines changed

2 files changed

+132
-70
lines changed

tests/integration/ha_tests/helpers.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,6 @@ async def is_storage_exists(ops_test: OpsTest, storage_id: str) -> bool:
875875
storage_id,
876876
"--format=json",
877877
]
878-
print(f"command: {complete_command}")
879878
return_code, stdout, _ = await ops_test.juju(*complete_command)
880879
if return_code != 0:
881880
if return_code == 1:
@@ -904,7 +903,7 @@ async def create_db(ops_test: OpsTest, app: str, db: str) -> None:
904903

905904

906905
async def check_db(ops_test: OpsTest, app: str, db: str) -> bool:
907-
"""Returns True if database with specified name is already exists."""
906+
"""Returns True if database with specified name already exists."""
908907
unit = ops_test.model.applications[app].units[0]
909908
unit_address = await unit.get_public_address()
910909
password = await get_password(ops_test, app)
@@ -934,14 +933,31 @@ async def get_any_deatached_storage(ops_test: OpsTest) -> str:
934933
if (str(storage["status"]["current"]) == "detached") and (str(storage["life"] == "alive")):
935934
return storage_name
936935

937-
return None
936+
raise Exception("failed to get deatached storage")
938937

939938

940-
async def check_password_auth(ops_test: OpsTest, unit_name) -> bool:
939+
async def check_password_auth(ops_test: OpsTest, unit_name: str) -> bool:
941940
"""Checks if "operator" password is valid for current postgresql db."""
942941
stdout = await run_command_on_unit(
943942
ops_test,
944943
unit_name,
945944
"""grep -E 'password authentication failed for user' /var/snap/charmed-postgresql/common/var/log/postgresql/postgresql*""",
946945
)
947946
return 'password authentication failed for user "operator"' not in stdout
947+
948+
949+
async def remove_unit_force(ops_test: OpsTest, unit_name: str):
950+
"""Removes unit with --force --no-wait."""
951+
app_name = unit_name.split("/")[0]
952+
complete_command = ["remove-unit", f"{unit_name}", "--force", "--no-wait", "--no-prompt"]
953+
return_code, stdout, _ = await ops_test.juju(*complete_command)
954+
if return_code != 0:
955+
raise Exception(
956+
"Expected command %s to succeed instead it failed: %s with code: ",
957+
complete_command,
958+
stdout,
959+
return_code,
960+
)
961+
962+
for unit in ops_test.model.applications[app_name].units:
963+
assert unit != unit_name

tests/integration/ha_tests/test_smoke.py

Lines changed: 112 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -15,67 +15,33 @@
1515
CHARM_SERIES,
1616
get_primary,
1717
)
18+
from ..juju_ import juju_major_version
1819
from .helpers import (
20+
add_unit_with_storage,
1921
check_db,
2022
check_password_auth,
2123
create_db,
2224
get_any_deatached_storage,
2325
is_postgresql_ready,
2426
is_storage_exists,
27+
remove_unit_force,
2528
storage_id,
2629
)
2730

28-
TEST_GARBADGE_STORAGE_NAME = "test_pgdata"
31+
TEST_garbage_STORAGE_NAME = "test_pgdata"
2932
TEST_DATABASE_RELATION_NAME = "test_database"
3033
DUP_APPLICATION_NAME = "postgres-test-dup"
3134

3235
logger = logging.getLogger(__name__)
3336

3437

35-
@pytest.mark.group(1)
36-
@pytest.mark.abort_on_fail
37-
async def test_app_removal(ops_test: OpsTest, charm: str):
38-
"""Test all recoureces is removed after application removal."""
39-
# Deploy the charm.
40-
async with ops_test.fast_forward():
41-
await ops_test.model.deploy(
42-
charm,
43-
application_name=APPLICATION_NAME,
44-
num_units=1,
45-
series=CHARM_SERIES,
46-
config={"profile": "testing"},
47-
)
48-
49-
# Reducing the update status frequency to speed up the triggering of deferred events.
50-
await ops_test.model.set_config({"update-status-hook-interval": "10s"})
51-
52-
await ops_test.model.wait_for_idle(apps=[APPLICATION_NAME], status="active", timeout=1500)
53-
assert ops_test.model.applications[APPLICATION_NAME].units[0].workload_status == "active"
54-
55-
primary_name = await get_primary(
56-
ops_test, ops_test.model.applications[APPLICATION_NAME].units[0].name
57-
)
58-
assert await is_postgresql_ready(ops_test, primary_name)
59-
60-
storage_id_str = storage_id(ops_test, primary_name)
61-
62-
# Check if storage exists after application deployed
63-
assert await is_storage_exists(ops_test, storage_id_str)
64-
65-
await ops_test.model.remove_application(
66-
APPLICATION_NAME, block_until_done=True, destroy_storage=True
67-
)
68-
69-
# Check if storage removed after application removal
70-
assert not await is_storage_exists(ops_test, storage_id_str)
71-
72-
7338
@pytest.mark.group(1)
7439
@pytest.mark.abort_on_fail
7540
async def test_app_force_removal(ops_test: OpsTest, charm: str):
7641
"""Remove unit with force while storage is alive."""
7742
async with ops_test.fast_forward():
7843
# Deploy the charm.
44+
logger.info("deploying charm")
7945
await ops_test.model.deploy(
8046
charm,
8147
application_name=APPLICATION_NAME,
@@ -88,101 +54,181 @@ async def test_app_force_removal(ops_test: OpsTest, charm: str):
8854
# Reducing the update status frequency to speed up the triggering of deferred events.
8955
await ops_test.model.set_config({"update-status-hook-interval": "10s"})
9056

57+
logger.info("waiting for idle")
9158
await ops_test.model.wait_for_idle(apps=[APPLICATION_NAME], status="active", timeout=1500)
9259
assert ops_test.model.applications[APPLICATION_NAME].units[0].workload_status == "active"
9360

61+
logger.info("getting primary")
9462
primary_name = await get_primary(
9563
ops_test, ops_test.model.applications[APPLICATION_NAME].units[0].name
9664
)
97-
assert await is_postgresql_ready(ops_test, primary_name)
9865

66+
logger.info("waiting for postgresql")
67+
for attempt in Retrying(stop=stop_after_delay(15 * 3), wait=wait_fixed(3)):
68+
with attempt:
69+
assert await is_postgresql_ready(ops_test, primary_name)
70+
71+
logger.info("getting storage id")
9972
storage_id_str = storage_id(ops_test, primary_name)
10073

10174
# Check if storage exists after application deployed
102-
assert await is_storage_exists(ops_test, storage_id_str)
75+
logger.info("werifing is storage exists")
76+
for attempt in Retrying(stop=stop_after_delay(15 * 3), wait=wait_fixed(3)):
77+
with attempt:
78+
assert await is_storage_exists(ops_test, storage_id_str)
10379

10480
# Create test database to check there is no resources conflicts
81+
logger.info("creating db")
10582
await create_db(ops_test, APPLICATION_NAME, TEST_DATABASE_RELATION_NAME)
10683

10784
# Destroy charm
108-
await ops_test.model.destroy_unit(
109-
primary_name, force=True, destroy_storage=False, max_wait=1500
110-
)
85+
logger.info("force removing charm")
86+
if juju_major_version == 2:
87+
await remove_unit_force(ops_test, primary_name)
88+
else:
89+
await ops_test.model.destroy_unit(
90+
primary_name, force=True, destroy_storage=False, max_wait=1500
91+
)
11192

11293
# Storage should remain
113-
assert await is_storage_exists(ops_test, storage_id_str)
94+
logger.info("werifing is storage exists")
95+
for attempt in Retrying(stop=stop_after_delay(15 * 3), wait=wait_fixed(3)):
96+
with attempt:
97+
assert await is_storage_exists(ops_test, storage_id_str)
11498

11599

116100
@pytest.mark.group(1)
117101
@pytest.mark.abort_on_fail
118102
async def test_charm_garbage_ignorance(ops_test: OpsTest, charm: str):
119103
"""Test charm deploy in dirty environment with garbage storage."""
120104
async with ops_test.fast_forward():
121-
garbadge_storage = None
105+
logger.info("checking garbage storage")
106+
garbage_storage = None
122107
for attempt in Retrying(stop=stop_after_delay(30 * 3), wait=wait_fixed(3)):
123108
with attempt:
124-
garbadge_storage = await get_any_deatached_storage(ops_test)
125-
assert garbadge_storage is not None
126-
127-
assert garbadge_storage is not None
128-
129-
await ops_test.model.applications[APPLICATION_NAME].add_unit(
130-
1, attach_storage=[tag.storage(garbadge_storage)]
131-
)
109+
garbage_storage = await get_any_deatached_storage(ops_test)
132110

133111
# Reducing the update status frequency to speed up the triggering of deferred events.
134112
await ops_test.model.set_config({"update-status-hook-interval": "10s"})
135113

136-
await ops_test.model.wait_for_idle(apps=[APPLICATION_NAME], status="active", timeout=1500)
137-
assert ops_test.model.applications[APPLICATION_NAME].units[0].workload_status == "active"
114+
logger.info("add unit with attached storage")
115+
await add_unit_with_storage(ops_test, APPLICATION_NAME, garbage_storage)
138116

117+
logger.info("getting primary")
139118
primary_name = await get_primary(
140119
ops_test, ops_test.model.applications[APPLICATION_NAME].units[0].name
141120
)
142-
assert await is_postgresql_ready(ops_test, primary_name)
143121

122+
logger.info("waiting for postgresql")
123+
for attempt in Retrying(stop=stop_after_delay(15 * 3), wait=wait_fixed(3)):
124+
with attempt:
125+
assert await is_postgresql_ready(ops_test, primary_name)
126+
127+
logger.info("getting storage id")
144128
storage_id_str = storage_id(ops_test, primary_name)
145129

130+
assert storage_id_str == garbage_storage
131+
146132
# Check if storage exists after application deployed
147-
assert await is_storage_exists(ops_test, storage_id_str)
133+
logger.info("werifing is storage exists")
134+
for attempt in Retrying(stop=stop_after_delay(15 * 3), wait=wait_fixed(3)):
135+
with attempt:
136+
assert await is_storage_exists(ops_test, storage_id_str)
148137

149138
# Check that test database is not exists for new unit
139+
logger.info("checking db")
150140
assert not await check_db(ops_test, APPLICATION_NAME, TEST_DATABASE_RELATION_NAME)
151141

152-
await ops_test.model.destroy_unit(primary_name, destroy_storage=False, max_wait=1500)
142+
logger.info("removing charm")
143+
await ops_test.model.destroy_unit(primary_name)
153144

154145

155146
@pytest.mark.group(1)
156147
@pytest.mark.abort_on_fail
157-
async def test_app_recoures_conflicts(ops_test: OpsTest, charm: str):
148+
@pytest.mark.skipif(juju_major_version < 3, reason="Requires juju 3 or higher")
149+
async def test_app_resources_conflicts_v3(ops_test: OpsTest, charm: str):
158150
"""Test application deploy in dirty environment with garbage storage from another application."""
159151
async with ops_test.fast_forward():
160-
garbadge_storage = None
152+
logger.info("checking garbage storage")
153+
garbage_storage = None
161154
for attempt in Retrying(stop=stop_after_delay(30 * 3), wait=wait_fixed(3)):
162155
with attempt:
163-
garbadge_storage = await get_any_deatached_storage(ops_test)
164-
assert garbadge_storage is not None
156+
garbage_storage = await get_any_deatached_storage(ops_test)
157+
158+
logger.info("deploying duplicate application with attached storage")
159+
await ops_test.model.deploy(
160+
charm,
161+
application_name=DUP_APPLICATION_NAME,
162+
num_units=1,
163+
series=CHARM_SERIES,
164+
attach_storage=[tag.storage(garbage_storage)],
165+
config={"profile": "testing"},
166+
)
167+
168+
# Reducing the update status frequency to speed up the triggering of deferred events.
169+
await ops_test.model.set_config({"update-status-hook-interval": "10s"})
170+
171+
logger.info("waiting for duplicate application to be blocked")
172+
try:
173+
await ops_test.model.wait_for_idle(
174+
apps=[DUP_APPLICATION_NAME], timeout=1000, status="blocked"
175+
)
176+
except TimeoutError:
177+
logger.info("Application is not in blocked state. Checking logs...")
178+
179+
# Since application have postgresql db in storage from external application it should not be able to connect due to new password
180+
logger.info("checking operator password auth")
181+
assert not await check_password_auth(
182+
ops_test, ops_test.model.applications[DUP_APPLICATION_NAME].units[0].name
183+
)
184+
165185

166-
assert garbadge_storage is not None
186+
@pytest.mark.group(1)
187+
@pytest.mark.abort_on_fail
188+
@pytest.mark.skipif(juju_major_version != 2, reason="Requires juju 2")
189+
async def test_app_resources_conflicts_v2(ops_test: OpsTest, charm: str):
190+
"""Test application deploy in dirty environment with garbage storage from another application."""
191+
async with ops_test.fast_forward():
192+
logger.info("checking garbage storage")
193+
garbage_storage = None
194+
for attempt in Retrying(stop=stop_after_delay(30 * 3), wait=wait_fixed(3)):
195+
with attempt:
196+
garbage_storage = await get_any_deatached_storage(ops_test)
167197

168198
# Deploy duplicaate charm
199+
logger.info("deploying duplicate application")
169200
await ops_test.model.deploy(
170201
charm,
171202
application_name=DUP_APPLICATION_NAME,
172203
num_units=1,
173204
series=CHARM_SERIES,
174205
config={"profile": "testing"},
175-
attach_storage=[tag.storage(garbadge_storage)],
176206
)
177207

208+
# Reducing the update status frequency to speed up the triggering of deferred events.
209+
await ops_test.model.set_config({"update-status-hook-interval": "10s"})
210+
211+
logger.info("force removing charm")
212+
await remove_unit_force(
213+
ops_test, ops_test.model.applications[DUP_APPLICATION_NAME].units[0].name
214+
)
215+
216+
# Add unit with garbage storage
217+
logger.info("adding charm with attached storage")
218+
add_unit_cmd = f"add-unit {DUP_APPLICATION_NAME} --model={ops_test.model.info.name} --attach-storage={garbage_storage}".split()
219+
return_code, _, _ = await ops_test.juju(*add_unit_cmd)
220+
assert return_code == 0, "Failed to add unit with storage"
221+
222+
logger.info("waiting for duplicate application to be blocked")
178223
try:
179224
await ops_test.model.wait_for_idle(
180-
apps=[DUP_APPLICATION_NAME], timeout=500, status="blocked"
225+
apps=[DUP_APPLICATION_NAME], timeout=1000, status="blocked"
181226
)
182227
except TimeoutError:
183228
logger.info("Application is not in blocked state. Checking logs...")
184229

185230
# Since application have postgresql db in storage from external application it should not be able to connect due to new password
231+
logger.info("checking operator password auth")
186232
assert not await check_password_auth(
187233
ops_test, ops_test.model.applications[DUP_APPLICATION_NAME].units[0].name
188234
)

0 commit comments

Comments
 (0)