feat(poc): rewind MCP, skill, and recover-ladder docs
Initial PoC: find_protection, tagged checkpoints, FLR, mutating catalog. Lab 10.9 status enums (0=Initializing, 1=MeetingSLA). Credentials stay in gitignored config.json.
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
from zerto_rewind_mcp.protection import find_from_rows, group_vm_rows
|
||||
from zerto_rewind_mcp.status import (
|
||||
BITMAP_SYNC,
|
||||
DELTA_SYNC,
|
||||
INITIAL_SYNC,
|
||||
INITIALIZING,
|
||||
MEETING_SLA,
|
||||
NOT_MEETING_SLA,
|
||||
)
|
||||
|
||||
|
||||
def _row(vm_id, vm_name, vpg_id, vpg_name, status=MEETING_SLA, sub=0):
|
||||
return {
|
||||
"VmIdentifier": vm_id,
|
||||
"VmName": vm_name,
|
||||
"VpgIdentifier": vpg_id,
|
||||
"VpgName": vpg_name,
|
||||
"Status": status,
|
||||
"SubStatus": sub,
|
||||
}
|
||||
|
||||
|
||||
def test_none():
|
||||
result = find_from_rows("web01", [])
|
||||
assert result.outcome == "none"
|
||||
assert "refuse" in result.message.lower()
|
||||
|
||||
|
||||
def test_unique_two_vpgs():
|
||||
rows = [
|
||||
_row("vm-1", "web01", "vpg-local", "local-bu"),
|
||||
_row("vm-1", "web01", "vpg-dr", "dr-remote"),
|
||||
]
|
||||
result = find_from_rows("web01", rows)
|
||||
assert result.outcome == "ok"
|
||||
assert result.vm is not None
|
||||
assert result.vm.vm_identifier == "vm-1"
|
||||
assert len(result.vm.vpgs) == 2
|
||||
assert len(result.taggable_vpgs) == 2
|
||||
|
||||
|
||||
def test_ambiguous_two_vms():
|
||||
rows = [
|
||||
_row("vm-1", "web01", "vpg-a", "a"),
|
||||
_row("vm-2", "web01", "vpg-b", "b"),
|
||||
]
|
||||
result = find_from_rows("web01", rows)
|
||||
assert result.outcome == "ambiguous"
|
||||
assert len(result.matches) == 2
|
||||
assert result.taggable_vpgs == []
|
||||
|
||||
|
||||
def test_skip_syncing_vpg():
|
||||
rows = [
|
||||
_row("vm-1", "app", "vpg-ok", "ok", status=MEETING_SLA, sub=0),
|
||||
_row("vm-1", "app", "vpg-sync", "syncing", status=MEETING_SLA, sub=INITIAL_SYNC),
|
||||
_row("vm-1", "app", "vpg-delta", "delta", status=MEETING_SLA, sub=DELTA_SYNC),
|
||||
_row("vm-1", "app", "vpg-bitmap", "bitmap", status=MEETING_SLA, sub=BITMAP_SYNC),
|
||||
]
|
||||
result = find_from_rows("app", rows)
|
||||
assert result.outcome == "ok"
|
||||
names = {v.vpg_name for v in result.taggable_vpgs}
|
||||
assert names == {"ok"}
|
||||
assert "InitialSync" in result.message
|
||||
|
||||
|
||||
def test_not_meeting_sla_is_taggable():
|
||||
rows = [_row("vm-1", "app", "vpg-a", "a", status=NOT_MEETING_SLA, sub=0)]
|
||||
result = find_from_rows("app", rows)
|
||||
assert result.outcome == "ok"
|
||||
assert len(result.taggable_vpgs) == 1
|
||||
|
||||
|
||||
def test_initializing_not_taggable():
|
||||
rows = [_row("vm-1", "app", "vpg-a", "a", status=INITIALIZING, sub=INITIAL_SYNC)]
|
||||
result = find_from_rows("app", rows)
|
||||
assert result.outcome == "ok"
|
||||
assert result.taggable_vpgs == []
|
||||
assert "refuse" in result.message.lower()
|
||||
|
||||
|
||||
def test_all_syncing_ok_but_no_taggable():
|
||||
rows = [_row("vm-1", "app", "vpg-a", "a", status=MEETING_SLA, sub=INITIAL_SYNC)]
|
||||
result = find_from_rows("app", rows)
|
||||
assert result.outcome == "ok"
|
||||
assert result.taggable_vpgs == []
|
||||
assert "refuse" in result.message.lower()
|
||||
|
||||
|
||||
def test_camel_case_keys():
|
||||
rows = [
|
||||
{
|
||||
"vmIdentifier": "id-9",
|
||||
"vmName": "db01",
|
||||
"vpgIdentifier": "v1",
|
||||
"vpgName": "db-vpg",
|
||||
"status": 1,
|
||||
"subStatus": 0,
|
||||
}
|
||||
]
|
||||
grouped = group_vm_rows(rows)
|
||||
assert grouped[0].vm_name == "db01"
|
||||
assert grouped[0].vpgs[0].can_tag
|
||||
Reference in New Issue
Block a user