← Files Dataiku HeadlessARCHIVED FILE
tests/test_project_settings.py
6.16 KB · Nov 11, 2026 · 12:58 UTC
# Copyright 2026 Dataiku SAS
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for project settings inspection and updates."""
import asyncio
import json
import pytest
from dataiku_mcp.tools import projects
from tests.utils.fakes import FakeContext, FakeDSSClient
class _FakeSettings:
def __init__(self, raw: dict):
self.raw = raw
self.save_calls = 0
def get_raw(self) -> dict:
return self.raw
def save(self) -> None:
self.save_calls += 1
class _FakeProject:
def __init__(self, raw: dict):
self.settings = _FakeSettings(raw)
def get_settings(self) -> _FakeSettings:
return self.settings
def _install_fake_project(monkeypatch, raw: dict) -> _FakeProject:
project = _FakeProject(raw)
monkeypatch.setattr(
projects, "get_dss_client", lambda: FakeDSSClient({"PROJ": project})
)
return project
def test_get_project_settings_returns_editable_settings(monkeypatch):
raw = {
"settings": {"flowDisplaySettings": {"showFlowZoneDescriptions": False}},
"permissions": [{"group": "data-team"}],
}
_install_fake_project(monkeypatch, raw)
result = json.loads(
asyncio.run(projects.get_project_settings("PROJ", FakeContext()))
)
assert result == raw["settings"]
def test_update_project_settings_applies_merge_patch(monkeypatch):
raw = {
"settings": {
"flowDisplaySettings": {
"showFlowZoneDescriptions": False,
"zonesGraphConnectZones": True,
},
"codeEnvs": {
"python": {
"mode": "USE_BUILTIN_MODE",
"useBuiltinEnv": True,
"preventOverride": True,
},
"r": {
"mode": "EXPLICIT_ENV",
"envName": "R_ENV",
"useBuiltinEnv": True,
"preventOverride": False,
},
},
"container": {
"containerMode": "EXPLICIT_CONTAINER",
"containerConf": "container-config",
},
},
"permissions": [{"group": "data-team"}],
}
project = _install_fake_project(monkeypatch, raw)
patch = {
"flowDisplaySettings": {"showFlowZoneDescriptions": True},
"codeEnvs": {
"python": {"mode": "EXPLICIT_ENV", "envName": "PYTHON_ENV"},
"r": {"mode": "USE_BUILTIN_MODE"},
},
"container": {"containerMode": "NONE", "containerConf": None},
}
result = json.loads(
asyncio.run(
projects.update_project_settings("PROJ", json.dumps(patch), FakeContext())
)
)
assert result == {
"flowDisplaySettings": {
"showFlowZoneDescriptions": True,
"zonesGraphConnectZones": True,
},
"codeEnvs": {
"python": {
"mode": "EXPLICIT_ENV",
"envName": "PYTHON_ENV",
"useBuiltinEnv": False,
"preventOverride": True,
},
"r": {
"mode": "USE_BUILTIN_MODE",
"useBuiltinEnv": True,
"preventOverride": False,
},
},
"container": {"containerMode": "NONE"},
}
assert raw["permissions"] == [{"group": "data-team"}]
assert project.settings.save_calls == 1
def test_update_project_settings_sets_cobuild_instructions(monkeypatch):
raw = {"settings": {"cobuildSettings": {"customPromptMode": "APPEND_TO_GLOBAL"}}}
project = _install_fake_project(monkeypatch, raw)
patch = {
"cobuildSettings": {
"customSystemPrompt": "Prefer visual recipes.",
"customPromptMode": "OVERRIDE_GLOBAL",
}
}
result = json.loads(
asyncio.run(projects.update_project_settings("PROJ", patch, FakeContext()))
)
assert result == patch
assert project.settings.save_calls == 1
with pytest.raises(ValueError, match="Allowed values"):
asyncio.run(
projects.update_project_settings(
"PROJ",
{"cobuildSettings": {"customPromptMode": "REPLACE"}},
FakeContext(),
)
)
def test_update_project_settings_rejects_invalid_patch(monkeypatch):
project = _install_fake_project(monkeypatch, {"settings": {}})
with pytest.raises(ValueError, match="must not be empty"):
asyncio.run(projects.update_project_settings("PROJ", {}, FakeContext()))
with pytest.raises(ValueError, match="must be a JSON object"):
asyncio.run(projects.update_project_settings("PROJ", "[1,2]", FakeContext()))
with pytest.raises(ValueError, match="codeEnvs.python.unknown"):
asyncio.run(
projects.update_project_settings(
"PROJ", {"codeEnvs": {"python": {"unknown": True}}}, FakeContext()
)
)
with pytest.raises(ValueError, match="must be a boolean"):
asyncio.run(
projects.update_project_settings(
"PROJ",
{"flowBuildSettings": {"mergeSqlPipelines": "yes"}},
FakeContext(),
)
)
with pytest.raises(ValueError, match="Allowed values"):
asyncio.run(
projects.update_project_settings(
"PROJ", {"container": {"containerMode": "BANANA"}}, FakeContext()
)
)
with pytest.raises(ValueError, match="codeEnvs.python.envName"):
asyncio.run(
projects.update_project_settings(
"PROJ",
{"codeEnvs": {"python": {"mode": "EXPLICIT_ENV"}}},
FakeContext(),
)
)
assert project.settings.save_calls == 0
SHA-256: 58700d233bbac5a263adad7fa214bc3e4878c225a21e55c962853e97f7796404