mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
97 lines
3.7 KiB
Python
97 lines
3.7 KiB
Python
|
|
import pytest
|
||
|
|
import yaml
|
||
|
|
|
||
|
|
from modules.inventory import common as inventory_common
|
||
|
|
from modules.inventory.migrate import migrate_legacy_inventory, normalize_unit
|
||
|
|
|
||
|
|
|
||
|
|
def test_normalize_unit():
|
||
|
|
assert normalize_unit('pound') == 'lb'
|
||
|
|
assert normalize_unit('pounds') == 'lb'
|
||
|
|
assert normalize_unit('lbs') == 'lb'
|
||
|
|
# Already-valid mathjs units pass through unchanged.
|
||
|
|
assert normalize_unit('oz') == 'oz'
|
||
|
|
assert normalize_unit('gallon') == 'gallon'
|
||
|
|
assert normalize_unit(None) is None
|
||
|
|
|
||
|
|
|
||
|
|
def _write_legacy(config, inventories):
|
||
|
|
legacy_file = config.get_directory().parent / 'inventories.yaml'
|
||
|
|
legacy_file.parent.mkdir(parents=True, exist_ok=True)
|
||
|
|
with legacy_file.open('wt') as fh:
|
||
|
|
yaml.dump(dict(version=1, inventories=inventories), fh)
|
||
|
|
return legacy_file
|
||
|
|
|
||
|
|
|
||
|
|
def test_migrate_legacy_yaml(test_inventory_configs):
|
||
|
|
config = test_inventory_configs
|
||
|
|
legacy_file = _write_legacy(config, [
|
||
|
|
dict(name='Food Storage', created_at='2024-01-01', deleted_at=None, items=[
|
||
|
|
dict(id=1, inventory_id=1, brand='Ocean', name='Salt', item_size='25', unit='pound', count='8',
|
||
|
|
category='cooking ingredients', subcategory='salt', expiration_date='2030-01-01'),
|
||
|
|
dict(id=2, inventory_id=1, brand='deleted', name='Old', item_size='1', unit='oz', count='1',
|
||
|
|
deleted_at='2020-01-01'),
|
||
|
|
]),
|
||
|
|
])
|
||
|
|
|
||
|
|
assert migrate_legacy_inventory(config) is True
|
||
|
|
config.import_all()
|
||
|
|
|
||
|
|
inventories = config.all_inventories()
|
||
|
|
assert len(inventories) == 1
|
||
|
|
slug = inventories[0]['slug']
|
||
|
|
inventory = config.get_inventory(slug)
|
||
|
|
assert inventory['name'] == 'Food Storage'
|
||
|
|
assert inventory['type'] == 'food'
|
||
|
|
# The soft-deleted legacy item is dropped.
|
||
|
|
assert len(inventory['items']) == 1
|
||
|
|
item = inventory['items'][0]
|
||
|
|
assert item['name'] == 'Salt'
|
||
|
|
# Legacy pint unit 'pound' is normalized to mathjs 'lb'.
|
||
|
|
assert item['item_size_unit'] == 'lb'
|
||
|
|
|
||
|
|
# The legacy file is retired (renamed) and backed up so it is not migrated again.
|
||
|
|
assert not legacy_file.is_file()
|
||
|
|
assert legacy_file.with_suffix('.yaml.migrated').is_file()
|
||
|
|
|
||
|
|
|
||
|
|
def test_migrate_is_idempotent(test_inventory_configs):
|
||
|
|
config = test_inventory_configs
|
||
|
|
_write_legacy(config, [dict(name='Food', items=[])])
|
||
|
|
assert migrate_legacy_inventory(config) is True
|
||
|
|
config.import_all()
|
||
|
|
# Second run does nothing because per-inventory files now exist.
|
||
|
|
assert migrate_legacy_inventory(config) is False
|
||
|
|
config.import_all()
|
||
|
|
assert len(config.all_inventories()) == 1
|
||
|
|
|
||
|
|
|
||
|
|
def test_migrate_no_legacy_data(test_inventory_configs):
|
||
|
|
config = test_inventory_configs
|
||
|
|
assert migrate_legacy_inventory(config) is False
|
||
|
|
assert config.all_inventories() == []
|
||
|
|
|
||
|
|
|
||
|
|
def test_migrate_dedupes_same_named_inventories(test_inventory_configs):
|
||
|
|
"""Multiple inventories with the same name get distinct slugs (food, food-2, food-3) with no data loss."""
|
||
|
|
config = test_inventory_configs
|
||
|
|
_write_legacy(config, [
|
||
|
|
dict(name='Food', items=[]),
|
||
|
|
dict(name='Food', items=[]),
|
||
|
|
dict(name='Food', items=[]),
|
||
|
|
])
|
||
|
|
assert migrate_legacy_inventory(config) is True
|
||
|
|
config.import_all()
|
||
|
|
slugs = sorted(i['slug'] for i in config.all_inventories())
|
||
|
|
assert slugs == ['food', 'food-2', 'food-3']
|
||
|
|
assert len(config.all_inventories()) == 3 # none dropped
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_import_seeds_defaults_when_empty(test_inventory_configs, async_client):
|
||
|
|
"""A fresh install with no legacy data seeds the default example inventory."""
|
||
|
|
config = test_inventory_configs
|
||
|
|
inventory_common.import_inventories_config()
|
||
|
|
inventories = config.all_inventories()
|
||
|
|
assert any(i['name'] == 'Food Storage' for i in inventories)
|