diff --git a/reports/marathon/marathon.tar.gz b/reports/marathon/marathon.tar.gz new file mode 100644 index 0000000..64bd4a4 Binary files /dev/null and b/reports/marathon/marathon.tar.gz differ diff --git a/src/main/kotlin/fm/unit/UnitApp.kt b/src/main/kotlin/fm/unit/UnitApp.kt index c660d3f..bc0dd41 100644 --- a/src/main/kotlin/fm/unit/UnitApp.kt +++ b/src/main/kotlin/fm/unit/UnitApp.kt @@ -6,7 +6,8 @@ import fm.unit.dao.Organizations import fm.unit.dao.PayloadArgumentFactory import fm.unit.dao.Reports import fm.unit.dao.Repositories -import fm.unit.model.ProjectSummary +import fm.unit.dao.Testsuites +import fm.unit.model.Project import fm.unit.model.Report import fm.unit.model.Testsuite import io.ktor.application.Application @@ -35,6 +36,7 @@ import io.ktor.server.netty.Netty import io.ktor.velocity.Velocity import io.ktor.velocity.VelocityContent import kotlinx.coroutines.runBlocking +import mu.KotlinLogging import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader import org.jdbi.v3.core.Jdbi import org.jdbi.v3.sqlobject.kotlin.onDemand @@ -42,21 +44,9 @@ import kotlin.random.Random fun Application.module() { + val logger = KotlinLogging.logger {} - /** - * For DEBUGging purposes only. Method generates a list of fake reports to be able to test template generation locally - */ - fun testReports(random: Random = Random(1)): List { - fun summaries(random: Random): List { - return (0..random.nextInt(10)).map { - Testsuite.Summary(tests = random.nextInt(1, 10), errors = random.nextInt(2)) - } - } - - return listOf("Fake News!", "Cake Is a Lie", "Magic Unicorn").map { Report(it, summaries(random)) } - } - - fun template(summary: ProjectSummary): VelocityContent { + fun template(summary: Project.Summary): VelocityContent { val template = "templates/reports/summary.vm" val model = mutableMapOf("summary" to summary) return VelocityContent(template, model) @@ -136,14 +126,17 @@ fun Application.module() { val repository = call.parameters["repository"]!! val prefix = call.parameters["prefix"]!! - val orgId = jdbi.onDemand().read(organization) - val repoId = jdbi.onDemand().read(repository) + val orgId = runBlocking { jdbi.onDemand().read(organization) } + val repoId = runBlocking { jdbi.onDemand().read(repository) } if (orgId == null || repoId == null) { call.respond(HttpStatusCode.NotFound) } else { - val reports = testReports()// TODO(karsten): fetch from database - val summary = ProjectSummary(reports) + val reportSummaries = runBlocking { + jdbi.onDemand().readReportSummaries(orgId, repoId, prefix) + } + logger.debug { "Visualizing summaries: $reportSummaries" } + val summary = Project.Summary(reportSummaries) call.respond(template(summary)) } } @@ -163,7 +156,7 @@ fun Application.module() { val multipart = call.receiveMultipart() val (commit_hash, suites) = readPostedReport(multipart) runBlocking { - jdbi.onDemand().create(orgId, repoId, prefix, commit_hash, suites) + jdbi.onDemand().create(orgId, repoId, commit_hash, prefix, suites) } call.respond(HttpStatusCode.Created) diff --git a/src/main/kotlin/fm/unit/dao/Reports.kt b/src/main/kotlin/fm/unit/dao/Reports.kt index 6054075..6bf539f 100644 --- a/src/main/kotlin/fm/unit/dao/Reports.kt +++ b/src/main/kotlin/fm/unit/dao/Reports.kt @@ -1,5 +1,6 @@ package fm.unit.dao +import fm.unit.model.Report import fm.unit.model.Testsuite import org.jdbi.v3.sqlobject.CreateSqlObject import org.jdbi.v3.sqlobject.statement.GetGeneratedKeys @@ -48,8 +49,17 @@ interface Reports { return report_id } - - // TODO(karsten): join with testsuites. - @SqlQuery("SELECT (commit_hash) FROM reports ORDER BY report_id") - fun reports(): List + @SqlQuery(""" + SELECT reports.report_id, + SUM((xpath('count(//testcase)', payload))[1]::text::integer) AS ts_tests, + SUM((xpath('count(//failure)', payload))[1]::text::integer) AS ts_errors + FROM reports + LEFT JOIN testsuites ON reports.report_id = testsuites.report_id + WHERE reports.prefix = :prefix + AND reports.organization_id = :organization_id + AND reports.repository_id = :repository_id + GROUP BY reports.report_id + ORDER BY reports.report_id + """) + fun readReportSummaries(organization_id: Int, repository_id: Int, prefix: String): List } \ No newline at end of file diff --git a/src/main/kotlin/fm/unit/model/Project.kt b/src/main/kotlin/fm/unit/model/Project.kt new file mode 100644 index 0000000..5371998 --- /dev/null +++ b/src/main/kotlin/fm/unit/model/Project.kt @@ -0,0 +1,11 @@ +package fm.unit.model + +import fm.unit.model.Report + +object Project { + + /** + * A summary of the last n reports. + */ + data class Summary(val reports: List) +} diff --git a/src/main/kotlin/fm/unit/model/Report.kt b/src/main/kotlin/fm/unit/model/Report.kt index 4e5c153..a8448e5 100644 --- a/src/main/kotlin/fm/unit/model/Report.kt +++ b/src/main/kotlin/fm/unit/model/Report.kt @@ -1,9 +1,22 @@ package fm.unit.model +import com.sun.org.apache.xpath.internal.operations.Bool +import org.jdbi.v3.core.mapper.Nested + /** * A report belongs to a build of a repo in an organization. */ -data class Report(val prefix: String, val testsuites: List) { +data class Report(val prefix: String) { + + + /** + * A summary of the last n reports. + */ + data class Summary(val report_id: Int, @Nested("ts") val testsuiteSummary: Testsuite.Summary) { - val errors: Int = testsuites.sumBy { it.errors } + /** + * Indicates whether all testsuites succeeded. + */ + val successful: Boolean = testsuiteSummary.errors == 0 + } } diff --git a/src/main/kotlin/fm/unit/model/Summary.kt b/src/main/kotlin/fm/unit/model/Summary.kt deleted file mode 100644 index 1951ebc..0000000 --- a/src/main/kotlin/fm/unit/model/Summary.kt +++ /dev/null @@ -1,11 +0,0 @@ -package fm.unit.model - -import mu.KotlinLogging -import fm.unit.model.Report - -/** - * Summary of the project's* testsuites. - * - * * aka org/repo. - */ -data class ProjectSummary(val reports: List) diff --git a/src/main/resources/templates/reports/summary.vm b/src/main/resources/templates/reports/summary.vm index e0e2f13..c7dbd8d 100644 --- a/src/main/resources/templates/reports/summary.vm +++ b/src/main/resources/templates/reports/summary.vm @@ -10,7 +10,7 @@ #foreach($report in $summary.reports) - #set($outcome = "#if($report.errors == 0)success#{else}failure#end") + #set($outcome = "#if($report.successful)success#{else}failure#end") #set($x = $foreach.count * 10) diff --git a/src/test/kotlin/fm/unit/dao/ReportsTest.kt b/src/test/kotlin/fm/unit/dao/ReportsTest.kt index 56f3c8f..0979f11 100644 --- a/src/test/kotlin/fm/unit/dao/ReportsTest.kt +++ b/src/test/kotlin/fm/unit/dao/ReportsTest.kt @@ -5,16 +5,23 @@ import io.kotlintest.matchers.collections.shouldHaveSize import io.kotlintest.specs.StringSpec import org.jdbi.v3.sqlobject.kotlin.onDemand import fm.unit.kotlintest.listeners.JdbiFixture +import fm.unit.model.Report +import fm.unit.model.Testsuite +import io.kotlintest.matchers.collections.shouldContain import io.kotlintest.shouldBe +import java.io.File class ReportsTest: StringSpec() { // Setup database val db = JdbiFixture() override fun listeners(): List = listOf(db) + val exceptionXml = File("fixtures/exception.xml").bufferedReader().use { it.readText() } + val passXml = File("fixtures/pass.xml").bufferedReader().use { it.readText() } + init { "Reports DAO roundtrip" { - + // Given val org_dao = db.jdbi.onDemand() val org_id = org_dao.create("jeschkies") @@ -27,12 +34,37 @@ class ReportsTest: StringSpec() { repo_dao.read("unknown") shouldBe (null) repo_dao.read("unit") shouldBe (repo_id) + // When val dao = db.jdbi.onDemand() + dao.create(org_id, repo_id, "deadbeaf", "system-test") + dao.create(org_id, repo_id,"12345678", "system-test") + dao.create(org_id, repo_id,"12345678", "integration-test") + + // Then + dao.readReportSummaries(org_id, repo_id, "system-test") shouldHaveSize (2) + dao.readReportSummaries(org_id, repo_id, "integration-test") shouldHaveSize (1) + } + + "Summarize last n reports" { + // Given + val org_id = db.jdbi.onDemand().create("jeschkies") + val repo_id = db.jdbi.onDemand().create("unit") + + val reportsDao = db.jdbi.onDemand() + val suites = listOf( + Testsuite("exception.xml", Testsuite.Payload(exceptionXml)), + Testsuite("pass.xml", Testsuite.Payload(passXml)) + ) + val report_id1 = reportsDao.create(org_id, repo_id, "deadbeaf", "system-test", suites) + val report_id2 = reportsDao.create(org_id, repo_id, "12345678", "system-test", suites.takeLast(1)) - dao.create(org_id, repo_id, "deadbeaf", "/jeschkies/unit") - dao.create(org_id, repo_id,"12345678", "/jeschkies/unit") + // When + val summaries = reportsDao.readReportSummaries(org_id, repo_id, "system-test") - dao.reports() shouldHaveSize (2) + // Then + summaries shouldHaveSize (2) + summaries shouldContain (Report.Summary(report_id1, Testsuite.Summary(6, 1))) + summaries shouldContain (Report.Summary(report_id2, Testsuite.Summary(3, 0))) } } } \ No newline at end of file diff --git a/src/test/kotlin/fm/unit/dao/TestsuitesTest.kt b/src/test/kotlin/fm/unit/dao/TestsuitesTest.kt index 87819f6..beec71c 100644 --- a/src/test/kotlin/fm/unit/dao/TestsuitesTest.kt +++ b/src/test/kotlin/fm/unit/dao/TestsuitesTest.kt @@ -4,6 +4,7 @@ import fm.unit.kotlintest.listeners.JdbiFixture import fm.unit.model.Testsuite import io.kotlintest.extensions.TestListener import io.kotlintest.matchers.collections.shouldContain +import io.kotlintest.shouldBe import io.kotlintest.specs.StringSpec import java.io.File import org.jdbi.v3.sqlobject.kotlin.onDemand @@ -15,24 +16,27 @@ class TestsuitesTest: StringSpec() { override fun listeners(): List = listOf(db) + val exceptionXml = File("fixtures/exception.xml").bufferedReader().use { it.readText() } + val passXml = File("fixtures/pass.xml").bufferedReader().use { it.readText() } + init { "Testsuites DAO roundtrip" { - db.jdbi.registerArgument(PayloadArgumentFactory) - - val org_dao = db.jdbi.onDemand() - val org_id = org_dao.create("jeschkies") + // Given + val orgDao = db.jdbi.onDemand() + val org_id = orgDao.create("jeschkies") - val repo_dao = db.jdbi.onDemand() - val repo_id = repo_dao.create("unit") + val repoDao = db.jdbi.onDemand() + val repo_id = repoDao.create("unit") - val reports_dao = db.jdbi.onDemand() - val report_id = reports_dao.create(org_id, repo_id,"deadbeaf", "/jeschkies/unit") + val reportsDao = db.jdbi.onDemand() + val report_id = reportsDao.create(org_id, repo_id,"deadbeaf", "system-test") - val suite_dao = db.jdbi.onDemand() - val xmlFile = File("fixtures/exception.xml").bufferedReader().use { it.readText() } - suite_dao.create(report_id, Testsuite("exception.xml", Testsuite.Payload(xmlFile))) + // When + val suiteDao = db.jdbi.onDemand() + suiteDao.create(report_id, Testsuite("exception.xml", Testsuite.Payload(exceptionXml))) - val summaries = suite_dao.summaries() + // Then + val summaries = suiteDao.summaries() summaries shouldContain(Testsuite.Summary(3, 1)) } } diff --git a/src/test/kotlin/fm/unit/kotlintest/listeners/JdbiFixture.kt b/src/test/kotlin/fm/unit/kotlintest/listeners/JdbiFixture.kt index 59c0963..66ac3ab 100644 --- a/src/test/kotlin/fm/unit/kotlintest/listeners/JdbiFixture.kt +++ b/src/test/kotlin/fm/unit/kotlintest/listeners/JdbiFixture.kt @@ -1,7 +1,9 @@ package fm.unit.kotlintest.listeners import com.opentable.db.postgres.embedded.EmbeddedPostgres +import fm.unit.dao.PayloadArgumentFactory import io.kotlintest.Description +import io.kotlintest.Spec import io.kotlintest.TestResult import io.kotlintest.extensions.TestListener import org.flywaydb.core.Flyway @@ -20,19 +22,21 @@ class JdbiFixture : TestListener { val flyway = Flyway.configure().dataSource(dataSource).load() val jdbi: Jdbi = Jdbi.create(dataSource) - override fun beforeTest(description: Description): Unit { + override fun beforeSpec(description: Description, spec: Spec) { flyway.migrate() jdbi.installPlugins() + jdbi.registerArgument(PayloadArgumentFactory) + + super.beforeSpec(description, spec) } - override fun afterTest(description: Description, result: TestResult) { + override fun afterSpec(description: Description, spec: Spec) { try { epg.close() } catch (e: IOException) { throw AssertionError(e) } - super.afterTest(description, result) + super.afterSpec(description, spec) } - } \ No newline at end of file diff --git a/test-data.sql b/test-data.sql new file mode 100644 index 0000000..0dbe693 --- /dev/null +++ b/test-data.sql @@ -0,0 +1,386 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 10.5 +-- Dumped by pg_dump version 10.6 (Ubuntu 10.6-0ubuntu0.18.04.1) + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: +-- + +CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; + + +-- +-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; + + +SET default_tablespace = ''; + +SET default_with_oids = false; + +-- +-- Name: flyway_schema_history; Type: TABLE; Schema: public; Owner: kjeschkies +-- + +CREATE TABLE public.flyway_schema_history ( + installed_rank integer NOT NULL, + version character varying(50), + description character varying(200) NOT NULL, + type character varying(20) NOT NULL, + script character varying(1000) NOT NULL, + checksum integer, + installed_by character varying(100) NOT NULL, + installed_on timestamp without time zone DEFAULT now() NOT NULL, + execution_time integer NOT NULL, + success boolean NOT NULL +); + + +ALTER TABLE public.flyway_schema_history OWNER TO kjeschkies; + +-- +-- Name: organizations; Type: TABLE; Schema: public; Owner: kjeschkies +-- + +CREATE TABLE public.organizations ( + organization_id integer NOT NULL, + name text NOT NULL +); + + +ALTER TABLE public.organizations OWNER TO kjeschkies; + +-- +-- Name: organizations_organization_id_seq; Type: SEQUENCE; Schema: public; Owner: kjeschkies +-- + +CREATE SEQUENCE public.organizations_organization_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.organizations_organization_id_seq OWNER TO kjeschkies; + +-- +-- Name: organizations_organization_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: kjeschkies +-- + +ALTER SEQUENCE public.organizations_organization_id_seq OWNED BY public.organizations.organization_id; + + +-- +-- Name: reports; Type: TABLE; Schema: public; Owner: kjeschkies +-- + +CREATE TABLE public.reports ( + report_id integer NOT NULL, + organization_id integer, + repository_id integer, + commit_hash text NOT NULL, + prefix text NOT NULL +); + + +ALTER TABLE public.reports OWNER TO kjeschkies; + +-- +-- Name: reports_report_id_seq; Type: SEQUENCE; Schema: public; Owner: kjeschkies +-- + +CREATE SEQUENCE public.reports_report_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.reports_report_id_seq OWNER TO kjeschkies; + +-- +-- Name: reports_report_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: kjeschkies +-- + +ALTER SEQUENCE public.reports_report_id_seq OWNED BY public.reports.report_id; + + +-- +-- Name: repositories; Type: TABLE; Schema: public; Owner: kjeschkies +-- + +CREATE TABLE public.repositories ( + repository_id integer NOT NULL, + name text NOT NULL +); + + +ALTER TABLE public.repositories OWNER TO kjeschkies; + +-- +-- Name: repositories_repository_id_seq; Type: SEQUENCE; Schema: public; Owner: kjeschkies +-- + +CREATE SEQUENCE public.repositories_repository_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.repositories_repository_id_seq OWNER TO kjeschkies; + +-- +-- Name: repositories_repository_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: kjeschkies +-- + +ALTER SEQUENCE public.repositories_repository_id_seq OWNED BY public.repositories.repository_id; + + +-- +-- Name: testsuites; Type: TABLE; Schema: public; Owner: kjeschkies +-- + +CREATE TABLE public.testsuites ( + testsuite_id integer NOT NULL, + report_id integer, + filename text, + payload xml NOT NULL +); + + +ALTER TABLE public.testsuites OWNER TO kjeschkies; + +-- +-- Name: testsuites_testsuite_id_seq; Type: SEQUENCE; Schema: public; Owner: kjeschkies +-- + +CREATE SEQUENCE public.testsuites_testsuite_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.testsuites_testsuite_id_seq OWNER TO kjeschkies; + +-- +-- Name: testsuites_testsuite_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: kjeschkies +-- + +ALTER SEQUENCE public.testsuites_testsuite_id_seq OWNED BY public.testsuites.testsuite_id; + + +-- +-- Name: organizations organization_id; Type: DEFAULT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.organizations ALTER COLUMN organization_id SET DEFAULT nextval('public.organizations_organization_id_seq'::regclass); + + +-- +-- Name: reports report_id; Type: DEFAULT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.reports ALTER COLUMN report_id SET DEFAULT nextval('public.reports_report_id_seq'::regclass); + + +-- +-- Name: repositories repository_id; Type: DEFAULT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.repositories ALTER COLUMN repository_id SET DEFAULT nextval('public.repositories_repository_id_seq'::regclass); + + +-- +-- Name: testsuites testsuite_id; Type: DEFAULT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.testsuites ALTER COLUMN testsuite_id SET DEFAULT nextval('public.testsuites_testsuite_id_seq'::regclass); + + +-- +-- Data for Name: flyway_schema_history; Type: TABLE DATA; Schema: public; Owner: kjeschkies +-- + +COPY public.flyway_schema_history (installed_rank, version, description, type, script, checksum, installed_by, installed_on, execution_time, success) FROM stdin; +1 0 Boostraph SQL V0__Boostraph.sql 854922517 kjeschkies 2018-12-30 19:55:11.060933 47 t +\. + + +-- +-- Data for Name: organizations; Type: TABLE DATA; Schema: public; Owner: kjeschkies +-- + +COPY public.organizations (organization_id, name) FROM stdin; +1 jeschkies +\. + + +-- +-- Data for Name: reports; Type: TABLE DATA; Schema: public; Owner: kjeschkies +-- + +COPY public.reports (report_id, organization_id, repository_id, commit_hash, prefix) FROM stdin; +1 1 1 deafbeef system-test +2 1 1 deafbeef system-test +3 1 1 deafbeef system-test +4 1 1 deafbeef system-test +5 1 1 deafbeef system-test +6 1 1 deafbeef system-test +7 1 1 deafbeef system-test +\. + + +-- +-- Data for Name: repositories; Type: TABLE DATA; Schema: public; Owner: kjeschkies +-- + +COPY public.repositories (repository_id, name) FROM stdin; +1 unit +\. + + +-- +-- Data for Name: testsuites; Type: TABLE DATA; Schema: public; Owner: kjeschkies +-- + +COPY public.testsuites (testsuite_id, report_id, filename, payload) FROM stdin; +1 1 deadbeef.xml cli = <aiohttp.test_utils.TestClient object at 0x107342588>\n\n async def test_index(cli):\n response = await cli.get('/')\n> assert response.status == 201\nE AssertionError: assert 200 == 201\nE + where 200 = <ClientResponse(http://127.0.0.1:54359/) [200 OK]>\\n<CIMultiDictProxy('Content-Type': 'text/html; charset=utf-8', 'Content-Length': '480', 'Date': 'Mon, 18 Dec 2017 20:21:38 GMT', 'Server': 'Python/3.6 aiohttp/2.3.6')>\\n.status\n\ntests/test_app.py:13: AssertionError +2 1 exception.xml cli = <aiohttp.test_utils.TestClient object at 0x10ffdd4a8>\n\n async def test_junit_not_found(cli):\n response = await cli.get('/jeschkies/unit/commit/unknown')\n> assert response.status == 404\nE AssertionError: assert 500 == 404\nE + where 500 = <ClientResponse(http://127.0.0.1:57329/jeschkies/unit/commit/unknown) [500 Internal Server Error]>\\n<CIMultiDictProxy('...Length': '141', 'Date': 'Tue, 19 Dec 2017 18:49:51 GMT', 'Server': 'Python/3.6 aiohttp/2.3.6', 'Connection': 'close')>\\n.status\n\ntests/test_app.py:23: AssertionErrorweb_protocol.py 352 ERROR Error handling request\nTraceback (most recent call last):\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 410, in start\n resp = yield from self._request_handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web.py", line 325, in _handle\n resp = yield from handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_middlewares.py", line 93, in impl\n return (yield from handler(request))\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp_jinja2/__init__.py", line 88, in wrapped\n context = yield from coro(*args)\n File "/Users/karsten/Documents/unit/fm.unit.unitfm/main.py", line 41, in view_junit\n raw_junit = request.app['junits'][commit_sha]\nKeyError: 'unknown'\n\n +3 2 pass.xml \n\t\n\t\n\t\n\n +4 3 pass.xml \n\t\n\t\n\t\n\n +5 4 pass.xml \n\t\n\t\n\t\n\n +6 5 exception.xml cli = <aiohttp.test_utils.TestClient object at 0x10ffdd4a8>\n\n async def test_junit_not_found(cli):\n response = await cli.get('/jeschkies/unit/commit/unknown')\n> assert response.status == 404\nE AssertionError: assert 500 == 404\nE + where 500 = <ClientResponse(http://127.0.0.1:57329/jeschkies/unit/commit/unknown) [500 Internal Server Error]>\\n<CIMultiDictProxy('...Length': '141', 'Date': 'Tue, 19 Dec 2017 18:49:51 GMT', 'Server': 'Python/3.6 aiohttp/2.3.6', 'Connection': 'close')>\\n.status\n\ntests/test_app.py:23: AssertionErrorweb_protocol.py 352 ERROR Error handling request\nTraceback (most recent call last):\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 410, in start\n resp = yield from self._request_handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web.py", line 325, in _handle\n resp = yield from handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_middlewares.py", line 93, in impl\n return (yield from handler(request))\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp_jinja2/__init__.py", line 88, in wrapped\n context = yield from coro(*args)\n File "/Users/karsten/Documents/unit/fm.unit.unitfm/main.py", line 41, in view_junit\n raw_junit = request.app['junits'][commit_sha]\nKeyError: 'unknown'\n\n +7 6 exception.xml cli = <aiohttp.test_utils.TestClient object at 0x10ffdd4a8>\n\n async def test_junit_not_found(cli):\n response = await cli.get('/jeschkies/unit/commit/unknown')\n> assert response.status == 404\nE AssertionError: assert 500 == 404\nE + where 500 = <ClientResponse(http://127.0.0.1:57329/jeschkies/unit/commit/unknown) [500 Internal Server Error]>\\n<CIMultiDictProxy('...Length': '141', 'Date': 'Tue, 19 Dec 2017 18:49:51 GMT', 'Server': 'Python/3.6 aiohttp/2.3.6', 'Connection': 'close')>\\n.status\n\ntests/test_app.py:23: AssertionErrorweb_protocol.py 352 ERROR Error handling request\nTraceback (most recent call last):\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 410, in start\n resp = yield from self._request_handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web.py", line 325, in _handle\n resp = yield from handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_middlewares.py", line 93, in impl\n return (yield from handler(request))\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp_jinja2/__init__.py", line 88, in wrapped\n context = yield from coro(*args)\n File "/Users/karsten/Documents/unit/fm.unit.unitfm/main.py", line 41, in view_junit\n raw_junit = request.app['junits'][commit_sha]\nKeyError: 'unknown'\n\n +8 7 deadbeef.xml cli = <aiohttp.test_utils.TestClient object at 0x107342588>\n\n async def test_index(cli):\n response = await cli.get('/')\n> assert response.status == 201\nE AssertionError: assert 200 == 201\nE + where 200 = <ClientResponse(http://127.0.0.1:54359/) [200 OK]>\\n<CIMultiDictProxy('Content-Type': 'text/html; charset=utf-8', 'Content-Length': '480', 'Date': 'Mon, 18 Dec 2017 20:21:38 GMT', 'Server': 'Python/3.6 aiohttp/2.3.6')>\\n.status\n\ntests/test_app.py:13: AssertionError +9 7 exception.xml cli = <aiohttp.test_utils.TestClient object at 0x10ffdd4a8>\n\n async def test_junit_not_found(cli):\n response = await cli.get('/jeschkies/unit/commit/unknown')\n> assert response.status == 404\nE AssertionError: assert 500 == 404\nE + where 500 = <ClientResponse(http://127.0.0.1:57329/jeschkies/unit/commit/unknown) [500 Internal Server Error]>\\n<CIMultiDictProxy('...Length': '141', 'Date': 'Tue, 19 Dec 2017 18:49:51 GMT', 'Server': 'Python/3.6 aiohttp/2.3.6', 'Connection': 'close')>\\n.status\n\ntests/test_app.py:23: AssertionErrorweb_protocol.py 352 ERROR Error handling request\nTraceback (most recent call last):\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 410, in start\n resp = yield from self._request_handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web.py", line 325, in _handle\n resp = yield from handler(request)\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp/web_middlewares.py", line 93, in impl\n return (yield from handler(request))\n File "/Users/karsten/.local/share/virtualenvs/unit-fFY_xGcI/lib/python3.6/site-packages/aiohttp_jinja2/__init__.py", line 88, in wrapped\n context = yield from coro(*args)\n File "/Users/karsten/Documents/unit/fm.unit.unitfm/main.py", line 41, in view_junit\n raw_junit = request.app['junits'][commit_sha]\nKeyError: 'unknown'\n\n +\. + + +-- +-- Name: organizations_organization_id_seq; Type: SEQUENCE SET; Schema: public; Owner: kjeschkies +-- + +SELECT pg_catalog.setval('public.organizations_organization_id_seq', 1, true); + + +-- +-- Name: reports_report_id_seq; Type: SEQUENCE SET; Schema: public; Owner: kjeschkies +-- + +SELECT pg_catalog.setval('public.reports_report_id_seq', 7, true); + + +-- +-- Name: repositories_repository_id_seq; Type: SEQUENCE SET; Schema: public; Owner: kjeschkies +-- + +SELECT pg_catalog.setval('public.repositories_repository_id_seq', 1, true); + + +-- +-- Name: testsuites_testsuite_id_seq; Type: SEQUENCE SET; Schema: public; Owner: kjeschkies +-- + +SELECT pg_catalog.setval('public.testsuites_testsuite_id_seq', 9, true); + + +-- +-- Name: flyway_schema_history flyway_schema_history_pk; Type: CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.flyway_schema_history + ADD CONSTRAINT flyway_schema_history_pk PRIMARY KEY (installed_rank); + + +-- +-- Name: organizations organizations_pkey; Type: CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.organizations + ADD CONSTRAINT organizations_pkey PRIMARY KEY (organization_id); + + +-- +-- Name: reports reports_pkey; Type: CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.reports + ADD CONSTRAINT reports_pkey PRIMARY KEY (report_id); + + +-- +-- Name: repositories repositories_pkey; Type: CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.repositories + ADD CONSTRAINT repositories_pkey PRIMARY KEY (repository_id); + + +-- +-- Name: testsuites testsuites_pkey; Type: CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.testsuites + ADD CONSTRAINT testsuites_pkey PRIMARY KEY (testsuite_id); + + +-- +-- Name: flyway_schema_history_s_idx; Type: INDEX; Schema: public; Owner: kjeschkies +-- + +CREATE INDEX flyway_schema_history_s_idx ON public.flyway_schema_history USING btree (success); + + +-- +-- Name: reports reports_organization_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.reports + ADD CONSTRAINT reports_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES public.organizations(organization_id); + + +-- +-- Name: reports reports_repository_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.reports + ADD CONSTRAINT reports_repository_id_fkey FOREIGN KEY (repository_id) REFERENCES public.repositories(repository_id); + + +-- +-- Name: testsuites testsuites_report_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: kjeschkies +-- + +ALTER TABLE ONLY public.testsuites + ADD CONSTRAINT testsuites_report_id_fkey FOREIGN KEY (report_id) REFERENCES public.reports(report_id); + + +-- +-- PostgreSQL database dump complete +-- +