File size: 2,191 Bytes
071ba6b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
"""Tests for model loading — TRN-01 + TRN-10.

Uses sys.modules injection so tests run without unsloth installed on laptop.
"""
import sys
from unittest.mock import MagicMock, patch
import pytest
from hydra import initialize, compose


# Stub unsloth before any import of train.model_load
if "unsloth" not in sys.modules:
    sys.modules["unsloth"] = MagicMock()


def test_instruct_gate_rejects_non_instruct_variant():
    """TRN-01 gate: non-Instruct base model raises ValueError before any download."""
    with initialize(config_path="../configs", version_base="1.3"):
        cfg = compose(config_name="config", overrides=["model.name=unsloth/Qwen2.5-Coder-1.5B"])
    import importlib
    import train.model_load as m
    importlib.reload(m)
    with pytest.raises(ValueError, match="TRN-01 gate"):
        m.load_model_and_tokenizer(cfg)


def test_load_model_and_tokenizer_signature_smoke():
    """TRN-01: FastLanguageModel called with correct args when mocked."""
    with initialize(config_path="../configs", version_base="1.3"):
        cfg = compose(config_name="config")

    mock_model = MagicMock(name="model")
    mock_tok = MagicMock(name="tok")
    mock_peft_model = MagicMock(name="peft_model")

    flm_mock = sys.modules["unsloth"].FastLanguageModel
    flm_mock.from_pretrained.return_value = (mock_model, mock_tok)
    flm_mock.get_peft_model.return_value = mock_peft_model

    import importlib
    import train.model_load as m
    importlib.reload(m)

    result = m.load_model_and_tokenizer(cfg)

    assert isinstance(result, tuple) and len(result) == 2
    flm_mock.from_pretrained.assert_called_with(
        model_name="unsloth/Qwen2.5-Coder-1.5B-Instruct-bnb-4bit",
        load_in_4bit=True,
        max_seq_length=16384,
        dtype=None,
    )


def test_smoke_config_loads_0_5b():
    """TRN-10: 0.5B smoke config resolves correctly via Hydra."""
    with initialize(config_path="../configs", version_base="1.3"):
        cfg = compose(config_name="config", overrides=["model=qwen_0_5b_smoke"])
    assert cfg.model.name == "unsloth/Qwen2.5-Coder-0.5B-Instruct-bnb-4bit"
    assert cfg.model.max_seq_length == 4096
    assert cfg.model.lora_rank == 8