Skip to content

Commit 19afc7f

Browse files
committed
Create integration tests Block Storage Volume Limit Increase
1 parent 6bd48a3 commit 19afc7f

1 file changed

Lines changed: 162 additions & 0 deletions

File tree

tests/integration/volumes/test_volumes.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json as _json
12
import os
23
import re
34

@@ -6,9 +7,11 @@
67
from linodecli.exit_codes import ExitCodes
78
from tests.integration.helpers import (
89
BASE_CMDS,
10+
delete_target_id,
911
exec_failing_test_command,
1012
exec_test_command,
1113
get_random_text,
14+
wait_for_condition,
1215
)
1316
from tests.integration.volumes.fixtures import volume_instance_id # noqa: F401
1417

@@ -226,3 +229,162 @@ def test_fail_to_update_volume_size(volume_instance_id):
226229
"linode-cli volumes update: error: unrecognized arguments: --size=15"
227230
in result
228231
)
232+
233+
234+
def test_attach_volumes_to_extended_device_slots(linode_cloud_firewall):
235+
num_volumes = 12
236+
device_slots = [
237+
"sda", "sdb", "sdc", "sdd", "sde", "sdf", "sdg", "sdh",
238+
"sdi", "sdj", "sdk", "sdl",
239+
]
240+
regions_data = _json.loads(
241+
exec_test_command(
242+
["linode-cli", "regions", "ls", "--json", "--suppress-warnings"]
243+
)
244+
)
245+
eligible = [
246+
r["id"]
247+
for r in regions_data
248+
if r.get("site_type") == "core"
249+
and "Linodes" in r.get("capabilities", [])
250+
and "Block Storage" in r.get("capabilities", [])
251+
]
252+
assert eligible, "No eligible region found with Linodes and Block Storage"
253+
test_region = eligible[0]
254+
linode_id = exec_test_command(
255+
[
256+
"linode-cli",
257+
"linodes",
258+
"create",
259+
"--type",
260+
"g6-standard-6",
261+
"--region",
262+
test_region,
263+
"--firewall_id",
264+
linode_cloud_firewall,
265+
"--booted",
266+
"true",
267+
"--format",
268+
"id",
269+
"--text",
270+
"--no-headers",
271+
]
272+
)
273+
274+
vol_ids = []
275+
label_base = "vol-ext-" + get_random_text(4)
276+
277+
try:
278+
for i in range(num_volumes):
279+
vol_id = exec_test_command(
280+
BASE_CMDS["volumes"]
281+
+ [
282+
"create",
283+
"--label",
284+
f"{label_base}-{i}",
285+
"--region",
286+
test_region,
287+
"--size",
288+
"10",
289+
"--text",
290+
"--no-headers",
291+
"--format",
292+
"id",
293+
]
294+
)
295+
vol_ids.append(vol_id)
296+
297+
def volume_active(vid=vol_id):
298+
status = exec_test_command(
299+
BASE_CMDS["volumes"]
300+
+ ["view", vid, "--text", "--no-headers", "--format", "status"]
301+
)
302+
return status.strip() == "active"
303+
304+
wait_for_condition(10, 240, volume_active)
305+
306+
configs_result = exec_test_command(
307+
BASE_CMDS["linodes"]
308+
+ ["configs-list", linode_id, "--json", "--suppress-warnings"]
309+
)
310+
configs = _json.loads(configs_result)
311+
assert isinstance(configs, list), "configs-list should return a list"
312+
313+
config_create_result = exec_test_command(
314+
BASE_CMDS["linodes"]
315+
+ [
316+
"config-create",
317+
linode_id,
318+
"--label",
319+
label_base + "-config",
320+
"--devices.sda.volume_id",
321+
vol_ids[0],
322+
"--json",
323+
"--suppress-warnings",
324+
]
325+
)
326+
config_json = _json.loads(config_create_result)[0]
327+
config_id = str(config_json["id"])
328+
329+
view_result = exec_test_command(
330+
BASE_CMDS["linodes"]
331+
+ ["config-view", linode_id, config_id, "--json", "--suppress-warnings"]
332+
)
333+
viewed = _json.loads(view_result)[0]
334+
assert str(viewed["id"]) == config_id, (
335+
"config-view should return the correct config"
336+
)
337+
assert "devices" in viewed, (
338+
"config-view response should include a 'devices' field"
339+
)
340+
341+
for slot, vol_id in zip(device_slots[1:], vol_ids[1:]):
342+
exec_test_command(
343+
BASE_CMDS["linodes"]
344+
+ [
345+
"config-update",
346+
linode_id,
347+
config_id,
348+
f"--devices.{slot}.volume_id",
349+
vol_id,
350+
"--text",
351+
"--no-headers",
352+
]
353+
)
354+
355+
final_config_result = exec_test_command(
356+
BASE_CMDS["linodes"]
357+
+ ["config-view", linode_id, config_id, "--json", "--suppress-warnings"]
358+
)
359+
final_config = _json.loads(final_config_result)[0]
360+
devices = final_config.get("devices", {})
361+
362+
for slot in device_slots:
363+
assert devices.get(slot) is not None, (
364+
f"Extended device slot '{slot}' is unexpectedly empty; "
365+
"the plan-based volume limit may not be applied correctly."
366+
)
367+
368+
populated = [slot for slot in device_slots if devices.get(slot) is not None]
369+
assert len(populated) == num_volumes, (
370+
f"Expected {num_volumes} populated device slots, "
371+
f"got {len(populated)}: {populated}"
372+
)
373+
374+
finally:
375+
for vol_id in vol_ids:
376+
delete_target_id(
377+
target="volumes",
378+
id=vol_id,
379+
use_retry=True,
380+
retries=5,
381+
delay=15,
382+
)
383+
delete_target_id(
384+
target="linodes",
385+
id=linode_id,
386+
use_retry=True,
387+
retries=5,
388+
delay=15,
389+
)
390+

0 commit comments

Comments
 (0)