Skip to content

Commit 37104ac

Browse files
Gaudi: Add Integration Test for Gaudi Backend (#3142)
* feat(gaudi): add integration test * feat(test): add more models to integration tests * remove debug comments * fix typos
1 parent 87a0af4 commit 37104ac

21 files changed

+764
-3096
lines changed

backends/gaudi/Makefile

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
22
mkfile_dir := $(dir $(mkfile_path))
3-
root_dir := "${mkfile_dir}/../.."
3+
root_dir := ${mkfile_dir}/../..
44

55
HABANA_VERSION := 1.20.0
66
PYTORCH_VERSION := 2.6.0
@@ -47,3 +47,16 @@ local-dev-install: install-dependencies
4747
make install-server && \
4848
make install-router && \
4949
make install-launcher'
50+
51+
# In order to run the integration tests, you need to first build the image (make -C backends/gaudi image)
52+
run-integration-tests:
53+
uv pip install -r ${root_dir}/backends/gaudi/server/integration-tests/requirements.txt
54+
DOCKER_VOLUME=${root_dir}/data \
55+
HF_TOKEN=`cat ${HOME}/.cache/huggingface/token` \
56+
uv run pytest --durations=0 -sv ${root_dir}/backends/gaudi/server/integration-tests
57+
58+
# This is used to capture the expected outputs for the integration tests offering an easy way to add more models to the integration tests
59+
capture-expected-outputs-for-integration-tests:
60+
DOCKER_VOLUME=${root_dir}/data \
61+
HF_TOKEN=`cat ${HOME}/.cache/huggingface/token` \
62+
uv run pytest --durations=0 -sv ${root_dir}/backends/gaudi/server/integration-tests/capture_expected_outputs.py

backends/gaudi/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,47 @@ curl 127.0.0.1:8080/generate \
9696
-d '{"inputs":"What is Deep Learning?","parameters":{"max_new_tokens":20}}' \
9797
-H 'Content-Type: application/json'
9898
```
99+
100+
### Integration tests
101+
102+
To run the integration tests, you need to first build the image:
103+
```bash
104+
make -C backends/gaudi image
105+
```
106+
107+
Then run the following command to run the integration tests:
108+
```bash
109+
make -C backends/gaudi run-integration-tests
110+
```
111+
112+
To capture the expected outputs for the integration tests, you can run the following command:
113+
```bash
114+
make -C backends/gaudi capture-expected-outputs-for-integration-tests
115+
```
116+
117+
#### How the integration tests works
118+
The integration tests works as follows:
119+
120+
1. Start a tgi server in a container, similar to the command:
121+
```bash
122+
docker run --runtime=habana --ipc=host --cap-add=sys_nice \
123+
-p 8080:80 -v $volume:/data \
124+
-e LOG_LEVEL=debug -e HF_TOKEN=$hf_token \
125+
tgi-gaudi --model-id $model \
126+
--max-input-tokens 512 --max-total-tokens 1024 --max-batch-size 4 --max-batch-prefill-tokens 2048
127+
```
128+
129+
2. Do a /generate request to the server, similar to the command:
130+
```bash
131+
curl 127.0.0.1:8080/generate \
132+
-X POST \
133+
-d '{"inputs":"What is Deep Learning?","parameters":{"max_new_tokens":20}}' \
134+
-H 'Content-Type: application/json'
135+
```
136+
137+
3. Check the output of the server against the expected output:
138+
```python
139+
assert curl_output == expected_output
140+
```
141+
142+
This is the repeated for a set of models and configurations.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import json
2+
import os
3+
from typing import Dict, Any, Generator
4+
5+
import pytest
6+
from test_model import TEST_CONFIGS
7+
8+
UNKNOWN_CONFIGS = {
9+
name: config
10+
for name, config in TEST_CONFIGS.items()
11+
if config["expected_greedy_output"] == "unknown"
12+
or config["expected_batch_output"] == "unknown"
13+
}
14+
15+
16+
@pytest.fixture(scope="module", params=UNKNOWN_CONFIGS.keys())
17+
def test_config(request) -> Dict[str, Any]:
18+
"""Fixture that provides model configurations for testing."""
19+
test_config = UNKNOWN_CONFIGS[request.param]
20+
test_config["test_name"] = request.param
21+
return test_config
22+
23+
24+
@pytest.fixture(scope="module")
25+
def test_name(test_config):
26+
yield test_config["test_name"]
27+
28+
29+
@pytest.fixture(scope="module")
30+
def tgi_service(launcher, test_config, test_name) -> Generator:
31+
"""Fixture that provides a TGI service for testing."""
32+
with launcher(test_config["model_id"], test_name) as service:
33+
yield service
34+
35+
36+
@pytest.mark.asyncio
37+
async def test_capture_expected_outputs(tgi_service, test_config, test_name):
38+
"""Test that captures expected outputs for models with unknown outputs."""
39+
print(f"Testing {test_name} with {test_config['model_id']}")
40+
41+
# Wait for service to be ready
42+
await tgi_service.health(1000)
43+
client = tgi_service.client
44+
45+
# Test single request (greedy)
46+
print("Testing single request...")
47+
response = await client.generate(
48+
test_config["input"],
49+
max_new_tokens=32,
50+
)
51+
greedy_output = response.generated_text
52+
53+
# Test multiple requests (batch)
54+
print("Testing batch requests...")
55+
responses = []
56+
for _ in range(4):
57+
response = await client.generate(
58+
test_config["input"],
59+
max_new_tokens=32,
60+
)
61+
responses.append(response.generated_text)
62+
63+
# Store results in a JSON file
64+
output_file = "server/integration-tests/expected_outputs.json"
65+
results = {}
66+
67+
# Try to load existing results if file exists
68+
if os.path.exists(output_file):
69+
with open(output_file, "r") as f:
70+
results = json.load(f)
71+
72+
# Update results for this model
73+
results[test_name] = {
74+
"model_id": test_config["model_id"],
75+
"input": test_config["input"],
76+
"greedy_output": greedy_output,
77+
"batch_outputs": responses,
78+
"args": test_config["args"],
79+
}
80+
81+
# Save updated results
82+
with open(output_file, "w") as f:
83+
json.dump(results, f, indent=2)
84+
85+
print(f"\nResults for {test_name} saved to {output_file}")

0 commit comments

Comments
 (0)