Skip to content

Commit

Permalink
History API (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
dianaclarke committed Jul 21, 2021
1 parent 9d3cb9c commit c526d00
Show file tree
Hide file tree
Showing 8 changed files with 383 additions and 2 deletions.
1 change: 1 addition & 0 deletions conbench/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from .compare import * # noqa
from .contexts import * # noqa
from .distributions import * # noqa
from .history import * # noqa
from .index import * # noqa
from .machines import * # noqa
from .runs import * # noqa
Expand Down
6 changes: 4 additions & 2 deletions conbench/api/_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ def _201_created(example, schema=None):
spec.components.response("CommitList", _200_ok([ex.COMMIT_ENTITY]))
spec.components.response("CompareEntity", _200_ok(ex.COMPARE_ENTITY))
spec.components.response("CompareList", _200_ok(ex.COMPARE_LIST))
spec.components.response("DistributionEntity", _200_ok(ex.DISTRIBUTION_ENTITY))
spec.components.response("DistributionList", _200_ok([ex.DISTRIBUTION_ENTITY]))
spec.components.response("ContextEntity", _200_ok(ex.CONTEXT_ENTITY))
spec.components.response("ContextList", _200_ok([ex.CONTEXT_ENTITY]))
spec.components.response("DistributionEntity", _200_ok(ex.DISTRIBUTION_ENTITY))
spec.components.response("DistributionList", _200_ok([ex.DISTRIBUTION_ENTITY]))
spec.components.response("HistoryList", _200_ok([ex.HISTORY_ENTITY]))
spec.components.response("MachineEntity", _200_ok(ex.MACHINE_ENTITY))
spec.components.response("MachineList", _200_ok([ex.MACHINE_ENTITY]))
spec.components.response("RunEntity", _200_ok(ex.RUN_ENTITY))
Expand All @@ -90,6 +91,7 @@ def _201_created(example, schema=None):
{"name": "Comparisons", "description": "Benchmark comparisons"},
{"name": "Contexts", "description": "Benchmark contexts"},
{"name": "Distributions", "description": "Benchmark distributions"},
{"name": "History", "description": "Benchmark history"},
{"name": "Machines", "description": "Benchmark machines"},
{"name": "Runs", "description": "Benchmark runs"},
{"name": "Ping", "description": "Monitor status"},
Expand Down
23 changes: 23 additions & 0 deletions conbench/api/_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,24 @@ def _api_distribution_entity(
return result


def _api_history_entity(benchmark_id, case_id, context_id):
return [
{
"benchmark_id": benchmark_id,
"case_id": case_id,
"context_id": context_id,
"machine_hash": "diana-2-4-17179869184",
"mean": "0.036369",
"message": "ARROW-11771: [Developer][Archery] Move benchmark tests (so CI runs them)",
"repository": "https://github.com/apache/arrow",
"run_name": "commit: 02addad336ba19a654f9c857ede546331be7b631",
"sha": "02addad336ba19a654f9c857ede546331be7b631",
"timestamp": "2021-02-25T01:02:51",
"unit": "s",
},
]


def _api_machine_entity(machine_id, links=True):
result = {
"id": machine_id,
Expand Down Expand Up @@ -362,6 +380,11 @@ def _api_run_entity(run_id, commit_id, machine_id, now, baseline_id):
"some-machine-hash-1",
33,
)
HISTORY_ENTITY = _api_history_entity(
"some-benchmark-uuid-1",
"some-case-uuid-1",
"some-context-uuid-1",
)
MACHINE_ENTITY = _api_machine_entity("some-machine-uuid-1")
RUN_ENTITY = _api_run_entity(
"some-run-uuid-1",
Expand Down
48 changes: 48 additions & 0 deletions conbench/api/history.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from ..api import rule
from ..api._endpoint import ApiEndpoint
from ..entities._entity import NotFound
from ..entities.history import get_history, HistorySerializer
from ..entities.summary import Summary


class HistoryEntityAPI(ApiEndpoint):
serializer = HistorySerializer()

def _get(self, benchmark_id):
try:
summary = Summary.one(id=benchmark_id)
except NotFound:
self.abort_404_not_found()
return get_history(
summary.case_id,
summary.context_id,
summary.run.machine.hash,
)

def get(self, benchmark_id):
"""
---
description: Get benchmark history.
responses:
"200": "HistoryList"
"401": "401"
"404": "404"
parameters:
- name: benchmark_id
in: path
schema:
type: string
tags:
- History
"""
history = self._get(benchmark_id)
return self.serializer.many.dump(history)


history_entity_view = HistoryEntityAPI.as_view("history")

rule(
"/history/<benchmark_id>/",
view_func=history_entity_view,
methods=["GET"],
)
58 changes: 58 additions & 0 deletions conbench/entities/history.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from ..db import Session
from ..entities._entity import EntitySerializer
from ..entities.commit import Commit
from ..entities.machine import Machine
from ..entities.run import Run
from ..entities.summary import Summary


class _Serializer(EntitySerializer):
decimal_fmt = "{:.6f}"

def _dump(self, history):
return {
"benchmark_id": history.id,
"case_id": history.case_id,
"context_id": history.context_id,
"mean": self.decimal_fmt.format(history.mean),
"unit": history.unit,
"machine_hash": history.hash,
"sha": history.sha,
"repository": history.repository,
"message": history.message,
"timestamp": history.timestamp.isoformat(),
"run_name": history.name,
}


class HistorySerializer:
one = _Serializer()
many = _Serializer(many=True)


def get_history(case_id, context_id, machine_hash):
return (
Session.query(
Summary.id,
Summary.case_id,
Summary.context_id,
Summary.mean,
Summary.unit,
Machine.hash,
Commit.sha,
Commit.repository,
Commit.message,
Commit.timestamp,
Run.name,
)
.join(Run, Run.id == Summary.run_id)
.join(Machine, Machine.id == Run.machine_id)
.join(Commit, Commit.id == Run.commit_id)
.filter(
Summary.case_id == case_id,
Summary.context_id == context_id,
Machine.hash == machine_hash,
)
.order_by(Commit.timestamp.asc())
.all()
)
44 changes: 44 additions & 0 deletions conbench/tests/api/_expected_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,30 @@
},
"description": "OK",
},
"HistoryList": {
"content": {
"application/json": {
"example": [
[
{
"benchmark_id": "some-benchmark-uuid-1",
"case_id": "some-case-uuid-1",
"context_id": "some-context-uuid-1",
"machine_hash": "diana-2-4-17179869184",
"mean": "0.036369",
"message": "ARROW-11771: [Developer][Archery] Move benchmark tests (so CI runs them)",
"repository": "https://github.com/apache/arrow",
"run_name": "commit: 02addad336ba19a654f9c857ede546331be7b631",
"sha": "02addad336ba19a654f9c857ede546331be7b631",
"timestamp": "2021-02-25T01:02:51",
"unit": "s",
}
]
]
}
},
"description": "OK",
},
"Index": {
"content": {
"application/json": {
Expand Down Expand Up @@ -1172,6 +1196,25 @@
}
},
"/api/docs.json": {},
"/api/history/{benchmark_id}/": {
"get": {
"description": "Get benchmark history.",
"parameters": [
{
"in": "path",
"name": "benchmark_id",
"required": True,
"schema": {"type": "string"},
}
],
"responses": {
"200": {"$ref": "#/components/responses/HistoryList"},
"401": {"$ref": "#/components/responses/401"},
"404": {"$ref": "#/components/responses/404"},
},
"tags": ["History"],
}
},
"/api/login/": {
"post": {
"description": "Login with email and password.",
Expand Down Expand Up @@ -1375,6 +1418,7 @@
{"description": "Benchmark comparisons", "name": "Comparisons"},
{"description": "Benchmark contexts", "name": "Contexts"},
{"description": "Benchmark distributions", "name": "Distributions"},
{"description": "Benchmark history", "name": "History"},
{"description": "Benchmark machines", "name": "Machines"},
{"description": "Benchmark runs", "name": "Runs"},
{"description": "Monitor status", "name": "Ping"},
Expand Down
25 changes: 25 additions & 0 deletions conbench/tests/api/test_history.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from ...api._examples import _api_history_entity
from ...tests.api import _asserts
from ...tests.api import _fixtures


def _expected_entity(summary):
return _api_history_entity(
summary.id,
summary.case_id,
summary.context_id,
)[0]


class TestHistoryGet(_asserts.GetEnforcer):
url = "/api/history/{}/"
public = True

def _create(self):
return _fixtures.create_benchmark_summary()

def test_get_history(self, client):
self.authenticate(client)
summary = self._create()
response = client.get(f"/api/history/{summary.id}/")
self.assert_200_ok(response, contains=_expected_entity(summary))

0 comments on commit c526d00

Please sign in to comment.