Files
openobserve/tests/api-testing/tests/test_function_test_endpoint.py
T
Neha PandClaude 87a507f83a test: add API tests for bulk enable, functions, kvstore, multi-stream search, passcode (#10155)
### **User description**
- Add test_alert_bulk_enable.py: bulk enable/disable alerts (5 tests)
- Add test_function_test_endpoint.py: VRL function testing (7 tests)
- Add test_kvstore.py: KV store CRUD operations (8 tests)
- Add test_multi_stream_search.py: multi-stream SSE search (6 tests)
- Add test_org_passcode.py: organization passcode API (4 tests)

🤖 Generated with [Claude Code](https://claude.com/claude-code)


___

### **PR Type**
Tests


___

### **Description**
- Bulk alert enable/disable tests for existing alerts

- VRL/JS function test endpoint happy and error flows

- KV store create, read, list, update, delete tests

- Multi-stream SSE search tests for various scenarios

- Organization passcode get, update, persistence tests


___



<details> <summary><h3> File Walkthrough</h3></summary>

<table><thead><tr><th></th><th align="left">Relevant
files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><table>
<tr>
  <td>
    <details>
<summary><strong>test_alert_bulk_enable.py</strong><dd><code>Bulk alert
enable/disable tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

tests/api-testing/tests/test_alert_bulk_enable.py

<ul><li>Fixture setup for session and existing alerts retrieval<br> <li>
Tests bulk disable and enable single alerts<br> <li> Tests bulk disable
for multiple alerts<br> <li> Idempotency and response structure
verification</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10155/files#diff-bb438bbffe5aad82142e50aa7765cb47c711463ffc0fc1ce72b221cbcadafe9a">+241/-0</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>

<summary><strong>test_function_test_endpoint.py</strong><dd><code>Function
test endpoint tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

tests/api-testing/tests/test_function_test_endpoint.py

<ul><li>Fixture setup for VRL/JS function test endpoint<br> <li> Tests
basic function and value modification<br> <li> Multi-event and
conditional logic tests<br> <li> Invalid syntax and response structure
verification</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10155/files#diff-8f8ba09e2a96c246c77ae4512443842d0e8accb855bac0f949971941b9956b6c">+230/-0</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>test_kvstore.py</strong><dd><code>KV store CRUD API
tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></summary>
<hr>

tests/api-testing/tests/test_kvstore.py

<ul><li>Added KV store CRUD tests (create, read, list)<br> <li> Tests
prefix filtering and update behavior<br> <li> Delete operations, 404 and
idempotency tests</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10155/files#diff-b353df992b5db6b02190e9232e077967b8c30d702f24bb1903c8d5c8c32fd14e">+226/-0</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>

<summary><strong>test_multi_stream_search.py</strong><dd><code>Multi-stream
search SSE tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; </dd></summary>
<hr>

tests/api-testing/tests/test_multi_stream_search.py

<ul><li>Fixture setup and SSE response parser added<br> <li> Tests
single and multi-stream search queries<br> <li> SSE format and metadata
structure verification<br> <li> Size limit and invalid stream handling
tests</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10155/files#diff-c20d33fef67f42eb651e7a0d5d97d053c1d0d58307c13fb57ea0a19ffeedb329">+223/-0</a>&nbsp;
</td>

</tr>

<tr>
  <td>
    <details>
<summary><strong>test_org_passcode.py</strong><dd><code>Organization
passcode API tests</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
</dd></summary>
<hr>

tests/api-testing/tests/test_org_passcode.py

<ul><li>Tests organization passcode get and update endpoints<br> <li>
Verifies persistence and response structure</ul>


</details>


  </td>
<td><a
href="https://github.com/openobserve/openobserve/pull/10155/files#diff-819841cc5f7f2475248a5edd31f9d44c79159fa6fb97a9c2db9ea70139904379">+126/-0</a>&nbsp;
</td>

</tr>
</table></td></tr></tr></tbody></table>

</details>

___

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 11:07:04 +05:30

233 lines
7.8 KiB
Python

"""
Function Test Endpoint API Tests
Tests for Function Test operations:
- POST /api/{org_id}/functions/test - Test a VRL/JS function without saving it
"""
import pytest
class TestFunctionTestEndpoint:
"""Test class for Function Test API endpoint."""
ORG_ID = "default"
@pytest.fixture(autouse=True)
def setup(self, create_session, base_url):
"""Setup test fixtures."""
self.session = create_session
self.base_url = base_url
def test_01_basic_vrl_function(self):
"""Test a basic VRL function that adds a field"""
payload = {
"function": ".test_field = \"added_by_test\"\n.",
"events": [
{
"_timestamp": 1735128523652186,
"job": "pytest",
"level": "info",
"log": "test message"
}
]
}
response = self.session.post(
f"{self.base_url}api/{self.ORG_ID}/functions/test",
json=payload
)
assert response.status_code == 200, \
f"Expected 200, got {response.status_code}: {response.text}"
data = response.json()
assert "results" in data, f"Response should have 'results' field: {data}"
assert len(data["results"]) == 1, f"Should have 1 result: {data}"
result = data["results"][0]
assert "event" in result, f"Result should have 'event' field: {result}"
assert result["event"].get("test_field") == "added_by_test", \
f"Function should add 'test_field': {result}"
print(f"✓ VRL function successfully added field")
def test_02_vrl_function_modifies_value(self):
"""Test a VRL function that modifies an existing value"""
# Use upcase! (infallible version) to avoid VRL error handling requirements
payload = {
"function": ".level = upcase!(.level)\n.",
"events": [
{
"_timestamp": 1735128523652186,
"level": "info"
}
],
"trans_type": 0 # Explicitly set to VRL
}
response = self.session.post(
f"{self.base_url}api/{self.ORG_ID}/functions/test",
json=payload
)
assert response.status_code == 200, \
f"Expected 200, got {response.status_code}: {response.text}"
data = response.json()
assert "results" in data and len(data["results"]) > 0, \
f"Response should have results: {data}"
result = data["results"][0]
assert result["event"].get("level") == "INFO", \
f"Function should uppercase 'level': {result}"
print(f"✓ VRL function successfully modified field")
def test_03_vrl_function_with_multiple_events(self):
"""Test a VRL function with multiple events"""
payload = {
"function": ".processed = true\n.",
"events": [
{"id": 1, "name": "event1"},
{"id": 2, "name": "event2"},
{"id": 3, "name": "event3"}
]
}
response = self.session.post(
f"{self.base_url}api/{self.ORG_ID}/functions/test",
json=payload
)
assert response.status_code == 200, \
f"Expected 200, got {response.status_code}: {response.text}"
data = response.json()
assert len(data["results"]) == 3, \
f"Should have 3 results for 3 events: {data}"
# Verify all events have the added field
for i, result in enumerate(data["results"]):
assert result["event"].get("processed") is True, \
f"Event {i} should have 'processed' = true: {result}"
print(f"✓ VRL function successfully processed {len(data['results'])} events")
def test_04_vrl_function_with_conditional(self):
"""Test a VRL function with conditional logic"""
payload = {
"function": "if .level == \"error\" { .priority = \"high\" } else { .priority = \"normal\" }\n.",
"events": [
{"level": "error", "message": "something failed"},
{"level": "info", "message": "all good"}
],
"trans_type": 0 # Explicitly set to VRL
}
response = self.session.post(
f"{self.base_url}api/{self.ORG_ID}/functions/test",
json=payload
)
assert response.status_code == 200, \
f"Expected 200, got {response.status_code}: {response.text}"
data = response.json()
assert data["results"][0]["event"].get("priority") == "high", \
f"Error event should have high priority: {data['results'][0]}"
assert data["results"][1]["event"].get("priority") == "normal", \
f"Info event should have normal priority: {data['results'][1]}"
print(f"✓ VRL conditional logic works correctly")
def test_05_invalid_vrl_function(self):
"""Test that invalid VRL syntax returns an error"""
payload = {
"function": ".test = invalid syntax here!!!",
"events": [{"field": "value"}]
}
response = self.session.post(
f"{self.base_url}api/{self.ORG_ID}/functions/test",
json=payload
)
# Invalid syntax should return 400 or have error in results
# The API behavior may vary, so we check both possibilities
if response.status_code == 400:
print(f"✓ Invalid VRL correctly returned 400 error")
else:
data = response.json()
# Check if error message is present in results
has_error = any(
result.get("message", "") != ""
for result in data.get("results", [])
)
assert has_error or response.status_code == 400, \
f"Invalid VRL should produce an error: {response.status_code} - {data}"
print(f"✓ Invalid VRL correctly returned error in results")
def test_06_response_structure(self):
"""Test that response has correct structure"""
payload = {
"function": ".", # Identity function - returns input unchanged
"events": [{"test": "value"}]
}
response = self.session.post(
f"{self.base_url}api/{self.ORG_ID}/functions/test",
json=payload
)
assert response.status_code == 200
data = response.json()
# Verify response structure
assert "results" in data, "Response should have 'results' field"
assert isinstance(data["results"], list), "'results' should be a list"
for result in data["results"]:
assert "message" in result, "Each result should have 'message' field"
assert "event" in result, "Each result should have 'event' field"
print(f"✓ Response structure is correct: {data}")
def test_07_vrl_delete_field(self):
"""Test a VRL function that deletes a field"""
payload = {
"function": "del(.sensitive_data)\n.",
"events": [
{
"id": 1,
"name": "test",
"sensitive_data": "secret123"
}
],
"trans_type": 0 # Explicitly set to VRL
}
response = self.session.post(
f"{self.base_url}api/{self.ORG_ID}/functions/test",
json=payload
)
assert response.status_code == 200, \
f"Expected 200, got {response.status_code}: {response.text}"
data = response.json()
result = data["results"][0]
assert "sensitive_data" not in result["event"], \
f"Field 'sensitive_data' should be deleted: {result}"
assert result["event"].get("name") == "test", \
f"Other fields should remain: {result}"
print(f"✓ VRL function successfully deleted field")