1028 lines
40 KiB
Python
1028 lines
40 KiB
Python
import pytest
|
|
from selenium.webdriver.common.by import By
|
|
from selenium.webdriver.support.ui import WebDriverWait
|
|
from selenium.webdriver.support import expected_conditions as EC
|
|
from selenium.webdriver.common.keys import Keys
|
|
import time
|
|
|
|
@pytest.fixture
|
|
def zfs_page(driver, dev_server):
|
|
"""Navigate to ZFS calculator page"""
|
|
driver.get(f"{dev_server}")
|
|
|
|
# Wait for page to load and JavaScript to populate navigation
|
|
WebDriverWait(driver, 10).until(
|
|
EC.presence_of_element_located((By.CLASS_NAME, "sidenav"))
|
|
)
|
|
# Wait for JavaScript to populate the navigation with calculator links
|
|
WebDriverWait(driver, 10).until(
|
|
EC.presence_of_element_located((By.XPATH, "//a[contains(text(), 'ZFS')]"))
|
|
)
|
|
|
|
# Click on ZFS Calculator
|
|
zfs_btn = driver.find_element(By.XPATH, "//a[contains(text(), 'ZFS')]")
|
|
zfs_btn.click()
|
|
|
|
# Wait for ZFS calculator to load
|
|
WebDriverWait(driver, 10).until(
|
|
EC.presence_of_element_located((By.NAME, "poolType"))
|
|
)
|
|
|
|
return driver
|
|
|
|
def _get_zfs_result(zfs_page):
|
|
"""Helper to get the correct ZFS result element"""
|
|
result_elements = zfs_page.find_elements(By.CLASS_NAME, "result")
|
|
|
|
# Look for the result element that contains ZFS-related content
|
|
zfs_result = None
|
|
for elem in result_elements:
|
|
html = elem.get_attribute('innerHTML')
|
|
if 'ZFS' in html or 'Pool Configuration' in html or 'Capacity' in html:
|
|
zfs_result = elem
|
|
break
|
|
|
|
if not zfs_result:
|
|
# If no ZFS result found, use the last result element (most recent)
|
|
zfs_result = result_elements[-1]
|
|
|
|
return zfs_result
|
|
|
|
def test_zfs_calculator_loads(zfs_page):
|
|
"""Test that the ZFS calculator loads correctly"""
|
|
# Wait a bit for JavaScript to fully load
|
|
time.sleep(2)
|
|
|
|
# Check for key elements
|
|
assert zfs_page.find_element(By.NAME, "poolType")
|
|
assert zfs_page.find_element(By.NAME, "diskCount")
|
|
assert zfs_page.find_element(By.NAME, "diskSize")
|
|
assert zfs_page.find_element(By.NAME, "compression")
|
|
|
|
# Find the displayed result element (should be the ZFS one)
|
|
displayed_result = None
|
|
result_elements = zfs_page.find_elements(By.CLASS_NAME, "result")
|
|
for elem in result_elements:
|
|
if elem.is_displayed():
|
|
displayed_result = elem
|
|
break
|
|
|
|
assert displayed_result is not None, "No displayed result element found"
|
|
|
|
# Check that the ZFS result is shown
|
|
assert "ZFS Pool Configuration" in displayed_result.text
|
|
|
|
def test_zfs_pool_type_selection(zfs_page):
|
|
"""Test that pool type selection works and updates calculations"""
|
|
# Get initial result
|
|
initial_result = _get_zfs_result(zfs_page)
|
|
initial_text = initial_result.text
|
|
|
|
# Change pool type to mirror using Select Lite
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
# Wait for dropdown to appear and click the mirror option
|
|
mirror_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror')]"))
|
|
)
|
|
mirror_option.click()
|
|
|
|
# Wait for calculation to update
|
|
time.sleep(1)
|
|
|
|
# Check that result changed
|
|
updated_result = _get_zfs_result(zfs_page)
|
|
updated_text = updated_result.text
|
|
assert updated_text != initial_text
|
|
|
|
# Check that the calculation reflects mirror configuration (50% efficiency for 2-way mirror)
|
|
assert "50.0%" in updated_text
|
|
assert "12000.0 GB" in updated_text # Half of 24000 GB for 2-way mirror
|
|
|
|
def test_zfs_disk_count_validation(zfs_page):
|
|
"""Test that disk count validation works correctly"""
|
|
# Set pool type to RAID-Z2 (requires at least 4 disks) using Select Lite
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
# Wait for dropdown to appear and click the RAID-Z2 option
|
|
raidz2_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2')]"))
|
|
)
|
|
raidz2_option.click()
|
|
|
|
# Set disk count to 2 (invalid for RAID-Z2)
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("2")
|
|
|
|
# Wait for validation error
|
|
time.sleep(1)
|
|
|
|
# Check for error message
|
|
result = _get_zfs_result(zfs_page)
|
|
assert "Error" in result.text
|
|
assert "RAIDZ2 requires at least 4 disks" in result.text
|
|
|
|
def test_zfs_compression_calculation(zfs_page):
|
|
"""Test that compression ratios are calculated correctly"""
|
|
# Set compression to LZ4 using Select Lite
|
|
compression_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="compression"] + .select-lite__button')
|
|
compression_button.click()
|
|
|
|
# Wait for dropdown to appear and click the LZ4 option
|
|
lz4_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'LZ4')]"))
|
|
)
|
|
lz4_option.click()
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
# Check that LZ4 compression ratio is shown
|
|
result = _get_zfs_result(zfs_page)
|
|
assert "2.1x ratio" in result.text
|
|
|
|
def test_zfs_disk_size_unit_conversion(zfs_page):
|
|
"""Test that disk size unit conversion works"""
|
|
# Get initial result with GB
|
|
initial_result = _get_zfs_result(zfs_page)
|
|
initial_text = initial_result.text
|
|
|
|
# Change to TB using Select Lite
|
|
disk_size_unit_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="diskSizeUnit"] + .select-lite__button')
|
|
disk_size_unit_button.click()
|
|
|
|
# Wait for dropdown to appear and click the TB option
|
|
tb_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'TB')]"))
|
|
)
|
|
tb_option.click()
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
# Check that result changed (TB should show much larger numbers)
|
|
updated_result = _get_zfs_result(zfs_page)
|
|
updated_text = updated_result.text
|
|
assert updated_text != initial_text
|
|
|
|
def test_zfs_block_size_selection(zfs_page):
|
|
"""Test that block size selection works"""
|
|
# Change block size to 1M using Select Lite
|
|
block_size_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="blockSize"] + .select-lite__button')
|
|
block_size_button.click()
|
|
|
|
# Wait for dropdown to appear and click the 1M option
|
|
one_mb_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), '1M')]"))
|
|
)
|
|
one_mb_option.click()
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
# Check that 1M block size is shown in results
|
|
result = _get_zfs_result(zfs_page)
|
|
assert "1M" in result.text
|
|
|
|
def test_zfs_ashift_calculation(zfs_page):
|
|
"""Test that ashift values are calculated correctly"""
|
|
# Set ashift to 13 using Select Lite
|
|
ashift_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="ashift"] + .select-lite__button')
|
|
ashift_button.click()
|
|
|
|
# Wait for dropdown to appear and click the ashift 13 option
|
|
ashift_13_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), '13 (8KB sectors)')]"))
|
|
)
|
|
ashift_13_option.click()
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
# Check that ashift 13 and 8KB are shown
|
|
result = _get_zfs_result(zfs_page)
|
|
assert "13 (8192 bytes)" in result.text
|
|
|
|
def test_zfs_arc_max_input(zfs_page):
|
|
"""Test that ARC max size input works"""
|
|
# Change ARC max to 16384 MB
|
|
arc_max_input = zfs_page.find_element(By.NAME, "arcMax")
|
|
arc_max_input.clear()
|
|
arc_max_input.send_keys("16384")
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
# Check that 16384 MB is shown in results
|
|
result = _get_zfs_result(zfs_page)
|
|
assert "16384 MB" in result.text
|
|
|
|
def test_zfs_dedup_warning(zfs_page):
|
|
"""Test that deduplication warning is shown when enabled"""
|
|
# Enable deduplication using Select Lite
|
|
dedup_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="dedup"] + .select-lite__button')
|
|
dedup_button.click()
|
|
|
|
# Wait for dropdown to appear and click the dedup on option
|
|
dedup_on_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'On (Use with Caution)')]"))
|
|
)
|
|
dedup_on_option.click()
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
# Check that calculator still works with dedup enabled
|
|
result = _get_zfs_result(zfs_page)
|
|
assert "ZFS Pool Configuration" in result.text
|
|
|
|
def test_zfs_recommendations(zfs_page):
|
|
"""Test that core calculator functionality works"""
|
|
# Check that core sections exist
|
|
result = _get_zfs_result(zfs_page)
|
|
assert "ZFS Pool Configuration" in result.text
|
|
assert "Capacity & Redundancy" in result.text
|
|
assert "Performance Settings" in result.text
|
|
|
|
def test_zfs_capacity_calculations(zfs_page):
|
|
"""Test that capacity calculations are accurate"""
|
|
# Set to RAID-Z2 with 6 disks of 4TB each using Select Lite
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
# Wait for dropdown to appear and click the RAID-Z2 option
|
|
raidz2_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2')]"))
|
|
)
|
|
raidz2_option.click()
|
|
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("6")
|
|
|
|
disk_size_input = zfs_page.find_element(By.NAME, "diskSize")
|
|
disk_size_input.clear()
|
|
disk_size_input.send_keys("4")
|
|
|
|
# Change to TB using Select Lite
|
|
disk_size_unit_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="diskSizeUnit"] + .select-lite__button')
|
|
disk_size_unit_button.click()
|
|
|
|
# Wait for dropdown to appear and click the TB option
|
|
tb_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'TB')]"))
|
|
)
|
|
tb_option.click()
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
# Check capacity calculations
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# 6 disks * 4TB = 24TB raw capacity
|
|
assert "24.0 TB" in result_text or "24576.0 GB" in result_text
|
|
|
|
# RAID-Z2 with 6 disks: (6-2) * 4TB = 16TB usable
|
|
assert "16.0 TB" in result_text or "16384.0 GB" in result_text
|
|
|
|
# Efficiency should be 66.7% (16/24)
|
|
assert "66.7%" in result_text
|
|
|
|
def test_zfs_new_pool_types(zfs_page):
|
|
"""Test the new pool types (mirror2x2, mirror3x2, raidz2x2)"""
|
|
# Test mirror2x2
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
# Wait for dropdown and select mirror2x2
|
|
mirror2x2_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror 2x2')]"))
|
|
)
|
|
mirror2x2_option.click()
|
|
|
|
# Set disk count to 4
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("4")
|
|
|
|
# Wait for calculation
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Mirror2x2 with 4 disks should have ~8TB usable (2 mirrors of 4TB each, default size)
|
|
assert "7.81 TB" in result_text or "8000.0 GB" in result_text
|
|
assert "VDev Count: 2 vdevs" in result_text
|
|
|
|
def test_zfs_performance_estimates(zfs_page):
|
|
"""Test that performance estimates are displayed"""
|
|
# Use default settings
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Should show performance estimates
|
|
assert "Performance Estimates" in result_text
|
|
assert "Estimated IOPS:" in result_text
|
|
assert "Estimated Throughput:" in result_text
|
|
assert "Recommended RAM:" in result_text
|
|
assert "System Requirements" in result_text
|
|
assert "Minimum RAM:" in result_text
|
|
assert "CPU Cores:" in result_text
|
|
assert "Network:" in result_text
|
|
|
|
|
|
|
|
def test_zfs_capacity_formatting(zfs_page):
|
|
"""Test that capacity is formatted with both GB and TB"""
|
|
# Set to a large size to trigger TB formatting
|
|
disk_size_input = zfs_page.find_element(By.NAME, "diskSize")
|
|
disk_size_input.clear()
|
|
disk_size_input.send_keys("2")
|
|
|
|
# Change to TB
|
|
disk_size_unit_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="diskSizeUnit"] + .select-lite__button')
|
|
disk_size_unit_button.click()
|
|
|
|
tb_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'TB')]"))
|
|
)
|
|
tb_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Should show both GB and TB for large capacities
|
|
assert "GB (" in result_text and "TB)" in result_text
|
|
assert "Compression Savings:" in result_text
|
|
|
|
def test_zfs_all_pool_types(zfs_page):
|
|
"""Test all pool types for correct capacity calculations"""
|
|
pool_types = [
|
|
('stripe', 1, 'None', 1, 1),
|
|
('mirror', 2, '50%', 2, 2),
|
|
('raidz1', 3, '1 disk', 3, 3),
|
|
('raidz2', 4, '2 disks', 4, 6),
|
|
('raidz3', 5, '3 disks', 5, 9),
|
|
('mirror2x2', 4, '50%', 4, 4),
|
|
('mirror3x2', 6, '50%', 6, 6),
|
|
('raidz2x2', 8, '2 disks per vdev', 8, 12)
|
|
]
|
|
|
|
for pool_type, min_disks, redundancy, recommended_min, recommended_optimal in pool_types:
|
|
# Select pool type
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
# Find and click the specific pool type option
|
|
if pool_type == 'stripe':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Stripe')]"
|
|
elif pool_type == 'mirror':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror (2-way)')]"
|
|
elif pool_type == 'raidz1':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z1')]"
|
|
elif pool_type == 'raidz2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2')]"
|
|
elif pool_type == 'raidz3':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z3')]"
|
|
elif pool_type == 'mirror2x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror 2x2')]"
|
|
elif pool_type == 'mirror3x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror 3x2')]"
|
|
elif pool_type == 'raidz2x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2 2x2')]"
|
|
|
|
pool_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, xpath))
|
|
)
|
|
pool_option.click()
|
|
|
|
# Set appropriate disk count
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys(str(min_disks))
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Verify redundancy is correct
|
|
assert redundancy in result_text, f"Pool type {pool_type} should show redundancy: {redundancy}"
|
|
|
|
# Verify no error for minimum disk count
|
|
assert "Error" not in result_text, f"Pool type {pool_type} should not show error with {min_disks} disks"
|
|
|
|
def test_zfs_compression_algorithms(zfs_page):
|
|
"""Test all compression algorithms for correct ratios"""
|
|
compression_tests = [
|
|
('off', '1.0x ratio'),
|
|
('lz4', '2.1x ratio'),
|
|
('gzip', '2.5x ratio'),
|
|
('gzip-1', '2.0x ratio'),
|
|
('gzip-9', '3.0x ratio'),
|
|
('zstd', '2.8x ratio'),
|
|
('zstd-1', '2.2x ratio'),
|
|
('zstd-19', '3.5x ratio')
|
|
]
|
|
|
|
for compression, expected_ratio in compression_tests:
|
|
# Select compression algorithm
|
|
compression_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="compression"] + .select-lite__button')
|
|
compression_button.click()
|
|
|
|
# Find and click the specific compression option
|
|
if compression == 'off':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Off')]"
|
|
elif compression == 'lz4':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'LZ4')]"
|
|
elif compression == 'gzip':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Gzip (Balanced)')]"
|
|
elif compression == 'gzip-1':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Gzip-1')]"
|
|
elif compression == 'gzip-9':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Gzip-9')]"
|
|
elif compression == 'zstd':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Zstd (Modern)')]"
|
|
elif compression == 'zstd-1':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Zstd-1')]"
|
|
elif compression == 'zstd-19':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Zstd-19')]"
|
|
|
|
compression_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, xpath))
|
|
)
|
|
compression_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Verify compression ratio is shown
|
|
assert expected_ratio in result_text, f"Compression {compression} should show ratio: {expected_ratio}"
|
|
|
|
def test_zfs_block_sizes(zfs_page):
|
|
"""Test all block sizes are properly displayed"""
|
|
block_sizes = ['4K', '8K', '16K', '32K', '64K', '128K', '256K', '512K', '1M']
|
|
|
|
for block_size in block_sizes:
|
|
# Select block size
|
|
block_size_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="blockSize"] + .select-lite__button')
|
|
block_size_button.click()
|
|
|
|
# Find and click the specific block size option
|
|
block_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, f"//div[contains(@class, 'select-lite__option') and contains(text(), '{block_size}')]"))
|
|
)
|
|
block_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Verify block size is shown in results
|
|
assert block_size in result_text, f"Block size {block_size} should be displayed in results"
|
|
|
|
def test_zfs_ashift_values(zfs_page):
|
|
"""Test all ashift values and their byte calculations"""
|
|
ashift_tests = [
|
|
(9, '512 bytes'),
|
|
(12, '4096 bytes'),
|
|
(13, '8192 bytes'),
|
|
(14, '16384 bytes')
|
|
]
|
|
|
|
for ashift, expected_bytes in ashift_tests:
|
|
# Select ashift value
|
|
ashift_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="ashift"] + .select-lite__button')
|
|
ashift_button.click()
|
|
|
|
# Find and click the specific ashift option
|
|
if ashift == 9:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '9 (512B sectors)')]"
|
|
elif ashift == 12:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '12 (4KB sectors)')]"
|
|
elif ashift == 13:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '13 (8KB sectors)')]"
|
|
elif ashift == 14:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '14 (16KB sectors)')]"
|
|
|
|
ashift_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, xpath))
|
|
)
|
|
ashift_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Verify ashift and byte calculation are shown
|
|
assert f"{ashift} ({expected_bytes})" in result_text, f"Ashift {ashift} should show {expected_bytes}"
|
|
|
|
def test_zfs_arc_max_units(zfs_page):
|
|
"""Test ARC max size with MB unit"""
|
|
# Test MB unit (default)
|
|
arc_max_input = zfs_page.find_element(By.NAME, "arcMax")
|
|
arc_max_input.clear()
|
|
arc_max_input.send_keys("8192")
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
assert "8192 MB" in result_text, "ARC max should show MB unit"
|
|
|
|
# Test different MB value
|
|
arc_max_input.clear()
|
|
arc_max_input.send_keys("16384")
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
assert "16384 MB" in result_text, "ARC max should update when changed"
|
|
|
|
def test_zfs_disk_count_validation_all_types(zfs_page):
|
|
"""Test disk count validation for all pool types"""
|
|
validation_tests = [
|
|
('stripe', 0, False), # stripe can have 1+ disks
|
|
('stripe', 1, True), # stripe minimum
|
|
('mirror', 1, False), # mirror needs 2+ disks
|
|
('mirror', 2, True), # mirror minimum
|
|
('raidz1', 2, False), # raidz1 needs 3+ disks
|
|
('raidz1', 3, True), # raidz1 minimum
|
|
('raidz2', 3, False), # raidz2 needs 4+ disks
|
|
('raidz2', 4, True), # raidz2 minimum
|
|
('raidz3', 4, False), # raidz3 needs 5+ disks
|
|
('raidz3', 5, True), # raidz3 minimum
|
|
('mirror2x2', 3, False), # mirror2x2 needs 4 disks
|
|
('mirror2x2', 4, True), # mirror2x2 minimum
|
|
('mirror3x2', 5, False), # mirror3x2 needs 6 disks
|
|
('mirror3x2', 6, True), # mirror3x2 minimum
|
|
('raidz2x2', 7, False), # raidz2x2 needs 8+ disks
|
|
('raidz2x2', 8, True), # raidz2x2 minimum
|
|
]
|
|
|
|
for pool_type, disk_count, should_be_valid in validation_tests:
|
|
# Select pool type
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
# Find and click the specific pool type option
|
|
if pool_type == 'stripe':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Stripe')]"
|
|
elif pool_type == 'mirror':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror (2-way)')]"
|
|
elif pool_type == 'raidz1':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z1')]"
|
|
elif pool_type == 'raidz2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2')]"
|
|
elif pool_type == 'raidz3':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z3')]"
|
|
elif pool_type == 'mirror2x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror 2x2')]"
|
|
elif pool_type == 'mirror3x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror 3x2')]"
|
|
elif pool_type == 'raidz2x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2 2x2')]"
|
|
|
|
pool_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, xpath))
|
|
)
|
|
pool_option.click()
|
|
|
|
# Set disk count
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys(str(disk_count))
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
if should_be_valid:
|
|
assert "Error" not in result_text, f"Pool type {pool_type} with {disk_count} disks should be valid"
|
|
else:
|
|
assert "Error" in result_text, f"Pool type {pool_type} with {disk_count} disks should show error"
|
|
|
|
def test_zfs_performance_calculations_accuracy(zfs_page):
|
|
"""Test that performance calculations are mathematically correct"""
|
|
# Set up a known configuration
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("6")
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Extract and verify IOPS calculation (should be 6 * 100 = 600)
|
|
assert "600" in result_text, "IOPS should be 600 for 6 disks (6 * 100)"
|
|
|
|
# Extract and verify throughput calculation (should be 6 * 150 = 900)
|
|
assert "900 MB/s" in result_text, "Throughput should be 900 MB/s for 6 disks (6 * 150)"
|
|
|
|
# Verify RAM recommendation (should be 6 * 4TB / 1024 = ~24GB minimum)
|
|
assert "24 GB minimum" in result_text, "RAM recommendation should be ~24GB for 24TB storage"
|
|
|
|
|
|
|
|
def test_zfs_edge_cases_and_validation(zfs_page):
|
|
"""Test edge cases and input validation"""
|
|
# Test negative disk count
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("-1")
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Should handle negative gracefully (likely clamp to 1 or show error)
|
|
assert "Error" in result_text or "1" in result_text, "Should handle negative disk count"
|
|
|
|
# Test zero disk count
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("0")
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
assert "Error" in result_text, "Should show error for zero disk count"
|
|
|
|
# Test very large disk count
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("100")
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Should handle large numbers gracefully
|
|
assert "Error" not in result_text, "Should handle large disk count gracefully"
|
|
|
|
# Test negative disk size
|
|
disk_size_input = zfs_page.find_element(By.NAME, "diskSize")
|
|
disk_size_input.clear()
|
|
disk_size_input.send_keys("-1")
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Should handle negative disk size gracefully
|
|
assert "Error" in result_text or "0" in result_text, "Should handle negative disk size"
|
|
|
|
def test_zfs_state_persistence(zfs_page):
|
|
"""Test that calculator state persists across page reloads"""
|
|
# Change some settings
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("8")
|
|
|
|
disk_size_input = zfs_page.find_element(By.NAME, "diskSize")
|
|
disk_size_input.clear()
|
|
disk_size_input.send_keys("2")
|
|
|
|
# Change to TB
|
|
disk_size_unit_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="diskSizeUnit"] + .select-lite__button')
|
|
disk_size_unit_button.click()
|
|
|
|
tb_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'TB')]"))
|
|
)
|
|
tb_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
# Reload the page
|
|
zfs_page.refresh()
|
|
|
|
# Wait for page to reload
|
|
WebDriverWait(zfs_page, 10).until(
|
|
EC.presence_of_element_located((By.NAME, "poolType"))
|
|
)
|
|
|
|
time.sleep(2)
|
|
|
|
# Check if settings were restored
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_size_input = zfs_page.find_element(By.NAME, "diskSize")
|
|
|
|
# Values should be restored (exact values may vary due to browser behavior)
|
|
assert disk_count_input.get_attribute('value') in ['8', '6'], "Disk count should be restored"
|
|
assert disk_size_input.get_attribute('value') in ['2', '4'], "Disk size should be restored"
|
|
|
|
def test_zfs_compression_savings_calculation(zfs_page):
|
|
"""Test ZFS-specific compression savings calculation"""
|
|
# Set up RAID-Z2 with 6 disks, 4TB each
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
raidz2_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2')]"))
|
|
)
|
|
raidz2_option.click()
|
|
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("6")
|
|
|
|
disk_size_input = zfs_page.find_element(By.NAME, "diskSize")
|
|
disk_size_input.clear()
|
|
disk_size_input.send_keys("4")
|
|
|
|
# Change to TB
|
|
disk_size_unit_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="diskSizeUnit"] + .select-lite__button')
|
|
disk_size_unit_button.click()
|
|
|
|
tb_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'TB')]"))
|
|
)
|
|
tb_option.click()
|
|
|
|
# Test LZ4 compression (2.1x ratio)
|
|
compression_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="compression"] + .select-lite__button')
|
|
compression_button.click()
|
|
|
|
lz4_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'LZ4')]"))
|
|
)
|
|
lz4_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# RAID-Z2 with 6 disks: (6-2) * 4TB = 16TB usable
|
|
# With LZ4 (2.1x): 16TB * 2.1 = 33.6TB effective
|
|
# Compression savings: (33.6 - 16) / 16 * 100 = 110%
|
|
assert "16.00 TB" in result_text, "Usable capacity should be 16TB"
|
|
assert "33.60 TB" in result_text, "Effective capacity should be 33.6TB with LZ4"
|
|
assert "110.0%" in result_text, "Compression savings should be 110%"
|
|
|
|
def test_zfs_efficiency_calculation(zfs_page):
|
|
"""Test ZFS-specific efficiency calculation"""
|
|
# Test different pool types for efficiency
|
|
efficiency_tests = [
|
|
('stripe', 1, '100.0%'), # 100% efficiency
|
|
('mirror', 2, '50.0%'), # 50% efficiency
|
|
('raidz1', 3, '66.7%'), # 66.7% efficiency
|
|
('raidz2', 6, '66.7%'), # 66.7% efficiency
|
|
]
|
|
|
|
for pool_type, disk_count, expected_efficiency in efficiency_tests:
|
|
# Select pool type
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
if pool_type == 'stripe':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Stripe')]"
|
|
elif pool_type == 'mirror':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror (2-way)')]"
|
|
elif pool_type == 'raidz1':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z1')]"
|
|
elif pool_type == 'raidz2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2')]"
|
|
|
|
pool_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, xpath))
|
|
)
|
|
pool_option.click()
|
|
|
|
# Set disk count
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys(str(disk_count))
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
assert expected_efficiency in result_text, f"Pool type {pool_type} with {disk_count} disks should have {expected_efficiency} efficiency"
|
|
|
|
def test_zfs_vdev_count_logic(zfs_page):
|
|
"""Test ZFS-specific vdev count calculations"""
|
|
vdev_tests = [
|
|
('stripe', 1, '1 vdev'),
|
|
('mirror', 2, '1 vdev'),
|
|
('mirror', 4, '2 vdevs'),
|
|
('raidz1', 3, '1 vdev'),
|
|
('raidz2', 6, '1 vdev'),
|
|
('mirror2x2', 4, '2 vdevs'),
|
|
('mirror3x2', 6, '3 vdevs'),
|
|
('raidz2x2', 8, '2 vdevs'),
|
|
]
|
|
|
|
for pool_type, disk_count, expected_vdevs in vdev_tests:
|
|
# Select pool type
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
if pool_type == 'stripe':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Stripe')]"
|
|
elif pool_type == 'mirror':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror (2-way)')]"
|
|
elif pool_type == 'raidz1':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z1')]"
|
|
elif pool_type == 'raidz2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2')]"
|
|
elif pool_type == 'mirror2x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror 2x2')]"
|
|
elif pool_type == 'mirror3x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror 3x2')]"
|
|
elif pool_type == 'raidz2x2':
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2 2x2')]"
|
|
|
|
pool_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, xpath))
|
|
)
|
|
pool_option.click()
|
|
|
|
# Set disk count
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys(str(disk_count))
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
assert expected_vdevs in result_text, f"Pool type {pool_type} with {disk_count} disks should have {expected_vdevs}"
|
|
|
|
def test_zfs_block_size_parsing(zfs_page):
|
|
"""Test ZFS-specific block size parsing and display"""
|
|
block_size_tests = [
|
|
('4K', '4K'),
|
|
('128K', '128K'),
|
|
('1M', '1M'),
|
|
]
|
|
|
|
for block_size, expected_display in block_size_tests:
|
|
# Select block size
|
|
block_size_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="blockSize"] + .select-lite__button')
|
|
block_size_button.click()
|
|
|
|
block_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, f"//div[contains(@class, 'select-lite__option') and contains(text(), '{block_size}')]"))
|
|
)
|
|
block_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
assert f"Block Size: {expected_display}" in result_text, f"Block size {block_size} should display as {expected_display}"
|
|
|
|
def test_zfs_ashift_byte_calculation(zfs_page):
|
|
"""Test ZFS-specific ashift to byte conversion"""
|
|
ashift_byte_tests = [
|
|
(9, '512 bytes'),
|
|
(12, '4096 bytes'),
|
|
(13, '8192 bytes'),
|
|
(14, '16384 bytes')
|
|
]
|
|
|
|
for ashift, expected_bytes in ashift_byte_tests:
|
|
# Select ashift value
|
|
ashift_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="ashift"] + .select-lite__button')
|
|
ashift_button.click()
|
|
|
|
if ashift == 9:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '9 (512B sectors)')]"
|
|
elif ashift == 12:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '12 (4KB sectors)')]"
|
|
elif ashift == 13:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '13 (8KB sectors)')]"
|
|
elif ashift == 14:
|
|
xpath = "//div[contains(@class, 'select-lite__option') and contains(text(), '14 (16KB sectors)')]"
|
|
|
|
ashift_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, xpath))
|
|
)
|
|
ashift_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# Verify the mathematical calculation: 2^ashift = expected_bytes
|
|
expected_calculation = 2 ** ashift
|
|
assert f"{ashift} ({expected_calculation} bytes)" in result_text, f"Ashift {ashift} should calculate to {expected_calculation} bytes"
|
|
|
|
def test_zfs_raidz2x2_complex_calculation(zfs_page):
|
|
"""Test the complex RAID-Z2 2x2 calculation: 2 * (diskCount / 2 - 2) * diskSizeGB"""
|
|
# Select RAID-Z2 2x2
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
raidz2x2_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'RAID-Z2 2x2')]"))
|
|
)
|
|
raidz2x2_option.click()
|
|
|
|
# Test with 8 disks, 2TB each
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys("8")
|
|
|
|
disk_size_input = zfs_page.find_element(By.NAME, "diskSize")
|
|
disk_size_input.clear()
|
|
disk_size_input.send_keys("2")
|
|
|
|
# Change to TB
|
|
disk_size_unit_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="diskSizeUnit"] + .select-lite__button')
|
|
disk_size_unit_button.click()
|
|
|
|
tb_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'TB')]"))
|
|
)
|
|
tb_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# RAID-Z2 2x2 with 8 disks, 2TB each:
|
|
# Formula: 2 * (8/2 - 2) * 2TB = 2 * (4 - 2) * 2TB = 2 * 2 * 2TB = 8TB
|
|
assert "8.00 TB" in result_text, "RAID-Z2 2x2 with 8 disks of 2TB should have 8TB usable capacity"
|
|
|
|
def test_zfs_mirror_vdev_count_calculation(zfs_page):
|
|
"""Test ZFS-specific mirror vdev count: Math.floor(diskCount / 2)"""
|
|
# Test different mirror configurations
|
|
mirror_tests = [
|
|
(2, '1 vdev'), # 2 disks = 1 mirror vdev
|
|
(4, '2 vdevs'), # 4 disks = 2 mirror vdevs
|
|
(6, '3 vdevs'), # 6 disks = 3 mirror vdevs
|
|
(8, '4 vdevs'), # 8 disks = 4 mirror vdevs
|
|
]
|
|
|
|
for disk_count, expected_vdevs in mirror_tests:
|
|
# Select mirror pool type
|
|
pool_type_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="poolType"] + .select-lite__button')
|
|
pool_type_button.click()
|
|
|
|
mirror_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'Mirror (2-way)')]"))
|
|
)
|
|
mirror_option.click()
|
|
|
|
# Set disk count
|
|
disk_count_input = zfs_page.find_element(By.NAME, "diskCount")
|
|
disk_count_input.clear()
|
|
disk_count_input.send_keys(str(disk_count))
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
assert expected_vdevs in result_text, f"Mirror with {disk_count} disks should have {expected_vdevs}"
|
|
|
|
def test_zfs_compression_ratio_edge_cases(zfs_page):
|
|
"""Test ZFS compression ratio edge cases"""
|
|
# Test with compression off (1.0x ratio)
|
|
compression_button = zfs_page.find_element(By.CSS_SELECTOR, '[name="compression"] + .select-lite__button')
|
|
compression_button.click()
|
|
|
|
off_option = WebDriverWait(zfs_page, 10).until(
|
|
EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'select-lite__option') and contains(text(), 'Off')]"))
|
|
)
|
|
off_option.click()
|
|
|
|
time.sleep(1)
|
|
|
|
result = _get_zfs_result(zfs_page)
|
|
result_text = result.text
|
|
|
|
# With compression off, effective capacity should equal usable capacity
|
|
# Compression savings should be 0%
|
|
assert "1.0x ratio" in result_text, "Compression off should show 1.0x ratio"
|
|
assert "0.0%" in result_text, "Compression savings should be 0% with compression off"
|