592 lines
22 KiB
Python
592 lines
22 KiB
Python
"""Tests for wandb integration.
|
|
|
|
Note: These tests use a set of mocked APIs:
|
|
- _MockWandbAPI: Mocks wandb API calls (ex: wandb.init).
|
|
- _MockWandbLoggingActor: The same as the regular _WandbLoggingActor,
|
|
except using the mocked wandb API
|
|
- WandbTestExperimentLogger: Thin subclass of `WandbLoggerCallback` to use for testing.
|
|
Provides a helper `trial_logging_actors` property that can be used to
|
|
access attributes of the remote actors for assertions.
|
|
- Use the `get_mock_wandb_logger` helper method to create a logger with
|
|
a custom mock wandb API class. (Ex: If you want to override some wandb API methods.)
|
|
|
|
Template for testing with these mocks:
|
|
|
|
wandb_logger_kwargs = {}
|
|
logger = get_mock_wandb_logger(mock_api_cls=_MockWandbAPI, **wandb_logger_kwargs)
|
|
logger.setup()
|
|
|
|
# From now on, the API key is in the env variable.
|
|
# Start the remote logging actor
|
|
logger.on_trial_start(0, [], trial)
|
|
# Log some results
|
|
result = {}
|
|
logger.on_trial_result(0, [], trial, result)
|
|
# Send a STOP signal to the logging actor
|
|
logger.on_trial_complete(0, [], trial)
|
|
# This will wait for the logging actor to finish + cleanup
|
|
logger.on_experiment_end(trials=[trial])
|
|
|
|
# Now, we can access properties of the logging actors
|
|
# (must happen after `on_trial_end` and `on_experiment_end`)
|
|
logger_state = logger.trial_logging_actor_states[trial]
|
|
# logger_state.logs, logger_state.config, logger_state.kwargs, ...
|
|
"""
|
|
|
|
import gc
|
|
import os
|
|
import tempfile
|
|
import time
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
import ray
|
|
from ray.air.integrations.wandb import (
|
|
WANDB_ENV_VAR,
|
|
WANDB_GROUP_ENV_VAR,
|
|
WANDB_POPULATE_RUN_LOCATION_HOOK,
|
|
WANDB_PROJECT_ENV_VAR,
|
|
WANDB_SETUP_API_KEY_HOOK,
|
|
RunDisabled,
|
|
WandbLoggerCallback,
|
|
_QueueItem,
|
|
_WandbLoggingActor,
|
|
setup_wandb,
|
|
)
|
|
from ray.air.tests.mocked_wandb_integration import (
|
|
Trial,
|
|
WandbTestExperimentLogger,
|
|
_MockWandbAPI,
|
|
_MockWandbLoggingActor,
|
|
get_mock_wandb_logger,
|
|
)
|
|
from ray.exceptions import RayActorError
|
|
from ray.tune.execution.placement_groups import PlacementGroupFactory
|
|
|
|
|
|
@pytest.fixture(autouse=True, scope="module")
|
|
def ray_start_2_cpus():
|
|
address_info = ray.init(num_cpus=2)
|
|
yield address_info
|
|
ray.shutdown()
|
|
|
|
|
|
@pytest.fixture
|
|
def trial():
|
|
trial_config = {"par1": 4, "par2": 9.12345678}
|
|
trial = Trial(
|
|
trial_config,
|
|
0,
|
|
"trial_0",
|
|
"trainable",
|
|
PlacementGroupFactory([{"CPU": 1}]),
|
|
"/tmp",
|
|
)
|
|
yield trial
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def wandb_env():
|
|
"""Clean up W&B env var before and after each test.
|
|
|
|
Even if we use monkeypatch in the test, this is useful to remove environment
|
|
variables that are set on the laptop when running tests locally.
|
|
"""
|
|
if WANDB_ENV_VAR in os.environ:
|
|
del os.environ[WANDB_ENV_VAR]
|
|
yield
|
|
if WANDB_ENV_VAR in os.environ:
|
|
del os.environ[WANDB_ENV_VAR]
|
|
|
|
|
|
def fake_wandb_populate_run_location_hook():
|
|
"""Fake user-provided hook to populate W&B environment variables."""
|
|
os.environ[WANDB_PROJECT_ENV_VAR] = "test_project"
|
|
os.environ[WANDB_GROUP_ENV_VAR] = "test_group"
|
|
|
|
|
|
FAKE_WANDB_POPULATE_RUN_LOCATION_HOOK_IMPORT_PATH = (
|
|
"ray.air.tests.test_integration_wandb.fake_wandb_populate_run_location_hook"
|
|
)
|
|
|
|
|
|
class TestWandbLogger:
|
|
def test_wandb_logger_project_group(self, monkeypatch):
|
|
monkeypatch.setenv(WANDB_PROJECT_ENV_VAR, "test_project_from_env_var")
|
|
monkeypatch.setenv(WANDB_GROUP_ENV_VAR, "test_group_from_env_var")
|
|
# Read project and group name from environment variable
|
|
logger = WandbTestExperimentLogger(api_key="1234")
|
|
logger.setup()
|
|
assert logger.project == "test_project_from_env_var"
|
|
assert logger.group == "test_group_from_env_var"
|
|
|
|
def test_wandb_logger_api_key_config(self, monkeypatch):
|
|
# No API key
|
|
with pytest.raises(ValueError):
|
|
logger = WandbTestExperimentLogger(project="test_project")
|
|
logger.setup()
|
|
|
|
# Fetch API key from argument even if external hook and WANDB_ENV_VAR set
|
|
monkeypatch.setenv(
|
|
WANDB_SETUP_API_KEY_HOOK, "ray._private.test_utils.wandb_setup_api_key_hook"
|
|
)
|
|
monkeypatch.setenv(
|
|
WANDB_ENV_VAR,
|
|
"abcde",
|
|
)
|
|
# API Key in config
|
|
logger = WandbTestExperimentLogger(project="test_project", api_key="1234")
|
|
logger.setup()
|
|
assert os.environ[WANDB_ENV_VAR] == "1234"
|
|
|
|
def test_wandb_logger_api_key_file(self, monkeypatch):
|
|
# Fetch API key from file even if external hook and WANDB_ENV_VAR set
|
|
monkeypatch.setenv(
|
|
WANDB_SETUP_API_KEY_HOOK, "ray._private.test_utils.wandb_setup_api_key_hook"
|
|
)
|
|
monkeypatch.setenv(
|
|
WANDB_ENV_VAR,
|
|
"abcde",
|
|
)
|
|
# API Key file
|
|
with tempfile.NamedTemporaryFile("wt") as fp:
|
|
fp.write("5678")
|
|
fp.flush()
|
|
|
|
logger = WandbTestExperimentLogger(
|
|
project="test_project", api_key_file=fp.name
|
|
)
|
|
logger.setup()
|
|
assert os.environ[WANDB_ENV_VAR] == "5678"
|
|
|
|
def test_wandb_logger_api_key_env_var(self, monkeypatch):
|
|
# API Key from env var takes precedence over external hook and
|
|
# logged in W&B API key
|
|
monkeypatch.setenv(
|
|
WANDB_SETUP_API_KEY_HOOK, "ray._private.test_utils.wandb_setup_api_key_hook"
|
|
)
|
|
monkeypatch.setenv(
|
|
WANDB_ENV_VAR,
|
|
"1234",
|
|
)
|
|
mock_wandb = Mock(api=Mock(api_key="efgh"))
|
|
with patch.multiple("ray.air.integrations.wandb", wandb=mock_wandb):
|
|
logger = WandbTestExperimentLogger(project="test_project")
|
|
logger.setup()
|
|
assert os.environ[WANDB_ENV_VAR] == "1234"
|
|
mock_wandb.ensure_configured.assert_not_called()
|
|
|
|
def test_wandb_logger_api_key_external_hook(self, monkeypatch):
|
|
# API Key from external hook if API key not provided through
|
|
# argument or WANDB_ENV_VAR and user not already logged in to W&B
|
|
monkeypatch.setenv(
|
|
WANDB_SETUP_API_KEY_HOOK, "ray._private.test_utils.wandb_setup_api_key_hook"
|
|
)
|
|
|
|
mock_wandb = Mock(api=Mock(api_key=None))
|
|
with patch.multiple("ray.air.integrations.wandb", wandb=mock_wandb):
|
|
logger = WandbTestExperimentLogger(project="test_project")
|
|
logger.setup()
|
|
assert os.environ[WANDB_ENV_VAR] == "abcd"
|
|
mock_wandb.ensure_configured.assert_called_once()
|
|
|
|
mock_wandb = Mock(ensure_configured=Mock(side_effect=AttributeError()))
|
|
with patch.multiple("ray.air.integrations.wandb", wandb=mock_wandb):
|
|
logger = WandbTestExperimentLogger(project="test_project")
|
|
logger.setup()
|
|
assert os.environ[WANDB_ENV_VAR] == "abcd"
|
|
|
|
def test_wandb_logger_api_key_from_wandb_login(self, monkeypatch):
|
|
# No API key should get set if user is already logged in to W&B
|
|
# and they didn't pass API key through argument or env var.
|
|
# External hook should not be called because user already logged
|
|
# in takes precedence.
|
|
monkeypatch.setenv(
|
|
WANDB_SETUP_API_KEY_HOOK, "ray._private.test_utils.wandb_setup_api_key_hook"
|
|
)
|
|
mock_wandb = Mock()
|
|
with patch.multiple("ray.air.integrations.wandb", wandb=mock_wandb):
|
|
logger = WandbTestExperimentLogger(project="test_project")
|
|
logger.setup()
|
|
assert os.environ.get(WANDB_ENV_VAR) is None
|
|
mock_wandb.ensure_configured.assert_called_once()
|
|
|
|
def test_wandb_logger_run_location_external_hook(self, monkeypatch):
|
|
with patch.dict(os.environ):
|
|
# No project
|
|
with pytest.raises(ValueError):
|
|
logger = WandbTestExperimentLogger(api_key="1234")
|
|
logger.setup()
|
|
|
|
# Project and group env vars from external hook
|
|
monkeypatch.setenv(
|
|
WANDB_POPULATE_RUN_LOCATION_HOOK,
|
|
FAKE_WANDB_POPULATE_RUN_LOCATION_HOOK_IMPORT_PATH,
|
|
)
|
|
logger = WandbTestExperimentLogger(api_key="1234")
|
|
logger.setup()
|
|
assert os.environ[WANDB_PROJECT_ENV_VAR] == "test_project"
|
|
assert os.environ[WANDB_GROUP_ENV_VAR] == "test_group"
|
|
|
|
def test_wandb_logger_start(self, monkeypatch, trial):
|
|
monkeypatch.setenv(WANDB_ENV_VAR, "9012")
|
|
# API Key in env
|
|
logger = WandbTestExperimentLogger(project="test_project")
|
|
logger.setup()
|
|
# From now on, the API key is in the env variable.
|
|
logger.log_trial_start(trial)
|
|
logger.log_trial_end(trial)
|
|
logger.on_experiment_end(trials=[trial])
|
|
|
|
logger_state = logger.trial_logging_actor_states[trial]
|
|
assert logger_state.kwargs["project"] == "test_project"
|
|
assert logger_state.kwargs["id"] == trial.trial_id
|
|
assert logger_state.kwargs["name"] == trial.trial_name
|
|
assert logger_state.kwargs["group"] == trial.experiment_dir_name
|
|
assert "config" in logger_state.exclude
|
|
|
|
del logger
|
|
|
|
# log config.
|
|
logger = WandbTestExperimentLogger(project="test_project", log_config=True)
|
|
logger.log_trial_start(trial)
|
|
logger.log_trial_end(trial)
|
|
logger.on_experiment_end(trials=[trial])
|
|
|
|
logger_state = logger.trial_logging_actor_states[trial]
|
|
assert "config" not in logger_state.exclude
|
|
assert "metric" not in logger_state.exclude
|
|
|
|
del logger
|
|
|
|
# Exclude metric.
|
|
logger = WandbTestExperimentLogger(project="test_project", excludes=["metric"])
|
|
logger.log_trial_start(trial)
|
|
logger.log_trial_end(trial)
|
|
logger.on_experiment_end(trials=[trial])
|
|
|
|
logger_state = logger.trial_logging_actor_states[trial]
|
|
assert "config" in logger_state.exclude
|
|
assert "metric" in logger_state.exclude
|
|
|
|
del logger
|
|
|
|
def test_wandb_logger_reporting(self, trial):
|
|
logger = WandbTestExperimentLogger(
|
|
project="test_project", api_key="1234", excludes=["metric2"]
|
|
)
|
|
logger.on_trial_start(0, [], trial)
|
|
r1 = {
|
|
"metric1": 0.8,
|
|
"metric2": 1.4,
|
|
"metric3": np.asarray(32.0),
|
|
"metric4": np.float32(32.0),
|
|
"const": "text",
|
|
"config": trial.config,
|
|
}
|
|
logger.on_trial_result(0, [], trial, r1)
|
|
logger.on_trial_complete(0, [], trial)
|
|
logger.on_experiment_end(trials=[trial])
|
|
logged = logger.trial_logging_actor_states[trial].logs[0]
|
|
assert "metric1" in logged
|
|
assert "metric2" not in logged
|
|
assert "metric3" in logged
|
|
assert "metric4" in logged
|
|
assert "const" not in logged
|
|
assert "config" not in logged
|
|
|
|
def test_wandb_logger_auto_config_keys(self, trial):
|
|
logger = WandbTestExperimentLogger(project="test_project", api_key="1234")
|
|
logger.on_trial_start(iteration=0, trials=[], trial=trial)
|
|
result = {key: 0 for key in WandbLoggerCallback.AUTO_CONFIG_KEYS}
|
|
logger.on_trial_result(0, [], trial, result)
|
|
logger.on_trial_complete(0, [], trial)
|
|
logger.on_experiment_end(trials=[trial])
|
|
config = logger.trial_logging_actor_states[trial].config
|
|
# The results in `AUTO_CONFIG_KEYS` should be saved as training configuration
|
|
# instead of output metrics.
|
|
assert set(WandbLoggerCallback.AUTO_CONFIG_KEYS) < set(config)
|
|
|
|
def test_wandb_logger_exclude_config(self):
|
|
trial = Trial(
|
|
config={"param1": 0, "param2": 0},
|
|
trial_id=0,
|
|
trial_name="trial_0",
|
|
experiment_dir_name="trainable",
|
|
placement_group_factory=PlacementGroupFactory([{"CPU": 1}]),
|
|
local_path=tempfile.gettempdir(),
|
|
)
|
|
logger = WandbTestExperimentLogger(
|
|
project="test_project",
|
|
api_key="1234",
|
|
excludes=(["param2"] + WandbLoggerCallback.AUTO_CONFIG_KEYS),
|
|
)
|
|
logger.on_trial_start(iteration=0, trials=[], trial=trial)
|
|
|
|
# We need to test that `excludes` also applies to `AUTO_CONFIG_KEYS`.
|
|
result = {key: 0 for key in WandbLoggerCallback.AUTO_CONFIG_KEYS}
|
|
logger.on_trial_result(0, [], trial, result)
|
|
logger.on_trial_complete(0, [], trial)
|
|
logger.on_experiment_end(trials=[trial])
|
|
|
|
config = logger.trial_logging_actor_states[trial].config
|
|
assert set(config) == {"param1"}
|
|
|
|
def test_set_serializability_result(self, trial):
|
|
"""Tests that objects that contain sets can be serialized by wandb."""
|
|
logger = WandbTestExperimentLogger(
|
|
project="test_project", api_key="1234", excludes=["metric2"]
|
|
)
|
|
logger.on_trial_start(0, [], trial)
|
|
|
|
# Testing for https://github.com/ray-project/ray/issues/28541
|
|
rllib_result = {
|
|
"env": "simple_spread",
|
|
"framework": "torch",
|
|
"num_gpus": 1,
|
|
"num_workers": 20,
|
|
"num_envs_per_env_runner": 1,
|
|
"compress_observations": True,
|
|
"lambda": 0.99,
|
|
"train_batch_size": 512,
|
|
"sgd_minibatch_size": 32,
|
|
"num_sgd_iter": 5,
|
|
"batch_mode": "truncate_episodes",
|
|
"entropy_coeff": 0.01,
|
|
"lr": 2e-05,
|
|
"multiagent": {
|
|
"policies": {"shared_policy"},
|
|
"policy_mapping_fn": lambda x: x,
|
|
},
|
|
}
|
|
logger.on_trial_result(0, [], trial, rllib_result)
|
|
logger.on_trial_complete(0, [], trial)
|
|
logger.on_experiment_end(trials=[trial])
|
|
logged = logger.trial_logging_actor_states[trial].logs[0]
|
|
assert logged != "serialization error"
|
|
|
|
def test_wandb_logging_actor_api_key(self, trial, monkeypatch):
|
|
"""Tests that the wandb API key get propagated as an environment variable to
|
|
the remote logging actors."""
|
|
|
|
def mock_run(actor_cls):
|
|
return os.environ.get(WANDB_ENV_VAR)
|
|
|
|
monkeypatch.setattr(_MockWandbLoggingActor, "run", mock_run)
|
|
|
|
logger = WandbLoggerCallback(
|
|
project="test_project", api_key="1234", excludes=["metric2"]
|
|
)
|
|
logger._logger_actor_cls = _MockWandbLoggingActor
|
|
logger.setup()
|
|
logger.log_trial_start(trial)
|
|
actor_env_var = ray.get(logger._trial_logging_futures[trial])
|
|
assert actor_env_var == "1234"
|
|
|
|
def test_wandb_finish(self, trial, tmp_path):
|
|
"""Test that logging actors are cleaned up upon experiment completion."""
|
|
marker = tmp_path / "hang_marker"
|
|
marker.write_text("")
|
|
|
|
class HangingFinishMockWandbAPI(_MockWandbAPI):
|
|
def finish(self):
|
|
while marker.exists():
|
|
time.sleep(0.1)
|
|
|
|
logger = get_mock_wandb_logger(
|
|
mock_api_cls=HangingFinishMockWandbAPI,
|
|
upload_timeout=1.0,
|
|
)
|
|
logger.setup()
|
|
logger.on_trial_start(0, [], trial)
|
|
logger.on_trial_complete(0, [], trial)
|
|
# Signalling stop will not cleanup fully due to the hanging finish
|
|
assert logger._trial_logging_actors
|
|
marker.unlink()
|
|
# wandb.finish has ended -> experiment end hook should cleanup actors fully
|
|
logger.on_experiment_end(trials=[trial])
|
|
assert not logger._trial_logging_actors
|
|
|
|
def test_wandb_kill_hanging_actor(self, trial):
|
|
"""Test that logging actors are killed if exceeding the upload timeout
|
|
upon experiment completion."""
|
|
|
|
class HangingFinishMockWandbAPI(_MockWandbAPI):
|
|
def finish(self):
|
|
time.sleep(5)
|
|
|
|
logger = get_mock_wandb_logger(
|
|
mock_api_cls=HangingFinishMockWandbAPI,
|
|
upload_timeout=0.1,
|
|
)
|
|
logger.setup()
|
|
logger.on_trial_start(0, [], trial)
|
|
logger.on_trial_complete(0, [], trial)
|
|
# Signalling stop will not cleanup fully due to the hanging finish
|
|
assert logger._trial_logging_actors
|
|
actor = logger._trial_logging_actors[trial]
|
|
# Experiment end hook should kill actors since upload_timeout < 5
|
|
logger.on_experiment_end(trials=[trial])
|
|
assert not logger._trial_logging_actors
|
|
gc.collect()
|
|
with pytest.raises(RayActorError):
|
|
ray.get(actor.get_state.remote())
|
|
|
|
def test_wandb_destructor(self, trial):
|
|
"""Test that the WandbLoggerCallback destructor forcefully cleans up
|
|
logging actors."""
|
|
|
|
class SlowFinishMockWandbAPI(_MockWandbAPI):
|
|
def finish(self):
|
|
time.sleep(5)
|
|
|
|
logger = get_mock_wandb_logger(
|
|
mock_api_cls=SlowFinishMockWandbAPI,
|
|
upload_timeout=1.0,
|
|
)
|
|
|
|
logger.setup()
|
|
# Triggers logging actor run loop
|
|
logger.on_trial_start(0, [], trial)
|
|
actor = logger._trial_logging_actors[trial]
|
|
del logger
|
|
gc.collect()
|
|
with pytest.raises(RayActorError):
|
|
ray.get(actor.get_state.remote())
|
|
|
|
def test_wandb_logging_actor_fault_tolerance(self, trial):
|
|
"""Tests that failing wandb logging actors are restarted"""
|
|
|
|
with tempfile.TemporaryDirectory() as tempdir:
|
|
fail_marker = Path(tempdir) / "fail_marker"
|
|
|
|
class _FailingWandbLoggingActor(_MockWandbLoggingActor):
|
|
def _handle_result(self, result):
|
|
if (
|
|
result.get("training_iteration") == 3
|
|
and not fail_marker.exists()
|
|
):
|
|
fail_marker.write_text("Ok")
|
|
raise SystemExit
|
|
|
|
return super()._handle_result(result)
|
|
|
|
logger = WandbLoggerCallback(
|
|
project="test_project", api_key="1234", excludes=["metric2"]
|
|
)
|
|
logger._logger_actor_cls = _FailingWandbLoggingActor
|
|
logger.setup()
|
|
logger.log_trial_start(trial)
|
|
|
|
actor = logger._trial_logging_actors[trial]
|
|
queue = logger._trial_queues[trial]
|
|
|
|
logger.log_trial_result(1, trial, result={"training_iteration": 1})
|
|
logger.log_trial_result(2, trial, result={"training_iteration": 2})
|
|
logger.log_trial_result(3, trial, result={"training_iteration": 3})
|
|
|
|
logger.log_trial_result(4, trial, result={"training_iteration": 4})
|
|
logger.log_trial_result(5, trial, result={"training_iteration": 5})
|
|
|
|
queue.put((_QueueItem.END, None))
|
|
|
|
# Wait for the actor's run method to complete
|
|
ray.get(logger._trial_logging_futures[trial])
|
|
|
|
state = ray.get(actor.get_state.remote())
|
|
assert [metrics["training_iteration"] for metrics in state.logs] == [4, 5]
|
|
|
|
def test_wandb_restart(self, trial):
|
|
"""Test that the WandbLoggerCallback reuses actors for trial restarts."""
|
|
|
|
logger = WandbLoggerCallback(project="test_project", api_key="1234")
|
|
logger._logger_actor_cls = _MockWandbLoggingActor
|
|
logger.setup()
|
|
|
|
assert len(logger._trial_logging_futures) == 0
|
|
assert len(logger._logging_future_to_trial) == 0
|
|
|
|
logger.log_trial_start(trial)
|
|
|
|
assert len(logger._trial_logging_futures) == 1
|
|
assert len(logger._logging_future_to_trial) == 1
|
|
|
|
logger.log_trial_start(trial)
|
|
|
|
assert len(logger._trial_logging_futures) == 1
|
|
assert len(logger._logging_future_to_trial) == 1
|
|
|
|
|
|
def test_wandb_logging_process_run_info_hook(monkeypatch):
|
|
"""
|
|
Test WANDB_PROCESS_RUN_INFO_HOOK in _WandbLoggingActor is
|
|
correctly called by calling _WandbLoggingActor.run() mocking
|
|
out calls to wandb.
|
|
"""
|
|
mock_queue = Mock(get=Mock(return_value=(_QueueItem.END, None)))
|
|
monkeypatch.setenv(
|
|
"WANDB_PROCESS_RUN_INFO_HOOK", "mock_wandb_process_run_info_hook"
|
|
)
|
|
|
|
with patch.object(ray.air.integrations.wandb, "load_class") as mock_load_class:
|
|
logging_process = _WandbLoggingActor(
|
|
logdir="/tmp", queue=mock_queue, exclude=[], to_config=[]
|
|
)
|
|
logging_process._wandb = Mock()
|
|
logging_process.run()
|
|
|
|
logging_process._wandb.init.assert_called_once()
|
|
run = logging_process._wandb.init.return_value
|
|
mock_load_class.assert_called_once_with("mock_wandb_process_run_info_hook")
|
|
external_hook = mock_load_class.return_value
|
|
external_hook.assert_called_once_with(run)
|
|
logging_process._wandb.finish.assert_called_once()
|
|
|
|
|
|
def test_wandb_logger_rank_zero_only(trial, monkeypatch):
|
|
"""Test that logging is disabled for non-rank-0 workers when rank_zero_only is True."""
|
|
|
|
monkeypatch.setenv(
|
|
WANDB_ENV_VAR,
|
|
"abcde",
|
|
)
|
|
|
|
mock_session = Mock()
|
|
mock_session.experiment_name = "test_project"
|
|
mock_session.trial_name = "trial_0"
|
|
mock_session.trial_id = "trial_0"
|
|
|
|
# Test case 1: rank_zero_only=True, rank 0
|
|
mock_session.world_rank = 0
|
|
with patch("ray.air.integrations.wandb.get_session", return_value=mock_session):
|
|
run = setup_wandb(project="test_project", rank_zero_only=True, _wandb=Mock())
|
|
assert not isinstance(run, RunDisabled)
|
|
|
|
# Test case 2: rank_zero_only=True, non-rank-0
|
|
mock_session.world_rank = 1
|
|
with patch("ray.air.integrations.wandb.get_session", return_value=mock_session):
|
|
run = setup_wandb(project="test_project", rank_zero_only=True, _wandb=Mock())
|
|
assert isinstance(run, RunDisabled)
|
|
|
|
# Test case 3: rank_zero_only=False, any rank
|
|
mock_session.world_rank = 1
|
|
with patch("ray.air.integrations.wandb.get_session", return_value=mock_session):
|
|
run = setup_wandb(project="test_project", rank_zero_only=False, _wandb=Mock())
|
|
assert not isinstance(run, RunDisabled)
|
|
|
|
# Test case 4: rank_zero_only=True, no session
|
|
with patch("ray.air.integrations.wandb.get_session", return_value=None):
|
|
run = setup_wandb(project="test_project", rank_zero_only=True, _wandb=Mock())
|
|
assert not isinstance(run, RunDisabled)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
sys.exit(pytest.main(["-v", __file__]))
|