Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[0.12.x] Make inner HTTP client configurable #16

Merged
merged 1 commit into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,14 @@ generate: tools ${OPENAPI_SPEC} ## Generate the Horreum client
set -e ;\
${PROJECT_BIN}/kiota generate -l python -c HorreumRawClient -n raw_client -d ${OPENAPI_PATH}/openapi.yaml -o ${GENERATED_CLIENT_PATH} ;\
}


##@ Example

.PHONY: run-basic-example
run-basic-example: ## Run basic example
cd examples && python basic_example.py

.PHONY: run-read-only-example
run-read-only-example: ## Run read-only example
cd examples && python read_only_example.py
6 changes: 3 additions & 3 deletions docs/GET_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ Here a very simple example:
>>> import asyncio

# Import the constructor function
>>> from horreum.horreum_client import new_horreum_client
>>> from horreum.horreum_client import new_horreum_client, HorreumCredentials

# Initialize the client
>>> client = await new_horreum_client(base_url="http://localhost:8080", username="..", password="..")
>>> client = await new_horreum_client(base_url="http://localhost:8080", credentials=HorreumCredentials(username=username, password=password))

# Call the api using the underlying raw client, in this case retrieve the Horreum server version
>>> await client.raw_client.api.config.version.get()
Expand All @@ -72,7 +72,7 @@ The previous api call is equivalent to the following `cURL`:
curl --silent -X 'GET' 'http://localhost:8080/api/config/version' -H 'accept: application/json' | jq '.'
```

Other examples can be found in the [test folder](../test), for instance:
Other examples can be found in the [examples folder](../examples), for instance:

```bash
# Import Horreum Test model
Expand Down
134 changes: 134 additions & 0 deletions examples/basic_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import asyncio
import json

from kiota_abstractions.base_request_configuration import RequestConfiguration

from horreum import HorreumCredentials, new_horreum_client
from horreum.horreum_client import HorreumClient
from horreum.raw_client.api.run.test.test_request_builder import TestRequestBuilder
from horreum.raw_client.models.extractor import Extractor
from horreum.raw_client.models.run import Run
from horreum.raw_client.models.schema import Schema
from horreum.raw_client.models.test import Test
from horreum.raw_client.models.transformer import Transformer

base_url = "http://localhost:8080"
username = "user"
password = "secret"

cleanup_data = True


async def create_schema(client: HorreumClient, data_path: str) -> int:
print(f"creating schema from {data_path}")
schema_data = json.load(open(data_path), object_hook=lambda d: Schema(**d))
print(schema_data)

schema_id = await client.raw_client.api.schema.post(schema_data)
assert schema_id > 0
return schema_id


async def create_schema_transformers(client: HorreumClient, schema_id: int, data_path: str,
extractors_data_path: str) -> int:
print(f"creating transformer from {data_path}")
transformer_data = json.load(open(data_path), object_hook=lambda d: Transformer(**d))
print(transformer_data)

print(f"creating extractors from {extractors_data_path}")
extractors_data = json.load(open(extractors_data_path),
object_hook=lambda d: Extractor(**d))
print(extractors_data)

transformer_data.extractors = extractors_data

transformer_id = await client.raw_client.api.schema.by_id_id(schema_id).transformers.post(transformer_data)
assert transformer_id > 0
return transformer_id


async def create_test(client: HorreumClient, data_path: str) -> Test:
print(f"creating test from {data_path}")

test_data = json.load(open(data_path), object_hook=lambda d: Test(**d))
print(test_data)

test = await client.raw_client.api.test.post(test_data)
assert test.id > 0
return test


async def set_test_transformers(client: HorreumClient, test_id: int, transformers: list[int]):
await client.raw_client.api.test.by_id(test_id).transformers.post(transformers)


async def upload_run(client: HorreumClient, test_id: int, run_path: str, run_data_path: str):
print(f"uploading run from {run_path}")

run = json.load(open(run_path), object_hook=lambda d: Run(**d))
run_data = json.load(open(run_data_path))
run.data = json.dumps(run_data)
print(run)

query_params = TestRequestBuilder.TestRequestBuilderPostQueryParameters(test=str(test_id))
config = RequestConfiguration(query_parameters=query_params)
await client.raw_client.api.run.test.post(run, config)


async def setup_roadrunner_test(client: HorreumClient):
print("creating roadrunner test")

acme_benchmark_schema_id = await create_schema(client, "./data/acme_benchmark_schema.json")
acme_horreum_schema_id = await create_schema(client, "./data/acme_horreum_schema.json")

acme_transformers_id = await create_schema_transformers(client, acme_benchmark_schema_id,
"./data/acme_transformer.json",
"./data/acme_transformer_extractors.json")

roadrunner_test = await create_test(client, "./data/roadrunner_test.json")
await set_test_transformers(client, roadrunner_test.id, [acme_transformers_id])

await upload_run(client, roadrunner_test.id, "./data/roadrunner_run.json", "./data/roadrunner_run_data.json")


async def delete_all(client: HorreumClient):
""" cleanup all Horreum data """

print("cleaning up tests")
get_tests = await client.raw_client.api.test.get()
for t in get_tests.tests:
await client.raw_client.api.test.by_id(t.id).delete()

get_tests = await client.raw_client.api.test.get()
assert get_tests.count == 0

print("cleaning up schemas")
get_schemas = await client.raw_client.api.schema.get()
for s in get_schemas.schemas:
await client.raw_client.api.schema.by_id_id(s.id).delete()

get_schemas = await client.raw_client.api.schema.get()
assert get_schemas.count == 0


async def example():
client = await new_horreum_client(base_url, credentials=HorreumCredentials(username=username, password=password))

if cleanup_data:
await delete_all(client)

await setup_roadrunner_test(client)

# check data is properly injected in the server
get_schemas = await client.raw_client.api.schema.get()
assert get_schemas.count == 2

get_tests = await client.raw_client.api.test.get()
assert get_tests.count == 1

get_runs = await client.raw_client.api.run.list_.get()
assert get_runs.total == 1


if __name__ == '__main__':
asyncio.run(example())
7 changes: 7 additions & 0 deletions examples/data/acme_benchmark_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "ACME Benchmark Schema",
"description": "Data produced by benchmarking tool",
"owner": "dev-team",
"access": "PUBLIC",
"uri": "urn:acme:benchmark:0.1"
}
7 changes: 7 additions & 0 deletions examples/data/acme_horreum_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "ACME Horreum Schema",
"description": "Used in Datasets",
"owner": "dev-team",
"access": "PUBLIC",
"uri": "urn:acme:horreum:0.1"
}
8 changes: 8 additions & 0 deletions examples/data/acme_transformer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "Acme Transformer",
"description": "Transformer for converting complex runs into individual datasets",
"owner": "dev-team",
"access": "PUBLIC",
"target_schema_uri": "urn:acme:horreum:0.1",
"function": "({results, hash}) => results.map(r => ({ ...r, hash }))"
}
12 changes: 12 additions & 0 deletions examples/data/acme_transformer_extractors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"name": "hash",
"jsonpath": "$.buildHash",
"isarray": false
},
{
"name": "results",
"jsonpath": "$.results",
"isarray": false
}
]
7 changes: 7 additions & 0 deletions examples/data/roadrunner_run.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"description": "Example run of Roadrunner",
"owner": "dev-team",
"access": "PUBLIC",
"start": 1669388931000,
"stop": 1669388932000
}
17 changes: 17 additions & 0 deletions examples/data/roadrunner_run_data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "urn:acme:benchmark:0.1",
"something": "This gets lost by the transformer",
"buildHash": "defec8eddeadbeafcafebabeb16b00b5",
"results": [
{
"test": "Foo",
"requests": 123,
"duration": 10
},
{
"test": "Bar",
"requests": 456,
"duration": 20
}
]
}
7 changes: 7 additions & 0 deletions examples/data/roadrunner_test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "Roadrunner Test",
"description": "acme.com benchmark",
"owner": "dev-team",
"access": "PUBLIC",
"fingerprint_labels": [ "benchmark_test" ]
}
42 changes: 42 additions & 0 deletions examples/read_only_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import asyncio

import httpx

from horreum import new_horreum_client, ClientConfiguration

DEFAULT_CONNECTION_TIMEOUT: int = 30
DEFAULT_REQUEST_TIMEOUT: int = 100

base_url = "http://localhost:8080"
username = "user"
password = "secret"

expected_server_version = "0.13.0"
expected_n_schemas = 2
expected_n_tests = 1
enable_assertions = False


async def example():
timeout = httpx.Timeout(DEFAULT_REQUEST_TIMEOUT, connect=DEFAULT_CONNECTION_TIMEOUT)
http_client = httpx.AsyncClient(timeout=timeout, http2=True, verify=False)
client = await new_horreum_client(base_url, client_config=ClientConfiguration(http_client=http_client))

server_version = await client.raw_client.api.config.version.get()
print(server_version)
if enable_assertions:
assert server_version.version == expected_server_version

get_schemas = await client.raw_client.api.schema.get()
print(get_schemas.count)
if enable_assertions:
assert get_schemas.count == expected_n_schemas

get_tests = await client.raw_client.api.test.get()
print(get_tests.count)
if enable_assertions:
assert get_tests.count == expected_n_tests


if __name__ == '__main__':
asyncio.run(example())
5 changes: 4 additions & 1 deletion src/horreum/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from horreum.configs import HorreumCredentials, ClientConfiguration
from horreum.horreum_client import new_horreum_client

__all__ = [
new_horreum_client
new_horreum_client,
HorreumCredentials,
ClientConfiguration
]
21 changes: 21 additions & 0 deletions src/horreum/configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from dataclasses import dataclass
from typing import Optional

import httpx
from kiota_abstractions.request_option import RequestOption


@dataclass(frozen=True)
class HorreumCredentials:
username: str = None
password: str = None


@dataclass
class ClientConfiguration:
# inner http async client that will be used to perform raw requests
http_client: Optional[httpx.AsyncClient] = None
# if true, set default middleware on the provided client
use_default_middlewares: bool = True
# if set use these options for default middlewares
options: Optional[dict[str, RequestOption]] = None
Loading