Spaces:
Running
Running
File size: 6,793 Bytes
3c65377 c3449ec 34f7221 3c65377 c3449ec 30e135b c3449ec 30e135b c3449ec 3c65377 34f7221 21ee86d 34f7221 21ee86d 34f7221 4489319 | 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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | from thoughtspot_errors import friendly_mcp_liveboard_error
from tests.e2e_quality import extract_db_schema_from_tml_docs
import liveboard_creator
import thoughtspot_deployer
def test_friendly_mcp_error_classifies_service_outage():
message, category = friendly_mcp_liveboard_error(
"MCP liveboard timed out after 360s — MCP endpoint unresponsive at network level"
)
assert category == "mcp_service"
assert "MCP service appears unavailable or timed out" in message
assert "Raw MCP error:" in message
def test_friendly_mcp_error_classifies_auth_failure():
message, category = friendly_mcp_liveboard_error(
"Failed to get trusted auth token. Check THOUGHTSPOT_TRUSTED_AUTH_KEY"
)
assert category == "mcp_auth"
assert "could not authenticate" in message
assert "trusted auth key" in message.lower()
def test_friendly_mcp_error_classifies_generation_failure():
message, category = friendly_mcp_liveboard_error(
"No questions generated. Model may be empty or incompatible."
)
assert category == "mcp_generation"
assert "MCP liveboard generation step" in message
assert "falling back" in message
def test_friendly_mcp_error_classifies_missing_answer_tokens_as_recoverable():
message, category = friendly_mcp_liveboard_error(
"No liveboard-compatible answers with ThoughtSpot session/tokens were retrieved."
)
assert category == "mcp_answer_tokens"
assert "backup liveboard" in message
def test_direct_answer_rejects_empty_token_payload(monkeypatch):
class FakeResponse:
status_code = 200
text = ""
def json(self):
return {
"session_identifier": "session-123",
"generation_number": -1,
"message_type": "TSAnswer",
"visualization_type": "Undefined",
"tokens": "",
"display_tokens": "",
}
class FakeSession:
def post(self, *args, **kwargs):
return FakeResponse()
monkeypatch.setattr(liveboard_creator, "_get_direct_api_session", lambda *args, **kwargs: (FakeSession(), "token"))
assert liveboard_creator._get_answer_direct(
"Total Net Sales",
"model-guid",
"testrunner@example.com",
"secret",
ts_url="https://example.thoughtspot.cloud",
) is None
def test_liveboard_answer_validation_requires_tokens_but_allows_undefined_visualization():
assert liveboard_creator._is_liveboard_answer_valid(
{
"session_identifier": "session-123",
"tokens": [{"token": "Net Sales"}],
"visualization_type": "Undefined",
}
)
assert not liveboard_creator._is_liveboard_answer_valid(
{
"session_identifier": "session-123",
"tokens": "",
"visualization_type": "Undefined",
}
)
def test_extract_db_schema_reads_physical_table_tml_not_model_name():
docs = [
"""
model:
name: TST_WRONG_01010000_ABC_mdl
""",
"""
table:
name: SALES
db: DEMOBUILD
schema: TST_RIGHT_01010000_DEF_sch
""",
]
assert extract_db_schema_from_tml_docs(docs) == ("DEMOBUILD", "TST_RIGHT_01010000_DEF_sch")
def test_extract_db_schema_does_not_guess_from_model_name():
docs = [
"""
model:
name: TST_WRONG_01010000_ABC_mdl
"""
]
assert extract_db_schema_from_tml_docs(docs) == ("", "")
def test_connection_create_reconciles_secure_store_bad_gateway(monkeypatch):
class FakeResponse:
status_code = 200
text = ""
def json(self):
return [
{
"response": {
"status": {
"status_code": "ERROR",
"error_message": (
"Exception occurred while saving dataSource: "
"Error Code: SECURE_STORE_ERROR Error Message: Bad Gateway."
),
},
"header": {"name": "MBB_VIZ_TEST_conn"},
}
}
]
class FakeSession:
def __init__(self):
self.posts = []
def post(self, url, **kwargs):
self.posts.append({"url": url, **kwargs})
return FakeResponse()
deployer = thoughtspot_deployer.ThoughtSpotDeployer.__new__(
thoughtspot_deployer.ThoughtSpotDeployer
)
deployer.base_url = "https://ts.example"
deployer.session = FakeSession()
deployer.headers = {}
deployer.create_connection_tml = lambda name, database: "connection:\n name: MBB_VIZ_TEST_conn\n"
calls = []
def fake_get_connection_by_name(name):
calls.append(name)
if len(calls) == 1:
return None
return {"header": {"id_guid": "connection-guid", "name": name}}
deployer.get_connection_by_name = fake_get_connection_by_name
monkeypatch.setattr(thoughtspot_deployer.time, "sleep", lambda seconds: None)
guid, fqn = deployer.create_connection_with_reconcile(
"MBB_VIZ_TEST_conn",
"DEMOBUILD_TEST",
log_progress=lambda message: None,
)
assert guid == "connection-guid"
assert fqn == "connection-guid"
assert len(deployer.session.posts) == 1
assert len(calls) == 2
def test_trusted_auth_retries_transient_gateway_error(monkeypatch):
class FakeResponse:
def __init__(self, status_code, payload=None, text=""):
self.status_code = status_code
self._payload = payload or {}
self.text = text
def json(self):
return self._payload
class FakeSession:
def __init__(self):
self.headers = {}
self.calls = 0
def post(self, url, **kwargs):
self.calls += 1
if self.calls == 1:
return FakeResponse(502, text="Bad Gateway")
return FakeResponse(200, {"token": "token-123"})
deployer = thoughtspot_deployer.ThoughtSpotDeployer.__new__(
thoughtspot_deployer.ThoughtSpotDeployer
)
deployer.base_url = "https://ts.example"
deployer.username = "mike.boone@thoughtspot.com"
deployer.secret_key = "secret-key-value"
deployer.session = FakeSession()
deployer.last_auth_status_code = None
deployer.last_auth_error = ""
monkeypatch.setenv("TS_AUTH_MAX_ATTEMPTS", "2")
monkeypatch.setenv("TS_AUTH_RETRY_WAIT_SECONDS", "1")
monkeypatch.setattr(thoughtspot_deployer.time, "sleep", lambda seconds: None)
assert deployer.authenticate_trusted() is True
assert deployer.session.calls == 2
assert deployer.session.headers["Authorization"] == "Bearer token-123"
|