fix model registration and anouncement. added console panel
This commit is contained in:
@@ -399,7 +399,7 @@ def test_download_shard_uses_huggingface_when_repo_is_assigned(tmp_path, monkeyp
|
||||
progress=False,
|
||||
)
|
||||
|
||||
assert shard_dir == tmp_path / "tiny-llama" / "layers_0-3"
|
||||
assert shard_dir == tmp_path / "tiny-llama"
|
||||
assert calls == [{
|
||||
"repo_id": "org/tiny-llama-shards",
|
||||
"cache_dir": str(tmp_path),
|
||||
@@ -407,6 +407,54 @@ def test_download_shard_uses_huggingface_when_repo_is_assigned(tmp_path, monkeyp
|
||||
}]
|
||||
|
||||
|
||||
def test_download_shard_reuses_model_cache_for_narrower_layer_range(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
):
|
||||
"""A wider cached shard satisfies a later narrower assignment for the same model."""
|
||||
cache_dir = tmp_path / "cache"
|
||||
model_dir = cache_dir / "tiny-llama"
|
||||
model_dir.mkdir(parents=True)
|
||||
(model_dir / "config.json").write_bytes(b"{}")
|
||||
(model_dir / "model-00001-of-00002.safetensors").write_bytes(b"a" * 3)
|
||||
(model_dir / "model-00002-of-00002.safetensors").write_bytes(b"b" * 5)
|
||||
|
||||
def unexpected_urlopen(*args, **kwargs):
|
||||
raise AssertionError("cached files should avoid tracker download")
|
||||
|
||||
def unexpected_snapshot_download(*args, **kwargs):
|
||||
raise AssertionError("cached files should avoid HuggingFace download")
|
||||
|
||||
monkeypatch.setattr(urllib.request, "urlopen", unexpected_urlopen)
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"huggingface_hub",
|
||||
types.SimpleNamespace(snapshot_download=unexpected_snapshot_download),
|
||||
)
|
||||
|
||||
shard_dir = download_shard(
|
||||
"tiny-llama",
|
||||
0,
|
||||
1,
|
||||
cache_dir=cache_dir,
|
||||
hf_repo="org/tiny-llama-shards",
|
||||
model_sources=[{
|
||||
"type": "tracker",
|
||||
"url": "http://tracker/v1/model-files/download?model=tiny-llama",
|
||||
"files": ["config.json", "model-00001-of-00002.safetensors"],
|
||||
"file_sizes": {
|
||||
"config.json": 2,
|
||||
"model-00001-of-00002.safetensors": 3,
|
||||
},
|
||||
}],
|
||||
peers=[{"endpoint": "http://peer", "checksum": "unused"}],
|
||||
progress=False,
|
||||
)
|
||||
|
||||
assert shard_dir == model_dir
|
||||
assert (model_dir / "model-00002-of-00002.safetensors").read_bytes() == b"b" * 5
|
||||
|
||||
|
||||
def test_download_shard_prefers_tracker_model_source_over_huggingface(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
@@ -1329,12 +1377,7 @@ def test_full_startup_sequence(tmp_path):
|
||||
tracker.stop()
|
||||
|
||||
|
||||
def test_second_node_downloads_same_shard_from_peer_without_huggingface(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
capsys,
|
||||
):
|
||||
"""Node A downloads from HF stub; node B downloads same assignment from node A."""
|
||||
def test_preset_model_startup_starts_heartbeat(tmp_path, monkeypatch):
|
||||
import meshnet_node.startup as startup_mod
|
||||
|
||||
monkeypatch.setattr(
|
||||
@@ -1342,6 +1385,53 @@ def test_second_node_downloads_same_shard_from_peer_without_huggingface(
|
||||
"detect_hardware",
|
||||
lambda: {"device": "cpu", "gpu_name": None, "vram_mb": 0},
|
||||
)
|
||||
heartbeat_calls = []
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"_start_heartbeat",
|
||||
lambda *args, **kwargs: heartbeat_calls.append((args, kwargs)),
|
||||
)
|
||||
|
||||
tracker = TrackerServer(model_presets={"stub-model": {"layers_start": 0, "layers_end": 15}})
|
||||
tracker_port = tracker.start()
|
||||
tracker_url = f"http://127.0.0.1:{tracker_port}"
|
||||
try:
|
||||
node = run_startup(
|
||||
tracker_url=tracker_url,
|
||||
model="stub-model",
|
||||
wallet_path=tmp_path / "wallet.json",
|
||||
cache_dir=tmp_path / "shards",
|
||||
)
|
||||
try:
|
||||
assert len(heartbeat_calls) == 1
|
||||
args, kwargs = heartbeat_calls[0]
|
||||
assert args[0] == tracker_url
|
||||
assert args[2]["model"] == "stub-model"
|
||||
assert kwargs["node_ref"] is node
|
||||
finally:
|
||||
node.stop()
|
||||
finally:
|
||||
tracker.stop()
|
||||
|
||||
|
||||
def test_real_model_startup_registers_downloaded_inventory_without_checksum(
|
||||
tmp_path,
|
||||
monkeypatch,
|
||||
capsys,
|
||||
):
|
||||
"""Real model folders are reported as inventory without hashing their contents."""
|
||||
import meshnet_node.startup as startup_mod
|
||||
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"detect_hardware",
|
||||
lambda: {"device": "cpu", "gpu_name": None, "vram_mb": 0},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
startup_mod,
|
||||
"compute_shard_checksum",
|
||||
lambda _path: (_ for _ in ()).throw(AssertionError("real model startup must not hash model files")),
|
||||
)
|
||||
hf_calls = []
|
||||
|
||||
def fake_snapshot_download(repo_id, cache_dir, local_dir):
|
||||
@@ -1365,36 +1455,75 @@ def test_second_node_downloads_same_shard_from_peer_without_huggingface(
|
||||
})
|
||||
tracker_port = tracker.start()
|
||||
tracker_url = f"http://127.0.0.1:{tracker_port}"
|
||||
nodes = []
|
||||
try:
|
||||
node_a = run_startup(
|
||||
node = run_startup(
|
||||
tracker_url=tracker_url,
|
||||
model="tiny-llama",
|
||||
wallet_path=tmp_path / "wallet-a.json",
|
||||
cache_dir=tmp_path / "node-a-shards",
|
||||
wallet_path=tmp_path / "wallet.json",
|
||||
cache_dir=tmp_path / "node-shards",
|
||||
)
|
||||
nodes.append(node_a)
|
||||
assert len(hf_calls) == 1
|
||||
|
||||
node_b = run_startup(
|
||||
tracker_url=tracker_url,
|
||||
model="tiny-llama",
|
||||
wallet_path=tmp_path / "wallet-b.json",
|
||||
cache_dir=tmp_path / "node-b-shards",
|
||||
)
|
||||
nodes.append(node_b)
|
||||
|
||||
assert len(hf_calls) == 1
|
||||
assert (tmp_path / "node-b-shards" / "tiny-llama" / "layers_0-15" / "weights.json").exists()
|
||||
output = capsys.readouterr().out
|
||||
assert "download source: HuggingFace" in output
|
||||
assert "download source: peer" in output
|
||||
finally:
|
||||
for node in reversed(nodes):
|
||||
try:
|
||||
assert len(hf_calls) == 1
|
||||
assert (tmp_path / "node-shards" / "tiny-llama" / "weights.json").exists()
|
||||
output = capsys.readouterr().out
|
||||
assert "Cached at:" in output
|
||||
network_map = _get_json(f"{tracker_url}/v1/network/map")
|
||||
registered = network_map["nodes"][0]
|
||||
assert registered["downloaded_models"] == [{
|
||||
"model": "tiny-llama",
|
||||
"shard_start": 0,
|
||||
"shard_end": 15,
|
||||
"path": str(tmp_path / "node-shards" / "tiny-llama"),
|
||||
"file_count": 1,
|
||||
"total_bytes": (tmp_path / "node-shards" / "tiny-llama" / "weights.json").stat().st_size,
|
||||
"hf_repo": "org/tiny-llama-shards",
|
||||
}]
|
||||
finally:
|
||||
node.stop()
|
||||
finally:
|
||||
tracker.stop()
|
||||
|
||||
|
||||
def test_downloaded_model_inventory_reports_local_model_percentage(tmp_path):
|
||||
import meshnet_node.startup as startup_mod
|
||||
|
||||
model_dir = tmp_path / "models" / "tiny-llama"
|
||||
model_dir.mkdir(parents=True)
|
||||
(model_dir / "config.json").write_bytes(b"{}")
|
||||
(model_dir / "weights-a.safetensors").write_bytes(b"a" * 3)
|
||||
|
||||
inventory = startup_mod._downloaded_model_inventory(
|
||||
"tiny-llama",
|
||||
0,
|
||||
1,
|
||||
model_dir,
|
||||
hf_repo="org/tiny-llama",
|
||||
model_sources=[{
|
||||
"full_files": ["config.json", "weights-a.safetensors", "weights-b.safetensors"],
|
||||
"file_sizes": {
|
||||
"config.json": 2,
|
||||
"weights-a.safetensors": 3,
|
||||
"weights-b.safetensors": 5,
|
||||
},
|
||||
}],
|
||||
)
|
||||
|
||||
assert inventory == [{
|
||||
"model": "tiny-llama",
|
||||
"shard_start": 0,
|
||||
"shard_end": 1,
|
||||
"path": str(model_dir),
|
||||
"file_count": 2,
|
||||
"total_bytes": 5,
|
||||
"hf_repo": "org/tiny-llama",
|
||||
"expected_file_count": 3,
|
||||
"local_expected_file_count": 2,
|
||||
"expected_bytes": 10,
|
||||
"local_expected_bytes": 5,
|
||||
"local_model_percentage": 50.0,
|
||||
}]
|
||||
|
||||
|
||||
def test_network_assign_gap_found_field():
|
||||
"""network/assign sets gap_found=True when a real gap exists, False when fully covered."""
|
||||
import json as _json
|
||||
@@ -1587,6 +1716,30 @@ def test_startup_cpu_fallback(tmp_path, monkeypatch):
|
||||
# --------------------------------------------------- layer detection (US: composite configs)
|
||||
|
||||
|
||||
def test_detect_num_layers_prefers_flattened_local_model_config(tmp_path, monkeypatch):
|
||||
import meshnet_node.startup as startup_mod
|
||||
|
||||
model_dir = tmp_path / "Qwen3.6-35B-A3B"
|
||||
model_dir.mkdir()
|
||||
(model_dir / "config.json").write_text("{}")
|
||||
calls = []
|
||||
|
||||
class AutoConfigStub:
|
||||
@staticmethod
|
||||
def from_pretrained(model_id, cache_dir=None):
|
||||
calls.append({"model_id": model_id, "cache_dir": cache_dir})
|
||||
return types.SimpleNamespace(num_hidden_layers=37)
|
||||
|
||||
monkeypatch.setitem(
|
||||
sys.modules,
|
||||
"transformers",
|
||||
types.SimpleNamespace(AutoConfig=AutoConfigStub),
|
||||
)
|
||||
|
||||
assert startup_mod._detect_num_layers("unsloth/Qwen3.6-35B-A3B", cache_dir=tmp_path) == 37
|
||||
assert calls == [{"model_id": str(model_dir), "cache_dir": None}]
|
||||
|
||||
|
||||
def test_layers_from_config_top_level():
|
||||
from meshnet_node.model_catalog import layers_from_config
|
||||
|
||||
|
||||
Reference in New Issue
Block a user