From a8b1a3c8cebdc79888a63ec3a0a20e5e3829506b Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 7 Aug 2023 23:18:25 +0100 Subject: [PATCH 01/12] Add base code --- res/MessageBus.drawio | 81 ++++++++++++ res/MessageBus.png | Bin 0 -> 28301 bytes res/MessageBus.txt | 66 ++++++++++ res/TestCaseStatus.ndjson | 5 + src/KiBoards.Tests/KiBoards.Tests.csproj | 31 +++++ src/KiBoards.Tests/UnitTest1.cs | 48 ++++++++ src/KiBoards.Tests/UnitTest2.cs | 51 ++++++++ src/KiBoards.Tests/Usings.cs | 1 + src/KiBoards.sln | 18 ++- src/KiBoards/Class1.cs | 7 -- src/KiBoards/Framework/TestAssemblyRunner.cs | 44 +++++++ src/KiBoards/Framework/TestClassRunner.cs | 26 ++++ .../Framework/TestCollectionRunner.cs | 21 ++++ src/KiBoards/Framework/TestContextMessage.cs | 16 +++ .../Framework/TestFrameworkExecutor.cs | 33 +++++ src/KiBoards/Framework/TestMessageBus.cs | 116 ++++++++++++++++++ src/KiBoards/Framework/TestMessageSink.cs | 106 ++++++++++++++++ src/KiBoards/Framework/TestMethodRunner.cs | 42 +++++++ src/KiBoards/KiBoards.csproj | 14 +-- .../Models/KiBoardsModelsExtensions.cs | 37 ++++++ src/KiBoards/Models/KiBoardsTestCaseState.cs | 8 ++ src/KiBoards/Models/KiBoardsTestCaseStatus.cs | 11 ++ .../Models/KiBoardsTestCaseStatusDto.cs | 13 ++ src/KiBoards/Models/KiBoardsTestClassDto.cs | 10 ++ src/KiBoards/Models/KiBoardsTestMethodDto.cs | 8 ++ .../Models/KiBoardsTestMethodInfoDto.cs | 8 ++ .../Services/IKiBoardsElasticService.cs | 11 ++ .../Services/IKiBoardsTestRunnerService.cs | 16 +++ .../Services/KiBoardsElasticService.cs | 54 ++++++++ .../KiBoardsElasticServiceExtensions.cs | 28 +++++ .../Services/KiBoardsTestRunnerService.cs | 77 ++++++++++++ src/KiBoards/TestContextFixture.cs | 20 +++ src/KiBoards/TestExtensions.cs | 22 ++++ src/KiBoards/TestFramework.cs | 40 ++++++ 34 files changed, 1069 insertions(+), 20 deletions(-) create mode 100644 res/MessageBus.drawio create mode 100644 res/MessageBus.png create mode 100644 res/MessageBus.txt create mode 100644 res/TestCaseStatus.ndjson create mode 100644 src/KiBoards.Tests/KiBoards.Tests.csproj create mode 100644 src/KiBoards.Tests/UnitTest1.cs create mode 100644 src/KiBoards.Tests/UnitTest2.cs create mode 100644 src/KiBoards.Tests/Usings.cs delete mode 100644 src/KiBoards/Class1.cs create mode 100644 src/KiBoards/Framework/TestAssemblyRunner.cs create mode 100644 src/KiBoards/Framework/TestClassRunner.cs create mode 100644 src/KiBoards/Framework/TestCollectionRunner.cs create mode 100644 src/KiBoards/Framework/TestContextMessage.cs create mode 100644 src/KiBoards/Framework/TestFrameworkExecutor.cs create mode 100644 src/KiBoards/Framework/TestMessageBus.cs create mode 100644 src/KiBoards/Framework/TestMessageSink.cs create mode 100644 src/KiBoards/Framework/TestMethodRunner.cs create mode 100644 src/KiBoards/Models/KiBoardsModelsExtensions.cs create mode 100644 src/KiBoards/Models/KiBoardsTestCaseState.cs create mode 100644 src/KiBoards/Models/KiBoardsTestCaseStatus.cs create mode 100644 src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs create mode 100644 src/KiBoards/Models/KiBoardsTestClassDto.cs create mode 100644 src/KiBoards/Models/KiBoardsTestMethodDto.cs create mode 100644 src/KiBoards/Models/KiBoardsTestMethodInfoDto.cs create mode 100644 src/KiBoards/Services/IKiBoardsElasticService.cs create mode 100644 src/KiBoards/Services/IKiBoardsTestRunnerService.cs create mode 100644 src/KiBoards/Services/KiBoardsElasticService.cs create mode 100644 src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs create mode 100644 src/KiBoards/Services/KiBoardsTestRunnerService.cs create mode 100644 src/KiBoards/TestContextFixture.cs create mode 100644 src/KiBoards/TestExtensions.cs create mode 100644 src/KiBoards/TestFramework.cs diff --git a/res/MessageBus.drawio b/res/MessageBus.drawio new file mode 100644 index 0000000..e4da87a --- /dev/null +++ b/res/MessageBus.drawio @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/MessageBus.png b/res/MessageBus.png new file mode 100644 index 0000000000000000000000000000000000000000..1f0d1214b58f9bf5a5f24b7c61137a8cb098a34b GIT binary patch literal 28301 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 PBhyybS1VJ2U;n=Vnlq8N literal 0 HcmV?d00001 diff --git a/res/MessageBus.txt b/res/MessageBus.txt new file mode 100644 index 0000000..d530433 --- /dev/null +++ b/res/MessageBus.txt @@ -0,0 +1,66 @@ +[xUnit.net 00:00:02.64] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodStarting + +[xUnit.net 00:00:02.67] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseStarting +[xUnit.net 00:00:02.67] KiBoards.Tests: MessageBus: Xunit.Sdk.TestStarting +[xUnit.net 00:00:02.67] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionStarting +[xUnit.net 00:00:02.67] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionFinished +[xUnit.net 00:00:02.68] KiBoards.Tests: MessageBus: Xunit.Sdk.TestPassed +[xUnit.net 00:00:02.68] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFinished +[xUnit.net 00:00:02.68] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseFinished + +[xUnit.net 00:00:02.71] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseStarting +[xUnit.net 00:00:02.71] KiBoards.Tests: MessageBus: Xunit.Sdk.TestStarting +[xUnit.net 00:00:02.71] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionStarting +[xUnit.net 00:00:02.71] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionFinished +[xUnit.net 00:00:02.72] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFailed +[xUnit.net 00:00:02.72] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFinished +[xUnit.net 00:00:02.72] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseFinished + +[xUnit.net 00:00:02.73] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseStarting +[xUnit.net 00:00:02.73] KiBoards.Tests: MessageBus: Xunit.Sdk.TestStarting +[xUnit.net 00:00:02.73] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionStarting +[xUnit.net 00:00:02.73] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionFinished + +[xUnit.net 00:00:02.73] KiBoards.Tests: MessageBus: Xunit.Sdk.TestPassed +[xUnit.net 00:00:02.73] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFinished + +[xUnit.net 00:00:02.73] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseFinished + +[xUnit.net 00:00:02.74] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodFinished + + +[xUnit.net 00:00:02.74] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodStarting +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseStarting +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestStarting +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionStarting +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionFinished + +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestPassed +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFinished + +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseFinished +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodFinished + +[xUnit.net 00:00:02.75] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodStarting +[xUnit.net 00:00:02.76] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseStarting +[xUnit.net 00:00:02.76] KiBoards.Tests: MessageBus: Xunit.Sdk.TestStarting +[xUnit.net 00:00:02.76] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionStarting +[xUnit.net 00:00:02.76] KiBoards.Tests: MessageBus: Xunit.Sdk.TestClassConstructionFinished + +[xUnit.net 00:00:02.76] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFailed +[xUnit.net 00:00:02.76] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFinished + +[xUnit.net 00:00:02.76] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseFinished +[xUnit.net 00:00:02.77] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodFinished + +[xUnit.net 00:00:02.77] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodStarting +[xUnit.net 00:00:02.77] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseStarting +[xUnit.net 00:00:02.77] KiBoards.Tests: MessageBus: Xunit.Sdk.TestStarting + +[xUnit.net 00:00:02.77] KiBoards.Tests: MessageBus: Xunit.Sdk.TestSkipped +[xUnit.net 00:00:02.77] KiBoards.Tests: MessageBus: Xunit.Sdk.TestFinished + +[xUnit.net 00:00:02.77] KiBoards.Tests: MessageBus: Xunit.Sdk.TestCaseFinished +[xUnit.net 00:00:02.78] KiBoards.Tests: MessageBus: Xunit.Sdk.TestMethodFinished + +Failed! - Failed: 2, Passed: 3, Skipped: 1, Total: 6, Duration: 85 ms - KiBoards.Tests.dll (net7.0) diff --git a/res/TestCaseStatus.ndjson b/res/TestCaseStatus.ndjson new file mode 100644 index 0000000..3044bf3 --- /dev/null +++ b/res/TestCaseStatus.ndjson @@ -0,0 +1,5 @@ +{"attributes":{"fieldAttrs":"{\"displayName\":{\"count\":2},\"state\":{\"count\":1},\"uniqueId\":{\"customLabel\":\"Id\",\"count\":1},\"status\":{\"customLabel\":\"Status\",\"count\":1},\"summary.time\":{\"count\":1}}","fieldFormatMap":"{\"status\":{\"id\":\"color\",\"params\":{\"parsedUrl\":{\"origin\":\"http://localhost:5601\",\"pathname\":\"/app/home\",\"basePath\":\"\"},\"fieldType\":\"string\",\"colors\":[{\"range\":\"-Infinity:Infinity\",\"regex\":\"Success\",\"text\":\"#459b83\",\"background\":\"#ffffff\"},{\"range\":\"-Infinity:Infinity\",\"regex\":\"Failure\",\"text\":\"#E7664C\",\"background\":\"#ffffff\"},{\"range\":\"-Infinity:Infinity\",\"regex\":\"Skipped\",\"text\":\"#D6BF57\",\"background\":\"#ffffff\"}]}}}","fields":"[]","name":"Test Case Status View","runtimeFieldMap":"{}","sourceFilters":"[]","timeFieldName":"","title":"kiboards-testcase-status-*","typeMeta":"{}"},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T21:26:05.088Z","id":"641b8927-249c-4669-9dea-a6bf989c8556","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2023-08-06T22:47:01.692Z","version":"WzM2NSwxXQ=="} +{"attributes":{"columns":["uniqueId","status","displayName"],"description":"","grid":{"columns":{"status":{"width":86},"uniqueId":{"width":313}}},"hideChart":false,"isTextBasedQuery":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"rowHeight":-1,"sort":[],"timeRestore":false,"title":"Test Case Status Search","usesAdHocDataView":false,"viewMode":"documents"},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T22:24:20.672Z","id":"fd2b4c00-34a7-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","typeMigrationVersion":"8.0.0","updated_at":"2023-08-06T22:46:19.042Z","version":"WzM2MywxXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"8.8.2\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":29,\"i\":\"f0134ca4-cbcd-483e-9107-6e93fba7de2f\"},\"panelIndex\":\"f0134ca4-cbcd-483e-9107-6e93fba7de2f\",\"embeddableConfig\":{\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Details\",\"panelRefName\":\"panel_f0134ca4-cbcd-483e-9107-6e93fba7de2f\"}]","timeRestore":false,"title":"Test Case Details","version":1},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T22:43:57.280Z","id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"fd2b4c00-34a7-11ee-8f8e-e312ee55ca24","name":"f0134ca4-cbcd-483e-9107-6e93fba7de2f:panel_f0134ca4-cbcd-483e-9107-6e93fba7de2f","type":"search"}],"type":"dashboard","typeMigrationVersion":"8.7.0","updated_at":"2023-08-06T22:43:57.280Z","version":"WzM1MiwxXQ=="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":8,\"h\":6,\"i\":\"10c370c6-5da2-4507-ad86-af1119649a69\"},\"panelIndex\":\"10c370c6-5da2-4507-ad86-af1119649a69\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":1},{\"color\":\"#343741\",\"stop\":20}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#343741\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Total\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":8,\"y\":0,\"w\":8,\"h\":6,\"i\":\"0b4751ed-1f30-4405-9801-1ccf24a0b956\"},\"panelIndex\":\"0b4751ed-1f30-4405-9801-1ccf24a0b956\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":20},{\"color\":\"#6d7482\",\"stop\":50},{\"color\":\"#343741\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#6d7482\",\"stop\":20},{\"color\":\"#343741\",\"stop\":50}]}},\"titlePosition\":\"top\",\"size\":\"l\",\"textAlign\":\"center\"},\"query\":{\"query\":\"status.keyword : \\\"Discovered\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Discovered\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":16,\"y\":0,\"w\":8,\"h\":6,\"i\":\"408ce981-f6e4-48c8-85c0-78231aa10b65\"},\"panelIndex\":\"408ce981-f6e4-48c8-85c0-78231aa10b65\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":20},{\"color\":\"#6d7482\",\"stop\":50},{\"color\":\"#343741\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#6d7482\",\"stop\":20},{\"color\":\"#343741\",\"stop\":50}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Running\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Running\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"Running\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":8,\"h\":6,\"i\":\"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7\"},\"panelIndex\":\"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#00000054\",\"stop\":1},{\"color\":\"#209280\",\"stop\":18}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#00000054\",\"stop\":0},{\"color\":\"#209280\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Success\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Success\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":32,\"y\":0,\"w\":8,\"h\":6,\"i\":\"446f37b5-2f7f-4814-8d3f-f7b1cae9e007\"},\"panelIndex\":\"446f37b5-2f7f-4814-8d3f-f7b1cae9e007\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#27987e\",\"stop\":1},{\"color\":\"#E7664C\",\"stop\":18}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#27987e\",\"stop\":0},{\"color\":\"#E7664C\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Failure\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Failure\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":40,\"y\":0,\"w\":8,\"h\":6,\"i\":\"f33640a2-03d3-4cb8-9514-ac7eddb8342c\"},\"panelIndex\":\"f33640a2-03d3-4cb8-9514-ac7eddb8342c\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#0000003b\",\"stop\":1},{\"color\":\"#D6BF57\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#0000003b\",\"stop\":0},{\"color\":\"#D6BF57\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Skipped\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Skipped\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":6,\"w\":24,\"h\":15,\"i\":\"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5\"},\"panelIndex\":\"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Test Cases\",\"description\":\"\",\"visualizationType\":\"lnsPie\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"shape\":\"donut\",\"palette\":{\"type\":\"palette\",\"name\":\"positive\"},\"layers\":[{\"layerId\":\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"primaryGroups\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\"],\"metrics\":[\"742e3600-35ca-4446-aac6-519f26cb3b13\"],\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"hide\",\"nestedLegend\":false,\"layerType\":\"data\",\"emptySizeRatio\":0.54,\"truncateLegend\":true,\"legendPosition\":\"left\",\"allowMultipleMetrics\":false}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\":{\"columns\":{\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\":{\"label\":\"Top 6 values of status.keyword\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"status.keyword\",\"isBucketed\":true,\"params\":{\"size\":6,\"orderBy\":{\"type\":\"column\",\"columnId\":\"742e3600-35ca-4446-aac6-519f26cb3b13\"},\"orderDirection\":\"asc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}},\"742e3600-35ca-4446-aac6-519f26cb3b13\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"742e3600-35ca-4446-aac6-519f26cb3b13\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"bf63f130-7338-4092-ba4d-8b2b9a9d478c\",\"triggers\":[\"FILTER_TRIGGER\"],\"action\":{\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\",\"name\":\"Go to test case details...\",\"config\":{\"useCurrentFilters\":true,\"useCurrentDateRange\":false,\"openInNewTab\":false}}}]}},\"hidePanelTitles\":true}},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":6,\"w\":24,\"h\":15,\"i\":\"d0939bca-79c1-4c67-bdd6-51c445abcf56\"},\"panelIndex\":\"d0939bca-79c1-4c67-bdd6-51c445abcf56\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Test Cases\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":false,\"position\":\"bottom\",\"showSingleSeries\":false,\"isInside\":false,\"shouldTruncate\":false},\"valueLabels\":\"show\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":false,\"yLeft\":false,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":false,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":false,\"yLeft\":false,\"yRight\":true},\"preferredSeriesType\":\"bar_horizontal_stacked\",\"layers\":[{\"layerId\":\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"seriesType\":\"bar_horizontal_stacked\",\"xAccessor\":\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"accessors\":[\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"64851214-2c34-44e3-838b-0af27323929b\",\"56018286-5231-4400-8d02-7653525b322a\",\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"2724574b-d6f9-4f13-8eb0-646a4b863619\"],\"yConfig\":[{\"forAccessor\":\"64851214-2c34-44e3-838b-0af27323929b\",\"color\":\"#54b399\"},{\"forAccessor\":\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"color\":\"#e7664c\"},{\"forAccessor\":\"56018286-5231-4400-8d02-7653525b322a\",\"color\":\"#d6bf57\"},{\"forAccessor\":\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"color\":\"#aaaaaa\",\"axisMode\":\"auto\"},{\"forAccessor\":\"2724574b-d6f9-4f13-8eb0-646a4b863619\",\"color\":\"#cccccc\"}],\"layerType\":\"data\"}],\"yLeftExtent\":{\"mode\":\"full\",\"niceValues\":false}},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\":{\"columns\":{\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\":{\"label\":\"Status\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"status.keyword\",\"isBucketed\":true,\"params\":{\"size\":6,\"orderBy\":{\"type\":\"custom\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"orderAgg\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}},\"secondaryFields\":[]},\"customLabel\":true},\"742e3600-35ca-4446-aac6-519f26cb3b13\":{\"label\":\"Failure\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0}}},\"customLabel\":true,\"filter\":{\"query\":\"status.keyword : \\\"Failure\\\" \",\"language\":\"kuery\"}},\"64851214-2c34-44e3-838b-0af27323929b\":{\"label\":\"Success\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Success\\\" \",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"56018286-5231-4400-8d02-7653525b322a\":{\"label\":\"Skipped\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Skipped\\\"\",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\":{\"label\":\"Running\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Running\\\"\",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2724574b-d6f9-4f13-8eb0-646a4b863619\":{\"label\":\"Discovered\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Discovered\\\" \",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true}},\"columnOrder\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"64851214-2c34-44e3-838b-0af27323929b\",\"56018286-5231-4400-8d02-7653525b322a\",\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"2724574b-d6f9-4f13-8eb0-646a4b863619\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"2b53c149-d516-401e-a487-c6efda1ade02\",\"triggers\":[\"FILTER_TRIGGER\"],\"action\":{\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\",\"name\":\"Go to test case details...\",\"config\":{\"useCurrentFilters\":true,\"useCurrentDateRange\":false,\"openInNewTab\":false}}}]}},\"hidePanelTitles\":true},\"title\":\"\"}]","timeRestore":false,"title":"Test Case Status","version":1},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T22:39:40.297Z","id":"1b934de0-34a9-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"10c370c6-5da2-4507-ad86-af1119649a69:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"0b4751ed-1f30-4405-9801-1ccf24a0b956:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"408ce981-f6e4-48c8-85c0-78231aa10b65:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"446f37b5-2f7f-4814-8d3f-f7b1cae9e007:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"f33640a2-03d3-4cb8-9514-ac7eddb8342c:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5:indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216","type":"index-pattern"},{"id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","name":"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:bf63f130-7338-4092-ba4d-8b2b9a9d478c:dashboardId","type":"dashboard"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"d0939bca-79c1-4c67-bdd6-51c445abcf56:indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216","type":"index-pattern"},{"id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","name":"d0939bca-79c1-4c67-bdd6-51c445abcf56:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:2b53c149-d516-401e-a487-c6efda1ade02:dashboardId","type":"dashboard"}],"type":"dashboard","typeMigrationVersion":"8.7.0","updated_at":"2023-08-06T22:39:40.297Z","version":"WzMzMiwxXQ=="} +{"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":4,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file diff --git a/src/KiBoards.Tests/KiBoards.Tests.csproj b/src/KiBoards.Tests/KiBoards.Tests.csproj new file mode 100644 index 0000000..95900e8 --- /dev/null +++ b/src/KiBoards.Tests/KiBoards.Tests.csproj @@ -0,0 +1,31 @@ + + + + net7.0 + enable + enable + en + ..\..\bin + false + true + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/src/KiBoards.Tests/UnitTest1.cs b/src/KiBoards.Tests/UnitTest1.cs new file mode 100644 index 0000000..3d6cfa7 --- /dev/null +++ b/src/KiBoards.Tests/UnitTest1.cs @@ -0,0 +1,48 @@ +using Xunit; +using Xunit.Sdk; + +[assembly: TestFramework("KiBoards.TestFramework", "KiBoards")] + +namespace KiBoards.Tests +{ + + public class UnitTest1 : IClassFixture + { + TestContextFixture _kiboards; + + public UnitTest1(TestContextFixture testContextFixture) + { + _kiboards = testContextFixture; + + _kiboards.SetContext(new { Version = "12345" }); + } + + [Fact] + public void Test1() + { + _kiboards.SetContext(new { Version = "12345" }); + + Thread.Sleep(1000); + } + + [Fact] + public void Test2() + { + Assert.Equal(1, 2); + } + + + [Fact] + public void Test3() + { + throw new NotImplementedException(); + } + + [Fact(Skip = "Not required.")] + public void Test4() + { + + } + + } +} \ No newline at end of file diff --git a/src/KiBoards.Tests/UnitTest2.cs b/src/KiBoards.Tests/UnitTest2.cs new file mode 100644 index 0000000..b797867 --- /dev/null +++ b/src/KiBoards.Tests/UnitTest2.cs @@ -0,0 +1,51 @@ + +using Microsoft.VisualStudio.TestPlatform.Utilities; +using System.Reflection; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Tests +{ + + public class UnitTest2 : IClassFixture + { + + public UnitTest2(TestContextFixture testContextFixture, ITestOutputHelper outputHelper) + { + // This is how to get messageBus + + outputHelper.SetContext(new { Version = "1234" }); + + outputHelper.WriteLine("HELLO WORLD MESSAGE BUS"); + } + + [Fact(Timeout = 1000)] + public void Test5() + { + Thread.Sleep(5000); + } + + [Theory] + [InlineData(1, 2)] + [InlineData(2, 2)] + [InlineData(3, 3)] + public void Test6(int a, int b) + { + Assert.Equal(a, b); + } + + + [Fact] + public void Test7() + { + throw new NotImplementedException(); + } + + [Fact(Skip = "Not required.")] + public void Test8() + { + + } + + } +} \ No newline at end of file diff --git a/src/KiBoards.Tests/Usings.cs b/src/KiBoards.Tests/Usings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/src/KiBoards.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/src/KiBoards.sln b/src/KiBoards.sln index 43d734a..dbc6024 100644 --- a/src/KiBoards.sln +++ b/src/KiBoards.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.33516.290 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FDCEF06B-A89A-43CC-B505-4608DF29BBF7}") = "KiBoards", "KiBoards\KiBoards.csproj", "{5DC70E65-1093-4D72-9129-F0FFE3AF5151}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KiBoards", "KiBoards\KiBoards.csproj", "{644D75DA-7457-4DC2-AD9B-2376A7C20BC1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KiBoards.Tests", "KiBoards.Tests\KiBoards.Tests.csproj", "{BD23E63C-CC78-4714-A319-E492CC90178A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,15 +13,19 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5DC70E65-1093-4D72-9129-F0FFE3AF5151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5DC70E65-1093-4D72-9129-F0FFE3AF5151}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5DC70E65-1093-4D72-9129-F0FFE3AF5151}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5DC70E65-1093-4D72-9129-F0FFE3AF5151}.Release|Any CPU.Build.0 = Release|Any CPU + {644D75DA-7457-4DC2-AD9B-2376A7C20BC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {644D75DA-7457-4DC2-AD9B-2376A7C20BC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {644D75DA-7457-4DC2-AD9B-2376A7C20BC1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {644D75DA-7457-4DC2-AD9B-2376A7C20BC1}.Release|Any CPU.Build.0 = Release|Any CPU + {BD23E63C-CC78-4714-A319-E492CC90178A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD23E63C-CC78-4714-A319-E492CC90178A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD23E63C-CC78-4714-A319-E492CC90178A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD23E63C-CC78-4714-A319-E492CC90178A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {58F0F7CE-57BF-43A9-8390-A15E0C1A9A66} + SolutionGuid = {F7A87B3B-2908-4E34-AC90-13E68B977B90} EndGlobalSection EndGlobal diff --git a/src/KiBoards/Class1.cs b/src/KiBoards/Class1.cs deleted file mode 100644 index 16e7b85..0000000 --- a/src/KiBoards/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace KiBoards -{ - public class Class1 - { - - } -} \ No newline at end of file diff --git a/src/KiBoards/Framework/TestAssemblyRunner.cs b/src/KiBoards/Framework/TestAssemblyRunner.cs new file mode 100644 index 0000000..e491107 --- /dev/null +++ b/src/KiBoards/Framework/TestAssemblyRunner.cs @@ -0,0 +1,44 @@ +using Xunit.Abstractions; +using Xunit.Sdk; +using KiBoards.Services; +using System.Reflection; + +namespace KiBoards.Framework +{ + internal class TestAssemblyRunner : XunitTestAssemblyRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + private readonly IMessageSink _messageSink; + + public TestAssemblyRunner(ITestAssembly testAssembly, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions, IKiBoardsTestRunnerService testRunner) + : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) + { + _testRunner = testRunner; + _messageSink = diagnosticMessageSink; + } + + protected override async Task RunTestCollectionAsync(IMessageBus messageBus, ITestCollection testCollection, IEnumerable testCases, CancellationTokenSource cancellationTokenSource) + { + var collectionRunner = new TestCollectionRunner(testCollection, testCases, DiagnosticMessageSink, messageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource, _testRunner); + return await collectionRunner.RunAsync(); + } + + protected override IMessageBus CreateMessageBus() + { + _messageSink.OnMessage(new DiagnosticMessage("Creating MessageBus")); + return new TestMessageBus(base.CreateMessageBus(), _messageSink); + } + + protected override string GetTestFrameworkDisplayName() + { + var version = Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion; + return $"KiBoards {version}"; + } + + protected override Task BeforeTestAssemblyFinishedAsync() + { + _messageSink.OnMessage(new DiagnosticMessage("BeforeTestAssemblyFinishedAsync")); + return base.BeforeTestAssemblyFinishedAsync(); + } + } +} diff --git a/src/KiBoards/Framework/TestClassRunner.cs b/src/KiBoards/Framework/TestClassRunner.cs new file mode 100644 index 0000000..6494609 --- /dev/null +++ b/src/KiBoards/Framework/TestClassRunner.cs @@ -0,0 +1,26 @@ +using Xunit.Abstractions; +using Xunit.Sdk; +using KiBoards.Services; + +namespace KiBoards.Framework +{ + internal class TestClassRunner : XunitTestClassRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + + public TestClassRunner(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IDictionary collectionFixtureMappings, IKiBoardsTestRunnerService testRunner) + : base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings) + { + _testRunner = testRunner; + } + + protected override Task RunTestMethodAsync(ITestMethod testMethod, IReflectionMethodInfo method, IEnumerable testCases, object[] constructorArguments) + => new TestMethodRunner(testMethod, Class, method, testCases, DiagnosticMessageSink, MessageBus, new ExceptionAggregator(Aggregator), CancellationTokenSource, constructorArguments, _testRunner) + .RunAsync(); + + protected override async Task RunTestMethodsAsync() + { + return await base.RunTestMethodsAsync(); + } + } +} diff --git a/src/KiBoards/Framework/TestCollectionRunner.cs b/src/KiBoards/Framework/TestCollectionRunner.cs new file mode 100644 index 0000000..e15da67 --- /dev/null +++ b/src/KiBoards/Framework/TestCollectionRunner.cs @@ -0,0 +1,21 @@ +using Xunit.Abstractions; +using Xunit.Sdk; +using KiBoards.Services; + +namespace KiBoards.Framework +{ + internal class TestCollectionRunner : XunitTestCollectionRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + + public TestCollectionRunner(ITestCollection testCollection, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IKiBoardsTestRunnerService testRunner) + : base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) + { + _testRunner = testRunner; + } + + protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) + => new TestClassRunner(testClass, @class, testCases, DiagnosticMessageSink, MessageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource, CollectionFixtureMappings, _testRunner) + .RunAsync(); + } +} diff --git a/src/KiBoards/Framework/TestContextMessage.cs b/src/KiBoards/Framework/TestContextMessage.cs new file mode 100644 index 0000000..f9c21e8 --- /dev/null +++ b/src/KiBoards/Framework/TestContextMessage.cs @@ -0,0 +1,16 @@ +using Xunit.Abstractions; + +namespace KiBoards.Framework +{ + internal class TestContextMessage : IMessageSinkMessage, IExecutionMessage + { + public object Context { get; set; } + + public IEnumerable TestCases => throw new NotImplementedException(); + + public TestContextMessage(object context) + { + Context = context; + } + } +} diff --git a/src/KiBoards/Framework/TestFrameworkExecutor.cs b/src/KiBoards/Framework/TestFrameworkExecutor.cs new file mode 100644 index 0000000..2b8fc35 --- /dev/null +++ b/src/KiBoards/Framework/TestFrameworkExecutor.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using KiBoards.Services; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Framework +{ + internal class TestFrameworkExecutor : XunitTestFrameworkExecutor + { + private readonly IKiBoardsTestRunnerService _testRunner; + + public TestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink, IKiBoardsTestRunnerService testRunner) + : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) + { + _testRunner = testRunner; + } + + protected override async void RunTestCases(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) + { + try + { + await _testRunner.BeginTestCasesRunAsync(testCases); + using var assemblyRunner = new TestAssemblyRunner(TestAssembly, testCases, new TestMessageSink(DiagnosticMessageSink), executionMessageSink, executionOptions, _testRunner); + var results = await assemblyRunner.RunAsync(); + await _testRunner.EndTestCasesRunAsync(results); + } + catch (Exception ex) + { + await _testRunner.ErrorTestCasesRunAsync(testCases, ex); + } + } + } +} diff --git a/src/KiBoards/Framework/TestMessageBus.cs b/src/KiBoards/Framework/TestMessageBus.cs new file mode 100644 index 0000000..0291a02 --- /dev/null +++ b/src/KiBoards/Framework/TestMessageBus.cs @@ -0,0 +1,116 @@ +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Framework +{ + internal class TestMessageBus : IMessageBus + { + private IMessageBus _messageBus; + private IMessageSink _messageSink; + + public TestMessageBus(IMessageBus messageBus, IMessageSink messageSink) + { + _messageBus = messageBus; + _messageSink = messageSink; + } + + public void Dispose() + { + _messageBus.Dispose(); + } + + private void LogMessage(string message) + { + _messageSink.OnMessage(new DiagnosticMessage(message)); + } + + private void LogTestCase(string messageType, ITestCase testCase) + { + LogMessage($"{messageType}: TestCase.UniqueID: {testCase.UniqueID}"); + LogMessage($"{messageType}: TestCase.DisplayName: {testCase.DisplayName}"); + LogMessage($"{messageType}: TestCase.Traits.Count: {testCase.Traits.Count}"); + + if (testCase.SourceInformation != null) + { + LogMessage($"{messageType}: TestCase.SourceInformation.FileName: {testCase.SourceInformation.FileName}"); + LogMessage($"{messageType}: TestCase.SourceInformation.LineNumber: {testCase.SourceInformation.LineNumber}"); + } + } + + public bool QueueMessage(IMessageSinkMessage message) + { + _messageSink.OnMessage(new DiagnosticMessage($"MessageBus: {message}")); + + HandleMessageSinkMessage(message); + + return _messageBus.QueueMessage(message); + } + + public void HandleMessageSinkMessage(IMessageSinkMessage message) + { + switch (message) + { + case ITestMethodStarting testMethodStarting: + LogMessage($"TestMethodStarting: TestCollection.DisplayName: {testMethodStarting.TestCollection.DisplayName}"); + LogMessage($"TestMethodStarting: TestCollection.UniqueID: {testMethodStarting.TestCollection.UniqueID}"); + LogMessage($"TestMethodStarting: TestCollection.TestAssembly.Assembly.AssemblyPath: {testMethodStarting.TestCollection.TestAssembly.Assembly.AssemblyPath}"); + LogMessage($"TestMethodStarting: TestCases.Count: {testMethodStarting.TestCases.Count()}"); + + LogMessage($"TestMethodStarting: TestClass.Class.Name: {testMethodStarting.TestClass.Class.Name}"); + break; + + case ITestCaseStarting testCaseStarting: + LogTestCase("TestCaseStarting", testCaseStarting.TestCase); + break; + + case ITestStarting testStarting: + LogMessage($"TestStarting: Test.DisplayName: {testStarting.Test.DisplayName}"); + LogTestCase("TestCaseStarting", testStarting.TestCase); + break; + + case ITestClassConstructionStarting classConstructionStarting: + // Code to handle Xunit.Sdk.TestClassConstructionStarting case + break; + + case ITestClassConstructionFinished classConstructionFinished: + // Code to handle Xunit.Sdk.TestClassConstructionFinished case + break; + + + case ITestSkipped testSkipped: + // Code to handle Xunit.Sdk.TestSkipped case + break; + + case ITestPassed testPassed: + // Code to handle Xunit.Sdk.TestPassed case + break; + + case ITestFailed testFailed: + LogTestCase("TestFailed", testFailed.TestCase); + LogMessage($"TestFailed: ExecutionTime: {testFailed.ExecutionTime}"); + LogMessage($"TestFailed: Messages: {string.Join('\n', testFailed.Messages)}"); + LogMessage($"TestFailed: Output: {testFailed.Output}"); + // Code to handle Xunit.Sdk.TestFailed case + break; + + case ITestFinished testFinished: + // Code to handle Xunit.Sdk.TestFinished case + break; + + case ITestCaseFinished testCaseFinished: + // Code to handle Xunit.Sdk.TestCaseFinished case + break; + + + case ITestMethodFinished testMethodFinished: + // Code to handle Xunit.Sdk.TestMethodFinished case + break; + + + default: + LogMessage($"UNKNOWN: {message.GetType().Name}"); + break; + } + } + } +} diff --git a/src/KiBoards/Framework/TestMessageSink.cs b/src/KiBoards/Framework/TestMessageSink.cs new file mode 100644 index 0000000..992da11 --- /dev/null +++ b/src/KiBoards/Framework/TestMessageSink.cs @@ -0,0 +1,106 @@ +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Framework +{ + internal class TestMessageSink : IMessageSink + { + private IMessageSink _messageSink; + + internal TestMessageSink(IMessageSink messageSink) + { + _messageSink = messageSink; + } + + private void LogMessage(string message) + { + _messageSink.OnMessage(new DiagnosticMessage($"MessageSink: {message}")); + } + + + public bool OnMessage(IMessageSinkMessage message) + { + HandleMessageSinkMessage(message); + return _messageSink.OnMessage(message); + } + + private void HandleMessageSinkMessage(IMessageSinkMessage message) + { + switch (message) + { + + case TestContextMessage testContext: + break; + + case ITestAssemblyStarting testAssemblyStarting: + LogMessage(message.GetType().Name); + break; + + case ITestCollectionStarting testCollectionStarting: + LogMessage(message.GetType().Name); + break; + + + + + case ITestMethodStarting testMethodStarting: + LogMessage($"TestMethodStarting: TestCollection.DisplayName: {testMethodStarting.TestCollection.DisplayName}"); + LogMessage($"TestMethodStarting: TestCollection.UniqueID: {testMethodStarting.TestCollection.UniqueID}"); + LogMessage($"TestMethodStarting: TestCollection.TestAssembly.Assembly.AssemblyPath: {testMethodStarting.TestCollection.TestAssembly.Assembly.AssemblyPath}"); + LogMessage($"TestMethodStarting: TestCases.Count: {testMethodStarting.TestCases.Count()}"); + + LogMessage($"TestMethodStarting: TestClass.Class.Name: {testMethodStarting.TestClass.Class.Name}"); + break; + + case ITestCaseStarting testCaseStarting: + LogMessage("TestCaseStarting"); + break; + + case ITestStarting testStarting: + LogMessage($"TestStarting: Test.DisplayName: {testStarting.Test.DisplayName}"); + break; + + case ITestClassConstructionStarting classConstructionStarting: + // Code to handle Xunit.Sdk.TestClassConstructionStarting case + break; + + case ITestClassConstructionFinished classConstructionFinished: + // Code to handle Xunit.Sdk.TestClassConstructionFinished case + break; + + + case ITestSkipped testSkipped: + // Code to handle Xunit.Sdk.TestSkipped case + break; + + case ITestPassed testPassed: + // Code to handle Xunit.Sdk.TestPassed case + break; + + case ITestFailed testFailed: + LogMessage($"TestFailed: ExecutionTime: {testFailed.ExecutionTime}"); + LogMessage($"TestFailed: Messages: {string.Join('\n', testFailed.Messages)}"); + LogMessage($"TestFailed: Output: {testFailed.Output}"); + // Code to handle Xunit.Sdk.TestFailed case + break; + + case ITestFinished testFinished: + // Code to handle Xunit.Sdk.TestFinished case + break; + + case ITestCaseFinished testCaseFinished: + // Code to handle Xunit.Sdk.TestCaseFinished case + break; + + + case ITestMethodFinished testMethodFinished: + // Code to handle Xunit.Sdk.TestMethodFinished case + break; + + default: + LogMessage($"UNKNOWN: {message.GetType().Name}"); + break; + } + } + } +} diff --git a/src/KiBoards/Framework/TestMethodRunner.cs b/src/KiBoards/Framework/TestMethodRunner.cs new file mode 100644 index 0000000..ef98867 --- /dev/null +++ b/src/KiBoards/Framework/TestMethodRunner.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Threading; +using Xunit.Abstractions; +using Xunit.Sdk; +using KiBoards.Services; + +namespace KiBoards.Framework +{ + internal class TestMethodRunner : XunitTestMethodRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + + + public TestMethodRunner(ITestMethod testMethod, IReflectionTypeInfo @class, IReflectionMethodInfo method, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, object[] constructorArguments, IKiBoardsTestRunnerService testRunner) + // : base(testMethod, @class, method, testCases, diagnosticMessageSink, new TestMessageBus(messageBus, diagnosticMessageSink), aggregator, cancellationTokenSource, constructorArguments) + : base(testMethod, @class, method, testCases, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource, constructorArguments) + + { + _testRunner = testRunner; + } + + protected override async Task RunTestCaseAsync(IXunitTestCase testCase) + { + try + { + await _testRunner.StartTestCaseAsync(testCase, TestMethod); + var result = await base.RunTestCaseAsync(testCase); + await _testRunner.FinishTestCaseAsync(testCase, TestMethod, Aggregator, result); + + + return result; + } + catch (Exception ex) + { + await _testRunner.ErrorTestCaseAsync(testCase, TestMethod, ex); + throw; + } + } + } +} diff --git a/src/KiBoards/KiBoards.csproj b/src/KiBoards/KiBoards.csproj index c8246b3..1e8c934 100644 --- a/src/KiBoards/KiBoards.csproj +++ b/src/KiBoards/KiBoards.csproj @@ -4,7 +4,6 @@ netstandard2.1 ..\..\bin enable - enable 10 @@ -28,15 +27,16 @@ - + - + - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + + diff --git a/src/KiBoards/Models/KiBoardsModelsExtensions.cs b/src/KiBoards/Models/KiBoardsModelsExtensions.cs new file mode 100644 index 0000000..70b2532 --- /dev/null +++ b/src/KiBoards/Models/KiBoardsModelsExtensions.cs @@ -0,0 +1,37 @@ +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Models +{ + internal static class KiBoardsModelsExtensions + { + + internal static KiBoardsTestCaseStatusDto ToKiBoardsTestCase(this IXunitTestCase testCase, ITestMethod testMethod, KiBoardsTestCaseStatus status, KiBoardsTestCaseState state) => new KiBoardsTestCaseStatusDto() + { + UniqueId = testCase.UniqueID, + DisplayName = testCase.DisplayName, + SkipReason = testCase.SkipReason, + UpdatedOn = DateTime.Now.ToUniversalTime(), + Status = status.ToString(), + State = state.ToString(), + TestMethod = new KiBoardsTestMethodDto() + { + TestClass = new KiBoardsTestClassDto() + { + Name = testMethod?.TestClass.Class.Name + }, + Method = new KiBoardsTestMethodInfoDto() + { + Name = testMethod?.Method.Name + } + } + }; + + + internal static IEnumerable ToKiBoardsTestCases(this IEnumerable testCases, KiBoardsTestCaseStatus status, KiBoardsTestCaseState state) => + testCases.Select(x => x.ToKiBoardsTestCase(null, status, state)); + + internal static KiBoardsTestCaseStatus ToKiBoardsTestCaseStatus(this RunSummary summary) + => summary.Failed > 0 ? KiBoardsTestCaseStatus.Failure : summary.Skipped > 0 ? KiBoardsTestCaseStatus.Skipped : KiBoardsTestCaseStatus.Success; + } +} diff --git a/src/KiBoards/Models/KiBoardsTestCaseState.cs b/src/KiBoards/Models/KiBoardsTestCaseState.cs new file mode 100644 index 0000000..6862720 --- /dev/null +++ b/src/KiBoards/Models/KiBoardsTestCaseState.cs @@ -0,0 +1,8 @@ +namespace KiBoards.Models +{ + internal enum KiBoardsTestCaseState + { + Active, + Inactive + } +} diff --git a/src/KiBoards/Models/KiBoardsTestCaseStatus.cs b/src/KiBoards/Models/KiBoardsTestCaseStatus.cs new file mode 100644 index 0000000..c1cafa7 --- /dev/null +++ b/src/KiBoards/Models/KiBoardsTestCaseStatus.cs @@ -0,0 +1,11 @@ +namespace KiBoards.Models +{ + internal enum KiBoardsTestCaseStatus + { + Discovered, + Running, + Success, + Failure, + Skipped + } +} diff --git a/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs b/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs new file mode 100644 index 0000000..4b5602c --- /dev/null +++ b/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs @@ -0,0 +1,13 @@ +namespace KiBoards.Models +{ + class KiBoardsTestCaseStatusDto + { + public string UniqueId { get; set; } + public string DisplayName { get; set; } + public DateTime UpdatedOn { get; set; } + public string Status { get; set; } + public string State { get; set; } + public string SkipReason { get; set; } + public KiBoardsTestMethodDto TestMethod { get; set; } + } +} diff --git a/src/KiBoards/Models/KiBoardsTestClassDto.cs b/src/KiBoards/Models/KiBoardsTestClassDto.cs new file mode 100644 index 0000000..c3fbb69 --- /dev/null +++ b/src/KiBoards/Models/KiBoardsTestClassDto.cs @@ -0,0 +1,10 @@ +using System; + +namespace KiBoards.Models +{ + class KiBoardsTestClassDto + { + public string Name { get; set; } + + } +} diff --git a/src/KiBoards/Models/KiBoardsTestMethodDto.cs b/src/KiBoards/Models/KiBoardsTestMethodDto.cs new file mode 100644 index 0000000..4011dc1 --- /dev/null +++ b/src/KiBoards/Models/KiBoardsTestMethodDto.cs @@ -0,0 +1,8 @@ +namespace KiBoards.Models +{ + class KiBoardsTestMethodDto + { + public KiBoardsTestClassDto TestClass { get; set; } + public KiBoardsTestMethodInfoDto Method { get; set; } + } +} diff --git a/src/KiBoards/Models/KiBoardsTestMethodInfoDto.cs b/src/KiBoards/Models/KiBoardsTestMethodInfoDto.cs new file mode 100644 index 0000000..7f33eab --- /dev/null +++ b/src/KiBoards/Models/KiBoardsTestMethodInfoDto.cs @@ -0,0 +1,8 @@ +namespace KiBoards.Models +{ + class KiBoardsTestMethodInfoDto + { + public string Name { get; set; } + + } +} diff --git a/src/KiBoards/Services/IKiBoardsElasticService.cs b/src/KiBoards/Services/IKiBoardsElasticService.cs new file mode 100644 index 0000000..fb4e1de --- /dev/null +++ b/src/KiBoards/Services/IKiBoardsElasticService.cs @@ -0,0 +1,11 @@ +using KiBoards.Models; + +namespace KiBoards.Services +{ + internal interface IKiBoardsElasticService + { + Task IndexTestCasesAsync(IEnumerable testCases); + Task IndexTestCaseAsync(KiBoardsTestCaseStatusDto testCase); + + } +} \ No newline at end of file diff --git a/src/KiBoards/Services/IKiBoardsTestRunnerService.cs b/src/KiBoards/Services/IKiBoardsTestRunnerService.cs new file mode 100644 index 0000000..f1f409d --- /dev/null +++ b/src/KiBoards/Services/IKiBoardsTestRunnerService.cs @@ -0,0 +1,16 @@ +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Services +{ + internal interface IKiBoardsTestRunnerService + { + Guid RunId { get; } + Task BeginTestCasesRunAsync(IEnumerable testCases); + Task StartTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod); + Task FinishTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod, ExceptionAggregator exceptionAggregator, RunSummary result); + Task ErrorTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod, Exception ex); + Task EndTestCasesRunAsync(RunSummary results); + Task ErrorTestCasesRunAsync(IEnumerable testCases, Exception ex); + } +} \ No newline at end of file diff --git a/src/KiBoards/Services/KiBoardsElasticService.cs b/src/KiBoards/Services/KiBoardsElasticService.cs new file mode 100644 index 0000000..b7c6d40 --- /dev/null +++ b/src/KiBoards/Services/KiBoardsElasticService.cs @@ -0,0 +1,54 @@ +using KiBoards.Models; +using Nest; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Services +{ + internal class KiBoardsElasticService : IKiBoardsElasticService + { + private readonly IElasticClient _elasticClient; + private readonly IMessageSink _messageSink; + + public KiBoardsElasticService(IElasticClient elasticClient, IMessageSink messageSink) + { + _elasticClient = elasticClient; + _messageSink = messageSink; + } + + public async Task IndexTestCasesAsync(IEnumerable testCases) + { + try + { + _messageSink.OnMessage(new DiagnosticMessage($"Indexing {testCases.Count()} test cases")); + var result = await _elasticClient.IndexManyAsync(testCases); + + if (!result.IsValid) + { + _messageSink.OnMessage(new DiagnosticMessage(result.DebugInformation)); + } + } + catch (Exception ex) + { + _messageSink.OnMessage(new DiagnosticMessage(ex.Message)); + } + } + + public async Task IndexTestCaseAsync(KiBoardsTestCaseStatusDto testCase) + { + try + { + var result = await _elasticClient.IndexDocumentAsync(testCase); + + if (!result.IsValid) + { + _messageSink.OnMessage(new DiagnosticMessage(result.DebugInformation)); + } + } + catch (Exception ex) + { + _messageSink.OnMessage(new DiagnosticMessage(ex.Message)); + } + } + } +} diff --git a/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs b/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs new file mode 100644 index 0000000..dbde2f2 --- /dev/null +++ b/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs @@ -0,0 +1,28 @@ +using KiBoards.Models; +using Microsoft.Extensions.DependencyInjection; +using Nest; +using System; + +namespace KiBoards.Services +{ + internal static class KiBoardsElasticServiceExtensions + { + internal static IServiceCollection AddElasticServices(this IServiceCollection services) + { + return services + .AddSingleton(new ElasticClient(ConfigureIndexes(new ConnectionSettings(new Uri($"http://localhost:9200")) + .MaxRetryTimeout(TimeSpan.FromMinutes(5)) + .MaximumRetries(3)))) + .AddTransient(); + } + + internal static ConnectionSettings ConfigureIndexes(ConnectionSettings connectionSettings) + { + connectionSettings.DefaultMappingFor(m => m + .IndexName($"kiboards-testcase-status-{DateTime.UtcNow:yyyy-MM}") + .IdProperty(p => p.UniqueId)); + + return connectionSettings; + } + } +} diff --git a/src/KiBoards/Services/KiBoardsTestRunnerService.cs b/src/KiBoards/Services/KiBoardsTestRunnerService.cs new file mode 100644 index 0000000..6489269 --- /dev/null +++ b/src/KiBoards/Services/KiBoardsTestRunnerService.cs @@ -0,0 +1,77 @@ +using KiBoards.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards.Services +{ + internal class KiBoardsTestRunnerService : IKiBoardsTestRunnerService, IDisposable + { + private readonly IMessageSink _messageSink; + private readonly IKiBoardsElasticService _elasticService; + + public Guid RunId { get; private set; } = Guid.NewGuid(); + + public KiBoardsTestRunnerService(IMessageSink messageSink, IKiBoardsElasticService elasticService) + { + _messageSink = messageSink; + _elasticService = elasticService; + + var version = Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion; + messageSink.OnMessage(new DiagnosticMessage($"KiBoards: {version}")); + messageSink.OnMessage(new DiagnosticMessage($"RunId: {RunId}")); + } + + + public void Dispose() + { + //_messageSink.OnMessage(new DiagnosticMessage("KiBoards run finished.")); + } + + public async Task BeginTestCasesRunAsync(IEnumerable testCases) + { + //foreach (var testCase in testCases) + // _messageSink.OnMessage(new DiagnosticMessage($"Discovered: {testCase.UniqueID} {testCase.DisplayName}")); + + await _elasticService.IndexTestCasesAsync(testCases.ToKiBoardsTestCases(KiBoardsTestCaseStatus.Discovered, KiBoardsTestCaseState.Active)); + } + + + public async Task ErrorTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod, Exception ex) + { + //_messageSink.OnMessage(new DiagnosticMessage($"Fatal: {testCase.UniqueID} ({ex.Message})")); + await Task.CompletedTask; + } + + public async Task FinishTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod, ExceptionAggregator exceptionAggregator, RunSummary summary) + { + //_messageSink.OnMessage(new DiagnosticMessage($"{(summary.Failed > 0 ? "Failure" : summary.Skipped > 0 ? "Skipped" : "Success")}: {testCase.UniqueID} {testCase.DisplayName} ({summary.Time}s)")); + await _elasticService.IndexTestCaseAsync(testCase.ToKiBoardsTestCase(testMethod, summary.ToKiBoardsTestCaseStatus(), KiBoardsTestCaseState.Inactive)); + } + + public async Task StartTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod) + { + //_messageSink.OnMessage(new DiagnosticMessage($"Started: {testCase.UniqueID} {testCase.DisplayName}")); + await _elasticService.IndexTestCaseAsync(testCase.ToKiBoardsTestCase(testMethod, KiBoardsTestCaseStatus.Running, KiBoardsTestCaseState.Active)); + } + + + public async Task EndTestCasesRunAsync(RunSummary results) + { + //_messageSink.OnMessage(new DiagnosticMessage("KiBoards run complete.")); + await Task.CompletedTask; + + } + + public async Task ErrorTestCasesRunAsync(IEnumerable testCases, Exception ex) + { + //_messageSink.OnMessage(new DiagnosticMessage($"Fatal: Run {RunId} failed. ({ex.Message})")); + await Task.CompletedTask; + } + } +} diff --git a/src/KiBoards/TestContextFixture.cs b/src/KiBoards/TestContextFixture.cs new file mode 100644 index 0000000..c79d96b --- /dev/null +++ b/src/KiBoards/TestContextFixture.cs @@ -0,0 +1,20 @@ +using KiBoards.Framework; +using Xunit.Abstractions; + +namespace KiBoards +{ + public class TestContextFixture + { + private readonly IMessageSink _messageSink; + + public TestContextFixture(IMessageSink messageSink) + { + _messageSink = messageSink; + } + + public void SetContext(object context) + { + _messageSink.OnMessage(new TestContextMessage(context)); + } + } +} diff --git a/src/KiBoards/TestExtensions.cs b/src/KiBoards/TestExtensions.cs new file mode 100644 index 0000000..1020903 --- /dev/null +++ b/src/KiBoards/TestExtensions.cs @@ -0,0 +1,22 @@ +using KiBoards.Framework; +using System.Reflection; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards +{ + public static class TestExtensions + { + public static ITestCase GetTestCase(this ITestOutputHelper output) + => (output.GetType().GetField("test", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(output) as ITest).TestCase; + + public static IMessageBus GetMessageBus(this ITestOutputHelper output) => + output.GetType() + .GetField("messageBus", BindingFlags.Instance | BindingFlags.NonPublic) + .GetValue(output) as IMessageBus; + + public static void SetContext(this ITestOutputHelper output, object context) => + GetMessageBus(output).QueueMessage(new TestContextMessage(context)); + + } +} diff --git a/src/KiBoards/TestFramework.cs b/src/KiBoards/TestFramework.cs new file mode 100644 index 0000000..42ff38b --- /dev/null +++ b/src/KiBoards/TestFramework.cs @@ -0,0 +1,40 @@ +using System.Reflection; +using KiBoards.Framework; +using KiBoards.Services; +using Microsoft.Extensions.DependencyInjection; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards +{ + public class TestFramework : XunitTestFramework, IDisposable + { + private readonly ServiceProvider _serviceProvider; + + public TestFramework(IMessageSink messageSink) + : base(messageSink) + { + IServiceCollection serviceCollection = new ServiceCollection(); + + serviceCollection + .AddSingleton(messageSink) + .AddElasticServices() + .AddSingleton(); + + _serviceProvider = serviceCollection.BuildServiceProvider(); + } + + protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) + { + return new TestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink, _serviceProvider.GetRequiredService()); + } + + public new async void Dispose() + { + await Task.Delay(1); + _serviceProvider.Dispose(); + base.Dispose(); + } + } +} + From 06aed7da74e26cdcdd30da3913d713fc62894174 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 16 Aug 2023 12:50:18 +0100 Subject: [PATCH 02/12] Add test context message --- src/KiBoards.Tests/UnitTest1.cs | 16 ++++++++++------ src/KiBoards.Tests/UnitTest2.cs | 2 ++ src/KiBoards/Framework/ITestContextMessage.cs | 9 +++++++++ src/KiBoards/Framework/TestContextMessage.cs | 4 +--- src/KiBoards/Framework/TestMessageSink.cs | 2 +- 5 files changed, 23 insertions(+), 10 deletions(-) create mode 100644 src/KiBoards/Framework/ITestContextMessage.cs diff --git a/src/KiBoards.Tests/UnitTest1.cs b/src/KiBoards.Tests/UnitTest1.cs index 3d6cfa7..d71db3e 100644 --- a/src/KiBoards.Tests/UnitTest1.cs +++ b/src/KiBoards.Tests/UnitTest1.cs @@ -1,4 +1,4 @@ -using Xunit; +using Xunit.Abstractions; using Xunit.Sdk; [assembly: TestFramework("KiBoards.TestFramework", "KiBoards")] @@ -8,20 +8,24 @@ namespace KiBoards.Tests public class UnitTest1 : IClassFixture { - TestContextFixture _kiboards; + readonly TestContextFixture _testContextFixture; + readonly ITestOutputHelper _testOutputHelper; - public UnitTest1(TestContextFixture testContextFixture) + public UnitTest1(TestContextFixture testContextFixture, ITestOutputHelper testOutputHelper) { - _kiboards = testContextFixture; + _testContextFixture = testContextFixture; + _testOutputHelper = testOutputHelper; - _kiboards.SetContext(new { Version = "12345" }); + _testContextFixture.SetContext(new { Version = "Context via Fixture" }); } [Fact] public void Test1() { - _kiboards.SetContext(new { Version = "12345" }); + var testCase = _testOutputHelper.GetTestCase(); + + _testContextFixture.SetContext(new { Version = "12345", TestCase = testCase }) ; Thread.Sleep(1000); } diff --git a/src/KiBoards.Tests/UnitTest2.cs b/src/KiBoards.Tests/UnitTest2.cs index b797867..27d2b57 100644 --- a/src/KiBoards.Tests/UnitTest2.cs +++ b/src/KiBoards.Tests/UnitTest2.cs @@ -23,6 +23,8 @@ public UnitTest2(TestContextFixture testContextFixture, ITestOutputHelper output public void Test5() { Thread.Sleep(5000); + + } [Theory] diff --git a/src/KiBoards/Framework/ITestContextMessage.cs b/src/KiBoards/Framework/ITestContextMessage.cs new file mode 100644 index 0000000..e18b926 --- /dev/null +++ b/src/KiBoards/Framework/ITestContextMessage.cs @@ -0,0 +1,9 @@ +using Xunit.Abstractions; + +namespace KiBoards.Framework +{ + internal interface ITestContextMessage : IMessageSinkMessage + { + public object Context { get; set; } + } +} diff --git a/src/KiBoards/Framework/TestContextMessage.cs b/src/KiBoards/Framework/TestContextMessage.cs index f9c21e8..23d3451 100644 --- a/src/KiBoards/Framework/TestContextMessage.cs +++ b/src/KiBoards/Framework/TestContextMessage.cs @@ -2,12 +2,10 @@ namespace KiBoards.Framework { - internal class TestContextMessage : IMessageSinkMessage, IExecutionMessage + internal class TestContextMessage : ITestContextMessage { public object Context { get; set; } - public IEnumerable TestCases => throw new NotImplementedException(); - public TestContextMessage(object context) { Context = context; diff --git a/src/KiBoards/Framework/TestMessageSink.cs b/src/KiBoards/Framework/TestMessageSink.cs index 992da11..d75d26b 100644 --- a/src/KiBoards/Framework/TestMessageSink.cs +++ b/src/KiBoards/Framework/TestMessageSink.cs @@ -29,7 +29,7 @@ private void HandleMessageSinkMessage(IMessageSinkMessage message) switch (message) { - case TestContextMessage testContext: + case ITestContextMessage testContext: break; case ITestAssemblyStarting testAssemblyStarting: From 788b754d1f15f3fc473834044ea343e6ececf457 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 16 Aug 2023 12:54:03 +0100 Subject: [PATCH 03/12] Remove message bus --- src/KiBoards.Tests/UnitTest2.cs | 4 +- src/KiBoards/Framework/TestAssemblyRunner.cs | 6 - src/KiBoards/Framework/TestMessageBus.cs | 116 ------------------- src/KiBoards/TestExtensions.cs | 13 +-- 4 files changed, 3 insertions(+), 136 deletions(-) delete mode 100644 src/KiBoards/Framework/TestMessageBus.cs diff --git a/src/KiBoards.Tests/UnitTest2.cs b/src/KiBoards.Tests/UnitTest2.cs index 27d2b57..19ea6ec 100644 --- a/src/KiBoards.Tests/UnitTest2.cs +++ b/src/KiBoards.Tests/UnitTest2.cs @@ -13,8 +13,8 @@ public class UnitTest2 : IClassFixture public UnitTest2(TestContextFixture testContextFixture, ITestOutputHelper outputHelper) { // This is how to get messageBus - - outputHelper.SetContext(new { Version = "1234" }); + + testContextFixture.SetContext(new { Version = "1234" }); outputHelper.WriteLine("HELLO WORLD MESSAGE BUS"); } diff --git a/src/KiBoards/Framework/TestAssemblyRunner.cs b/src/KiBoards/Framework/TestAssemblyRunner.cs index e491107..c77f841 100644 --- a/src/KiBoards/Framework/TestAssemblyRunner.cs +++ b/src/KiBoards/Framework/TestAssemblyRunner.cs @@ -23,12 +23,6 @@ protected override async Task RunTestCollectionAsync(IMessageBus mes return await collectionRunner.RunAsync(); } - protected override IMessageBus CreateMessageBus() - { - _messageSink.OnMessage(new DiagnosticMessage("Creating MessageBus")); - return new TestMessageBus(base.CreateMessageBus(), _messageSink); - } - protected override string GetTestFrameworkDisplayName() { var version = Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion; diff --git a/src/KiBoards/Framework/TestMessageBus.cs b/src/KiBoards/Framework/TestMessageBus.cs deleted file mode 100644 index 0291a02..0000000 --- a/src/KiBoards/Framework/TestMessageBus.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace KiBoards.Framework -{ - internal class TestMessageBus : IMessageBus - { - private IMessageBus _messageBus; - private IMessageSink _messageSink; - - public TestMessageBus(IMessageBus messageBus, IMessageSink messageSink) - { - _messageBus = messageBus; - _messageSink = messageSink; - } - - public void Dispose() - { - _messageBus.Dispose(); - } - - private void LogMessage(string message) - { - _messageSink.OnMessage(new DiagnosticMessage(message)); - } - - private void LogTestCase(string messageType, ITestCase testCase) - { - LogMessage($"{messageType}: TestCase.UniqueID: {testCase.UniqueID}"); - LogMessage($"{messageType}: TestCase.DisplayName: {testCase.DisplayName}"); - LogMessage($"{messageType}: TestCase.Traits.Count: {testCase.Traits.Count}"); - - if (testCase.SourceInformation != null) - { - LogMessage($"{messageType}: TestCase.SourceInformation.FileName: {testCase.SourceInformation.FileName}"); - LogMessage($"{messageType}: TestCase.SourceInformation.LineNumber: {testCase.SourceInformation.LineNumber}"); - } - } - - public bool QueueMessage(IMessageSinkMessage message) - { - _messageSink.OnMessage(new DiagnosticMessage($"MessageBus: {message}")); - - HandleMessageSinkMessage(message); - - return _messageBus.QueueMessage(message); - } - - public void HandleMessageSinkMessage(IMessageSinkMessage message) - { - switch (message) - { - case ITestMethodStarting testMethodStarting: - LogMessage($"TestMethodStarting: TestCollection.DisplayName: {testMethodStarting.TestCollection.DisplayName}"); - LogMessage($"TestMethodStarting: TestCollection.UniqueID: {testMethodStarting.TestCollection.UniqueID}"); - LogMessage($"TestMethodStarting: TestCollection.TestAssembly.Assembly.AssemblyPath: {testMethodStarting.TestCollection.TestAssembly.Assembly.AssemblyPath}"); - LogMessage($"TestMethodStarting: TestCases.Count: {testMethodStarting.TestCases.Count()}"); - - LogMessage($"TestMethodStarting: TestClass.Class.Name: {testMethodStarting.TestClass.Class.Name}"); - break; - - case ITestCaseStarting testCaseStarting: - LogTestCase("TestCaseStarting", testCaseStarting.TestCase); - break; - - case ITestStarting testStarting: - LogMessage($"TestStarting: Test.DisplayName: {testStarting.Test.DisplayName}"); - LogTestCase("TestCaseStarting", testStarting.TestCase); - break; - - case ITestClassConstructionStarting classConstructionStarting: - // Code to handle Xunit.Sdk.TestClassConstructionStarting case - break; - - case ITestClassConstructionFinished classConstructionFinished: - // Code to handle Xunit.Sdk.TestClassConstructionFinished case - break; - - - case ITestSkipped testSkipped: - // Code to handle Xunit.Sdk.TestSkipped case - break; - - case ITestPassed testPassed: - // Code to handle Xunit.Sdk.TestPassed case - break; - - case ITestFailed testFailed: - LogTestCase("TestFailed", testFailed.TestCase); - LogMessage($"TestFailed: ExecutionTime: {testFailed.ExecutionTime}"); - LogMessage($"TestFailed: Messages: {string.Join('\n', testFailed.Messages)}"); - LogMessage($"TestFailed: Output: {testFailed.Output}"); - // Code to handle Xunit.Sdk.TestFailed case - break; - - case ITestFinished testFinished: - // Code to handle Xunit.Sdk.TestFinished case - break; - - case ITestCaseFinished testCaseFinished: - // Code to handle Xunit.Sdk.TestCaseFinished case - break; - - - case ITestMethodFinished testMethodFinished: - // Code to handle Xunit.Sdk.TestMethodFinished case - break; - - - default: - LogMessage($"UNKNOWN: {message.GetType().Name}"); - break; - } - } - } -} diff --git a/src/KiBoards/TestExtensions.cs b/src/KiBoards/TestExtensions.cs index 1020903..454fe79 100644 --- a/src/KiBoards/TestExtensions.cs +++ b/src/KiBoards/TestExtensions.cs @@ -1,7 +1,5 @@ -using KiBoards.Framework; -using System.Reflection; +using System.Reflection; using Xunit.Abstractions; -using Xunit.Sdk; namespace KiBoards { @@ -9,14 +7,5 @@ public static class TestExtensions { public static ITestCase GetTestCase(this ITestOutputHelper output) => (output.GetType().GetField("test", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(output) as ITest).TestCase; - - public static IMessageBus GetMessageBus(this ITestOutputHelper output) => - output.GetType() - .GetField("messageBus", BindingFlags.Instance | BindingFlags.NonPublic) - .GetValue(output) as IMessageBus; - - public static void SetContext(this ITestOutputHelper output, object context) => - GetMessageBus(output).QueueMessage(new TestContextMessage(context)); - } } From a63353bddebc2124e947e1573f53f2bc66024fc7 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 16 Aug 2023 12:57:27 +0100 Subject: [PATCH 04/12] Resolve conflicts --- src/KiBoards/Framework/TestFrameworkExecutor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/KiBoards/Framework/TestFrameworkExecutor.cs b/src/KiBoards/Framework/TestFrameworkExecutor.cs index 2b8fc35..7f36af2 100644 --- a/src/KiBoards/Framework/TestFrameworkExecutor.cs +++ b/src/KiBoards/Framework/TestFrameworkExecutor.cs @@ -19,8 +19,8 @@ protected override async void RunTestCases(IEnumerable testCases { try { - await _testRunner.BeginTestCasesRunAsync(testCases); - using var assemblyRunner = new TestAssemblyRunner(TestAssembly, testCases, new TestMessageSink(DiagnosticMessageSink), executionMessageSink, executionOptions, _testRunner); + await _testRunner.BeginTestCasesRunAsync(testCases); + using var assemblyRunner = new XunitTestAssemblyRunner(TestAssembly, testCases, new TestMessageSink(DiagnosticMessageSink), executionMessageSink, executionOptions); var results = await assemblyRunner.RunAsync(); await _testRunner.EndTestCasesRunAsync(results); } @@ -29,5 +29,6 @@ protected override async void RunTestCases(IEnumerable testCases await _testRunner.ErrorTestCasesRunAsync(testCases, ex); } } + } } From 8c3fb86a13c4b6660f913b6db64479c13cf4da1e Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 16 Aug 2023 12:57:46 +0100 Subject: [PATCH 05/12] Add more diagnostic messages --- src/KiBoards/Framework/TestMessageSink.cs | 60 ++++++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/src/KiBoards/Framework/TestMessageSink.cs b/src/KiBoards/Framework/TestMessageSink.cs index d75d26b..802c1de 100644 --- a/src/KiBoards/Framework/TestMessageSink.cs +++ b/src/KiBoards/Framework/TestMessageSink.cs @@ -7,14 +7,27 @@ internal class TestMessageSink : IMessageSink { private IMessageSink _messageSink; - internal TestMessageSink(IMessageSink messageSink) + internal TestMessageSink(IMessageSink messageSink) { _messageSink = messageSink; } private void LogMessage(string message) { - _messageSink.OnMessage(new DiagnosticMessage($"MessageSink: {message}")); + _messageSink.OnMessage(new DiagnosticMessage(message)); + } + + private void LogTestCase(string messageType, ITestCase testCase) + { + LogMessage($"{messageType}: TestCase.UniqueID: {testCase.UniqueID}"); + LogMessage($"{messageType}: TestCase.DisplayName: {testCase.DisplayName}"); + LogMessage($"{messageType}: TestCase.Traits.Count: {testCase.Traits.Count}"); + + if (testCase.SourceInformation != null) + { + LogMessage($"{messageType}: TestCase.SourceInformation.FileName: {testCase.SourceInformation.FileName}"); + LogMessage($"{messageType}: TestCase.SourceInformation.LineNumber: {testCase.SourceInformation.LineNumber}"); + } } @@ -33,16 +46,20 @@ private void HandleMessageSinkMessage(IMessageSinkMessage message) break; case ITestAssemblyStarting testAssemblyStarting: - LogMessage(message.GetType().Name); + LogMessage($"TestAssemblyStarting: StartTime: {testAssemblyStarting.StartTime}"); + LogMessage($"TestAssemblyStarting: TestFrameworkDisplayName: {testAssemblyStarting.TestFrameworkDisplayName}"); + LogMessage($"TestAssemblyStarting: TestEnvironment: {testAssemblyStarting.TestEnvironment}"); + LogMessage($"TestAssemblyStarting: TestCases.Count: {testAssemblyStarting.TestCases.Count()}"); break; case ITestCollectionStarting testCollectionStarting: - LogMessage(message.GetType().Name); + LogMessage($"TestCollectionStarting: TestCollection.DisplayName: {testCollectionStarting.TestCollection.DisplayName}"); + LogMessage($"TestCollectionStarting: TestCollection.UniqueID: {testCollectionStarting.TestCollection.UniqueID}"); + LogMessage($"TestCollectionStarting: TestCollection.TestCases.Count: {testCollectionStarting.TestCases.Count()}"); + LogMessage($"TestCollectionStarting: TestAssembly.Assembly.Name: {testCollectionStarting.TestAssembly.Assembly.Name}"); break; - - case ITestMethodStarting testMethodStarting: LogMessage($"TestMethodStarting: TestCollection.DisplayName: {testMethodStarting.TestCollection.DisplayName}"); LogMessage($"TestMethodStarting: TestCollection.UniqueID: {testMethodStarting.TestCollection.UniqueID}"); @@ -61,7 +78,10 @@ private void HandleMessageSinkMessage(IMessageSinkMessage message) break; case ITestClassConstructionStarting classConstructionStarting: - // Code to handle Xunit.Sdk.TestClassConstructionStarting case + LogMessage($"TestClassConstructionStarting: Test.DisplayName: {classConstructionStarting.Test.DisplayName}"); + LogMessage($"TestClassConstructionStarting: Test.TestCase.DisplayName: {classConstructionStarting.Test.TestCase.DisplayName}"); + LogMessage($"TestClassConstructionStarting: Test.TestCase.UniqueID: {classConstructionStarting.Test.TestCase.UniqueID}"); + LogMessage($"TestClassConstructionStarting: Test.TestCase.TestMethod.Method.Name: {classConstructionStarting.Test.TestCase.TestMethod.Method.Name}"); break; case ITestClassConstructionFinished classConstructionFinished: @@ -74,6 +94,13 @@ private void HandleMessageSinkMessage(IMessageSinkMessage message) break; case ITestPassed testPassed: + LogMessage($"TestPassed: Output: {testPassed.Output}"); + LogMessage($"TestPassed: ExcecutionTime: {testPassed.ExecutionTime}"); + LogMessage($"TestPassed: Test.DisplayName: {testPassed.Test.DisplayName}"); + LogMessage($"TestPassed: TestCase.UniqueID: {testPassed.TestCase.UniqueID}"); + LogMessage($"TestPassed: TestCase.DisplayName: {testPassed.TestCase.DisplayName}"); + LogMessage($"TestPassed: TestCases.Count: {testPassed.TestCases.Count()}"); + // Code to handle Xunit.Sdk.TestPassed case break; @@ -97,6 +124,25 @@ private void HandleMessageSinkMessage(IMessageSinkMessage message) // Code to handle Xunit.Sdk.TestMethodFinished case break; + case ITestClassStarting testClassStarting: + break; + + case ITestOutput TestOutput: + break; + + case ITestClassFinished testClassFinished: + break; + + case ITestCollectionFinished testCollectionFinished: + break; + + case ITestAssemblyFinished testAssemblyFinished: + LogMessage($"TestAssemblyFinished: TestsRun: {testAssemblyFinished.TestsRun}"); + LogMessage($"TestAssemblyFinished: TestsFailed: {testAssemblyFinished.TestsFailed}"); + LogMessage($"TestAssemblyFinished: TestsSkipped: {testAssemblyFinished.TestsSkipped}"); + LogMessage($"TestAssemblyFinished: ExecutionTime: {testAssemblyFinished.ExecutionTime}"); + break; + default: LogMessage($"UNKNOWN: {message.GetType().Name}"); break; From cd220d05d84284122cb7ecbb20ecf468b5f9148a Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 21 Aug 2023 11:22:20 +0100 Subject: [PATCH 06/12] Consolidate framework classes --- src/KiBoards/Framework/ITestContextMessage.cs | 9 -- src/KiBoards/Framework/TestAssemblyRunner.cs | 38 ----- src/KiBoards/Framework/TestClassRunner.cs | 26 --- .../Framework/TestCollectionRunner.cs | 21 --- src/KiBoards/Framework/TestContextMessage.cs | 14 -- .../Framework/TestFrameworkExecutor.cs | 34 ---- src/KiBoards/Framework/TestMessageSink.cs | 152 ------------------ src/KiBoards/Framework/TestMethodRunner.cs | 42 ----- src/KiBoards/TestFramework.cs | 143 +++++++++++++++- 9 files changed, 141 insertions(+), 338 deletions(-) delete mode 100644 src/KiBoards/Framework/ITestContextMessage.cs delete mode 100644 src/KiBoards/Framework/TestAssemblyRunner.cs delete mode 100644 src/KiBoards/Framework/TestClassRunner.cs delete mode 100644 src/KiBoards/Framework/TestCollectionRunner.cs delete mode 100644 src/KiBoards/Framework/TestContextMessage.cs delete mode 100644 src/KiBoards/Framework/TestFrameworkExecutor.cs delete mode 100644 src/KiBoards/Framework/TestMessageSink.cs delete mode 100644 src/KiBoards/Framework/TestMethodRunner.cs diff --git a/src/KiBoards/Framework/ITestContextMessage.cs b/src/KiBoards/Framework/ITestContextMessage.cs deleted file mode 100644 index e18b926..0000000 --- a/src/KiBoards/Framework/ITestContextMessage.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Xunit.Abstractions; - -namespace KiBoards.Framework -{ - internal interface ITestContextMessage : IMessageSinkMessage - { - public object Context { get; set; } - } -} diff --git a/src/KiBoards/Framework/TestAssemblyRunner.cs b/src/KiBoards/Framework/TestAssemblyRunner.cs deleted file mode 100644 index c77f841..0000000 --- a/src/KiBoards/Framework/TestAssemblyRunner.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; -using KiBoards.Services; -using System.Reflection; - -namespace KiBoards.Framework -{ - internal class TestAssemblyRunner : XunitTestAssemblyRunner - { - private readonly IKiBoardsTestRunnerService _testRunner; - private readonly IMessageSink _messageSink; - - public TestAssemblyRunner(ITestAssembly testAssembly, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions, IKiBoardsTestRunnerService testRunner) - : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) - { - _testRunner = testRunner; - _messageSink = diagnosticMessageSink; - } - - protected override async Task RunTestCollectionAsync(IMessageBus messageBus, ITestCollection testCollection, IEnumerable testCases, CancellationTokenSource cancellationTokenSource) - { - var collectionRunner = new TestCollectionRunner(testCollection, testCases, DiagnosticMessageSink, messageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource, _testRunner); - return await collectionRunner.RunAsync(); - } - - protected override string GetTestFrameworkDisplayName() - { - var version = Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion; - return $"KiBoards {version}"; - } - - protected override Task BeforeTestAssemblyFinishedAsync() - { - _messageSink.OnMessage(new DiagnosticMessage("BeforeTestAssemblyFinishedAsync")); - return base.BeforeTestAssemblyFinishedAsync(); - } - } -} diff --git a/src/KiBoards/Framework/TestClassRunner.cs b/src/KiBoards/Framework/TestClassRunner.cs deleted file mode 100644 index 6494609..0000000 --- a/src/KiBoards/Framework/TestClassRunner.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; -using KiBoards.Services; - -namespace KiBoards.Framework -{ - internal class TestClassRunner : XunitTestClassRunner - { - private readonly IKiBoardsTestRunnerService _testRunner; - - public TestClassRunner(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IDictionary collectionFixtureMappings, IKiBoardsTestRunnerService testRunner) - : base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings) - { - _testRunner = testRunner; - } - - protected override Task RunTestMethodAsync(ITestMethod testMethod, IReflectionMethodInfo method, IEnumerable testCases, object[] constructorArguments) - => new TestMethodRunner(testMethod, Class, method, testCases, DiagnosticMessageSink, MessageBus, new ExceptionAggregator(Aggregator), CancellationTokenSource, constructorArguments, _testRunner) - .RunAsync(); - - protected override async Task RunTestMethodsAsync() - { - return await base.RunTestMethodsAsync(); - } - } -} diff --git a/src/KiBoards/Framework/TestCollectionRunner.cs b/src/KiBoards/Framework/TestCollectionRunner.cs deleted file mode 100644 index e15da67..0000000 --- a/src/KiBoards/Framework/TestCollectionRunner.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; -using KiBoards.Services; - -namespace KiBoards.Framework -{ - internal class TestCollectionRunner : XunitTestCollectionRunner - { - private readonly IKiBoardsTestRunnerService _testRunner; - - public TestCollectionRunner(ITestCollection testCollection, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IKiBoardsTestRunnerService testRunner) - : base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) - { - _testRunner = testRunner; - } - - protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) - => new TestClassRunner(testClass, @class, testCases, DiagnosticMessageSink, MessageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource, CollectionFixtureMappings, _testRunner) - .RunAsync(); - } -} diff --git a/src/KiBoards/Framework/TestContextMessage.cs b/src/KiBoards/Framework/TestContextMessage.cs deleted file mode 100644 index 23d3451..0000000 --- a/src/KiBoards/Framework/TestContextMessage.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Xunit.Abstractions; - -namespace KiBoards.Framework -{ - internal class TestContextMessage : ITestContextMessage - { - public object Context { get; set; } - - public TestContextMessage(object context) - { - Context = context; - } - } -} diff --git a/src/KiBoards/Framework/TestFrameworkExecutor.cs b/src/KiBoards/Framework/TestFrameworkExecutor.cs deleted file mode 100644 index 7f36af2..0000000 --- a/src/KiBoards/Framework/TestFrameworkExecutor.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Reflection; -using KiBoards.Services; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace KiBoards.Framework -{ - internal class TestFrameworkExecutor : XunitTestFrameworkExecutor - { - private readonly IKiBoardsTestRunnerService _testRunner; - - public TestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink, IKiBoardsTestRunnerService testRunner) - : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) - { - _testRunner = testRunner; - } - - protected override async void RunTestCases(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) - { - try - { - await _testRunner.BeginTestCasesRunAsync(testCases); - using var assemblyRunner = new XunitTestAssemblyRunner(TestAssembly, testCases, new TestMessageSink(DiagnosticMessageSink), executionMessageSink, executionOptions); - var results = await assemblyRunner.RunAsync(); - await _testRunner.EndTestCasesRunAsync(results); - } - catch (Exception ex) - { - await _testRunner.ErrorTestCasesRunAsync(testCases, ex); - } - } - - } -} diff --git a/src/KiBoards/Framework/TestMessageSink.cs b/src/KiBoards/Framework/TestMessageSink.cs deleted file mode 100644 index 802c1de..0000000 --- a/src/KiBoards/Framework/TestMessageSink.cs +++ /dev/null @@ -1,152 +0,0 @@ -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace KiBoards.Framework -{ - internal class TestMessageSink : IMessageSink - { - private IMessageSink _messageSink; - - internal TestMessageSink(IMessageSink messageSink) - { - _messageSink = messageSink; - } - - private void LogMessage(string message) - { - _messageSink.OnMessage(new DiagnosticMessage(message)); - } - - private void LogTestCase(string messageType, ITestCase testCase) - { - LogMessage($"{messageType}: TestCase.UniqueID: {testCase.UniqueID}"); - LogMessage($"{messageType}: TestCase.DisplayName: {testCase.DisplayName}"); - LogMessage($"{messageType}: TestCase.Traits.Count: {testCase.Traits.Count}"); - - if (testCase.SourceInformation != null) - { - LogMessage($"{messageType}: TestCase.SourceInformation.FileName: {testCase.SourceInformation.FileName}"); - LogMessage($"{messageType}: TestCase.SourceInformation.LineNumber: {testCase.SourceInformation.LineNumber}"); - } - } - - - public bool OnMessage(IMessageSinkMessage message) - { - HandleMessageSinkMessage(message); - return _messageSink.OnMessage(message); - } - - private void HandleMessageSinkMessage(IMessageSinkMessage message) - { - switch (message) - { - - case ITestContextMessage testContext: - break; - - case ITestAssemblyStarting testAssemblyStarting: - LogMessage($"TestAssemblyStarting: StartTime: {testAssemblyStarting.StartTime}"); - LogMessage($"TestAssemblyStarting: TestFrameworkDisplayName: {testAssemblyStarting.TestFrameworkDisplayName}"); - LogMessage($"TestAssemblyStarting: TestEnvironment: {testAssemblyStarting.TestEnvironment}"); - LogMessage($"TestAssemblyStarting: TestCases.Count: {testAssemblyStarting.TestCases.Count()}"); - break; - - case ITestCollectionStarting testCollectionStarting: - LogMessage($"TestCollectionStarting: TestCollection.DisplayName: {testCollectionStarting.TestCollection.DisplayName}"); - LogMessage($"TestCollectionStarting: TestCollection.UniqueID: {testCollectionStarting.TestCollection.UniqueID}"); - LogMessage($"TestCollectionStarting: TestCollection.TestCases.Count: {testCollectionStarting.TestCases.Count()}"); - LogMessage($"TestCollectionStarting: TestAssembly.Assembly.Name: {testCollectionStarting.TestAssembly.Assembly.Name}"); - break; - - - case ITestMethodStarting testMethodStarting: - LogMessage($"TestMethodStarting: TestCollection.DisplayName: {testMethodStarting.TestCollection.DisplayName}"); - LogMessage($"TestMethodStarting: TestCollection.UniqueID: {testMethodStarting.TestCollection.UniqueID}"); - LogMessage($"TestMethodStarting: TestCollection.TestAssembly.Assembly.AssemblyPath: {testMethodStarting.TestCollection.TestAssembly.Assembly.AssemblyPath}"); - LogMessage($"TestMethodStarting: TestCases.Count: {testMethodStarting.TestCases.Count()}"); - - LogMessage($"TestMethodStarting: TestClass.Class.Name: {testMethodStarting.TestClass.Class.Name}"); - break; - - case ITestCaseStarting testCaseStarting: - LogMessage("TestCaseStarting"); - break; - - case ITestStarting testStarting: - LogMessage($"TestStarting: Test.DisplayName: {testStarting.Test.DisplayName}"); - break; - - case ITestClassConstructionStarting classConstructionStarting: - LogMessage($"TestClassConstructionStarting: Test.DisplayName: {classConstructionStarting.Test.DisplayName}"); - LogMessage($"TestClassConstructionStarting: Test.TestCase.DisplayName: {classConstructionStarting.Test.TestCase.DisplayName}"); - LogMessage($"TestClassConstructionStarting: Test.TestCase.UniqueID: {classConstructionStarting.Test.TestCase.UniqueID}"); - LogMessage($"TestClassConstructionStarting: Test.TestCase.TestMethod.Method.Name: {classConstructionStarting.Test.TestCase.TestMethod.Method.Name}"); - break; - - case ITestClassConstructionFinished classConstructionFinished: - // Code to handle Xunit.Sdk.TestClassConstructionFinished case - break; - - - case ITestSkipped testSkipped: - // Code to handle Xunit.Sdk.TestSkipped case - break; - - case ITestPassed testPassed: - LogMessage($"TestPassed: Output: {testPassed.Output}"); - LogMessage($"TestPassed: ExcecutionTime: {testPassed.ExecutionTime}"); - LogMessage($"TestPassed: Test.DisplayName: {testPassed.Test.DisplayName}"); - LogMessage($"TestPassed: TestCase.UniqueID: {testPassed.TestCase.UniqueID}"); - LogMessage($"TestPassed: TestCase.DisplayName: {testPassed.TestCase.DisplayName}"); - LogMessage($"TestPassed: TestCases.Count: {testPassed.TestCases.Count()}"); - - // Code to handle Xunit.Sdk.TestPassed case - break; - - case ITestFailed testFailed: - LogMessage($"TestFailed: ExecutionTime: {testFailed.ExecutionTime}"); - LogMessage($"TestFailed: Messages: {string.Join('\n', testFailed.Messages)}"); - LogMessage($"TestFailed: Output: {testFailed.Output}"); - // Code to handle Xunit.Sdk.TestFailed case - break; - - case ITestFinished testFinished: - // Code to handle Xunit.Sdk.TestFinished case - break; - - case ITestCaseFinished testCaseFinished: - // Code to handle Xunit.Sdk.TestCaseFinished case - break; - - - case ITestMethodFinished testMethodFinished: - // Code to handle Xunit.Sdk.TestMethodFinished case - break; - - case ITestClassStarting testClassStarting: - break; - - case ITestOutput TestOutput: - break; - - case ITestClassFinished testClassFinished: - break; - - case ITestCollectionFinished testCollectionFinished: - break; - - case ITestAssemblyFinished testAssemblyFinished: - LogMessage($"TestAssemblyFinished: TestsRun: {testAssemblyFinished.TestsRun}"); - LogMessage($"TestAssemblyFinished: TestsFailed: {testAssemblyFinished.TestsFailed}"); - LogMessage($"TestAssemblyFinished: TestsSkipped: {testAssemblyFinished.TestsSkipped}"); - LogMessage($"TestAssemblyFinished: ExecutionTime: {testAssemblyFinished.ExecutionTime}"); - break; - - default: - LogMessage($"UNKNOWN: {message.GetType().Name}"); - break; - } - } - } -} diff --git a/src/KiBoards/Framework/TestMethodRunner.cs b/src/KiBoards/Framework/TestMethodRunner.cs deleted file mode 100644 index ef98867..0000000 --- a/src/KiBoards/Framework/TestMethodRunner.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Threading; -using Xunit.Abstractions; -using Xunit.Sdk; -using KiBoards.Services; - -namespace KiBoards.Framework -{ - internal class TestMethodRunner : XunitTestMethodRunner - { - private readonly IKiBoardsTestRunnerService _testRunner; - - - public TestMethodRunner(ITestMethod testMethod, IReflectionTypeInfo @class, IReflectionMethodInfo method, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, object[] constructorArguments, IKiBoardsTestRunnerService testRunner) - // : base(testMethod, @class, method, testCases, diagnosticMessageSink, new TestMessageBus(messageBus, diagnosticMessageSink), aggregator, cancellationTokenSource, constructorArguments) - : base(testMethod, @class, method, testCases, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource, constructorArguments) - - { - _testRunner = testRunner; - } - - protected override async Task RunTestCaseAsync(IXunitTestCase testCase) - { - try - { - await _testRunner.StartTestCaseAsync(testCase, TestMethod); - var result = await base.RunTestCaseAsync(testCase); - await _testRunner.FinishTestCaseAsync(testCase, TestMethod, Aggregator, result); - - - return result; - } - catch (Exception ex) - { - await _testRunner.ErrorTestCaseAsync(testCase, TestMethod, ex); - throw; - } - } - } -} diff --git a/src/KiBoards/TestFramework.cs b/src/KiBoards/TestFramework.cs index 42ff38b..b48949b 100644 --- a/src/KiBoards/TestFramework.cs +++ b/src/KiBoards/TestFramework.cs @@ -1,5 +1,4 @@ using System.Reflection; -using KiBoards.Framework; using KiBoards.Services; using Microsoft.Extensions.DependencyInjection; using Xunit.Abstractions; @@ -28,13 +27,153 @@ protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyNa { return new TestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink, _serviceProvider.GetRequiredService()); } - public new async void Dispose() { await Task.Delay(1); _serviceProvider.Dispose(); base.Dispose(); } + + + private class TestFrameworkExecutor : XunitTestFrameworkExecutor + { + private readonly IKiBoardsTestRunnerService _testRunner; + + public TestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink, IKiBoardsTestRunnerService testRunner) + : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) + { + _testRunner = testRunner; + } + + protected override async void RunTestCases(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) + { + try + { + await _testRunner.BeginTestCasesRunAsync(testCases); + using var assemblyRunner = new TestAssemblyRunner(TestAssembly, testCases, new TestMessageSink(DiagnosticMessageSink, _testRunner), executionMessageSink, executionOptions, _testRunner); + var results = await assemblyRunner.RunAsync(); + await _testRunner.EndTestCasesRunAsync(results); + } + catch (Exception ex) + { + await _testRunner.ErrorTestCasesRunAsync(testCases, ex); + } + } + } + + + + private class TestAssemblyRunner : XunitTestAssemblyRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + private readonly IMessageSink _messageSink; + + public TestAssemblyRunner(ITestAssembly testAssembly, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions, IKiBoardsTestRunnerService testRunner) + : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) + { + _testRunner = testRunner; + _messageSink = diagnosticMessageSink; + } + + protected override async Task RunTestCollectionAsync(IMessageBus messageBus, ITestCollection testCollection, IEnumerable testCases, CancellationTokenSource cancellationTokenSource) + { + var collectionRunner = new TestCollectionRunner(testCollection, testCases, DiagnosticMessageSink, messageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource, _testRunner); + return await collectionRunner.RunAsync(); + } + + protected override string GetTestFrameworkDisplayName() + { + var version = Assembly.GetExecutingAssembly().GetCustomAttribute()?.InformationalVersion; + return $"KiBoards {version}"; + } + + protected override Task AfterTestAssemblyStartingAsync() + { + _messageSink.OnMessage(new DiagnosticMessage("AfterTestAssemblyStartingAsync")); + return base.AfterTestAssemblyStartingAsync(); + } + + + protected override Task BeforeTestAssemblyFinishedAsync() + { + _messageSink.OnMessage(new DiagnosticMessage("BeforeTestAssemblyFinishedAsync")); + return base.BeforeTestAssemblyFinishedAsync(); + } + } + + + private class TestCollectionRunner : XunitTestCollectionRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + + public TestCollectionRunner(ITestCollection testCollection, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IKiBoardsTestRunnerService testRunner) + : base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) + { + _testRunner = testRunner; + } + + protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) + => new TestClassRunner(testClass, @class, testCases, DiagnosticMessageSink, MessageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource, CollectionFixtureMappings, _testRunner) + .RunAsync(); + } + + + private class TestClassRunner : XunitTestClassRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + + public TestClassRunner(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases, IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, IDictionary collectionFixtureMappings, IKiBoardsTestRunnerService testRunner) + : base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings) + { + _testRunner = testRunner; + } + + protected override Task RunTestMethodAsync(ITestMethod testMethod, IReflectionMethodInfo method, IEnumerable testCases, object[] constructorArguments) + => new TestMethodRunner(testMethod, Class, method, testCases, DiagnosticMessageSink, new TestResultBus(MessageBus), new ExceptionAggregator(Aggregator), CancellationTokenSource, constructorArguments, _testRunner) + .RunAsync(); + + protected override async Task RunTestMethodsAsync() + { + return await base.RunTestMethodsAsync(); + } + } + + + + private class TestMethodRunner : XunitTestMethodRunner + { + private readonly IKiBoardsTestRunnerService _testRunner; + private readonly TestResultSink _resultSink; + private readonly TestResultBus _resultBus; + + public TestMethodRunner(ITestMethod testMethod, IReflectionTypeInfo @class, IReflectionMethodInfo method, IEnumerable testCases, IMessageSink diagnosticMessageSink, TestResultBus messageBus, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource, object[] constructorArguments, IKiBoardsTestRunnerService testRunner) + : base(testMethod, @class, method, testCases, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource, constructorArguments) + + { + _resultBus = messageBus; + _testRunner = testRunner; + } + + protected override async Task RunTestCaseAsync(IXunitTestCase testCase) + { + try + { + await _testRunner.StartTestCaseAsync(testCase, TestMethod); + var result = await base.RunTestCaseAsync(testCase); + + var testResult = _resultBus.TestResult; + + await _testRunner.FinishTestCaseAsync(testCase, TestMethod, Aggregator, result); + + return result; + } + catch (Exception ex) + { + await _testRunner.ErrorTestCaseAsync(testCase, TestMethod, ex); + throw; + } + } + } } } From 6589f386befaab05bb15f4521aac320b553ceebd Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 21 Aug 2023 11:24:51 +0100 Subject: [PATCH 07/12] Add test context message --- src/KiBoards/ITestContextMessage.cs | 9 +++++++++ src/KiBoards/TestContextFixture.cs | 3 +-- src/KiBoards/TestContextMessage.cs | 12 ++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 src/KiBoards/ITestContextMessage.cs create mode 100644 src/KiBoards/TestContextMessage.cs diff --git a/src/KiBoards/ITestContextMessage.cs b/src/KiBoards/ITestContextMessage.cs new file mode 100644 index 0000000..0b6df27 --- /dev/null +++ b/src/KiBoards/ITestContextMessage.cs @@ -0,0 +1,9 @@ +using Xunit.Abstractions; + +namespace KiBoards +{ + internal interface ITestContextMessage : IMessageSinkMessage + { + public object Context { get; set; } + } +} diff --git a/src/KiBoards/TestContextFixture.cs b/src/KiBoards/TestContextFixture.cs index c79d96b..8da59cf 100644 --- a/src/KiBoards/TestContextFixture.cs +++ b/src/KiBoards/TestContextFixture.cs @@ -1,5 +1,4 @@ -using KiBoards.Framework; -using Xunit.Abstractions; +using Xunit.Abstractions; namespace KiBoards { diff --git a/src/KiBoards/TestContextMessage.cs b/src/KiBoards/TestContextMessage.cs new file mode 100644 index 0000000..e8d414c --- /dev/null +++ b/src/KiBoards/TestContextMessage.cs @@ -0,0 +1,12 @@ +namespace KiBoards +{ + internal class TestContextMessage : ITestContextMessage + { + public object Context { get; set; } + + public TestContextMessage(object context) + { + Context = context; + } + } +} From d2826ad0f89f551b528a10c79ea7254b45378904 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 21 Aug 2023 11:25:03 +0100 Subject: [PATCH 08/12] Add test result bus and sink --- src/KiBoards/TestMessageSink.cs | 156 ++++++++++++++++++++++++++++++++ src/KiBoards/TestResultBus.cs | 28 ++++++ src/KiBoards/TestResultSink.cs | 24 +++++ 3 files changed, 208 insertions(+) create mode 100644 src/KiBoards/TestMessageSink.cs create mode 100644 src/KiBoards/TestResultBus.cs create mode 100644 src/KiBoards/TestResultSink.cs diff --git a/src/KiBoards/TestMessageSink.cs b/src/KiBoards/TestMessageSink.cs new file mode 100644 index 0000000..cfcbf74 --- /dev/null +++ b/src/KiBoards/TestMessageSink.cs @@ -0,0 +1,156 @@ +using KiBoards.Services; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards +{ + internal class TestMessageSink : IMessageSink + { + private readonly IKiBoardsTestRunnerService _testRunner; + private IMessageSink _messageSink; + + internal TestMessageSink(IMessageSink messageSink, IKiBoardsTestRunnerService testRunner) + { + _messageSink = messageSink; + _testRunner = testRunner; + } + + private void LogMessage(string message) + { + _messageSink.OnMessage(new DiagnosticMessage(message)); + } + + private void LogTestCase(string messageType, ITestCase testCase) + { + LogMessage($"{messageType}: TestCase.UniqueID: {testCase.UniqueID}"); + LogMessage($"{messageType}: TestCase.DisplayName: {testCase.DisplayName}"); + LogMessage($"{messageType}: TestCase.Traits.Count: {testCase.Traits.Count}"); + + if (testCase.SourceInformation != null) + { + LogMessage($"{messageType}: TestCase.SourceInformation.FileName: {testCase.SourceInformation.FileName}"); + LogMessage($"{messageType}: TestCase.SourceInformation.LineNumber: {testCase.SourceInformation.LineNumber}"); + } + } + + + public bool OnMessage(IMessageSinkMessage message) + { + HandleMessageSinkMessage(message); + return _messageSink.OnMessage(message); + } + + private void HandleMessageSinkMessage(IMessageSinkMessage message) + { + switch (message) + { + + case ITestContextMessage testContext: + LogMessage($"TestContext: {testContext}"); + break; + + case ITestAssemblyStarting testAssemblyStarting: + LogMessage($"TestAssemblyStarting: StartTime: {testAssemblyStarting.StartTime}"); + LogMessage($"TestAssemblyStarting: TestFrameworkDisplayName: {testAssemblyStarting.TestFrameworkDisplayName}"); + LogMessage($"TestAssemblyStarting: TestEnvironment: {testAssemblyStarting.TestEnvironment}"); + LogMessage($"TestAssemblyStarting: TestCases.Count: {testAssemblyStarting.TestCases.Count()}"); + break; + + case ITestCollectionStarting testCollectionStarting: + LogMessage($"TestCollectionStarting: TestCollection.DisplayName: {testCollectionStarting.TestCollection.DisplayName}"); + LogMessage($"TestCollectionStarting: TestCollection.UniqueID: {testCollectionStarting.TestCollection.UniqueID}"); + LogMessage($"TestCollectionStarting: TestCollection.TestCases.Count: {testCollectionStarting.TestCases.Count()}"); + LogMessage($"TestCollectionStarting: TestAssembly.Assembly.Name: {testCollectionStarting.TestAssembly.Assembly.Name}"); + break; + + + case ITestMethodStarting testMethodStarting: + LogMessage($"TestMethodStarting: TestCollection.DisplayName: {testMethodStarting.TestCollection.DisplayName}"); + LogMessage($"TestMethodStarting: TestCollection.UniqueID: {testMethodStarting.TestCollection.UniqueID}"); + LogMessage($"TestMethodStarting: TestCollection.TestAssembly.Assembly.AssemblyPath: {testMethodStarting.TestCollection.TestAssembly.Assembly.AssemblyPath}"); + LogMessage($"TestMethodStarting: TestCases.Count: {testMethodStarting.TestCases.Count()}"); + + LogMessage($"TestMethodStarting: TestClass.Class.Name: {testMethodStarting.TestClass.Class.Name}"); + break; + + case ITestCaseStarting testCaseStarting: + LogMessage("TestCaseStarting"); + break; + + case ITestStarting testStarting: + LogMessage($"TestStarting: Test.DisplayName: {testStarting.Test.DisplayName}"); + break; + + case ITestClassConstructionStarting classConstructionStarting: + LogMessage($"TestClassConstructionStarting: Test.DisplayName: {classConstructionStarting.Test.DisplayName}"); + LogMessage($"TestClassConstructionStarting: Test.TestCase.DisplayName: {classConstructionStarting.Test.TestCase.DisplayName}"); + LogMessage($"TestClassConstructionStarting: Test.TestCase.UniqueID: {classConstructionStarting.Test.TestCase.UniqueID}"); + LogMessage($"TestClassConstructionStarting: Test.TestCase.TestMethod.Method.Name: {classConstructionStarting.Test.TestCase.TestMethod.Method.Name}"); + break; + + case ITestClassConstructionFinished classConstructionFinished: + // Code to handle Xunit.Sdk.TestClassConstructionFinished case + break; + + + case ITestSkipped testSkipped: + // Code to handle Xunit.Sdk.TestSkipped case + break; + + case ITestPassed testPassed: + LogMessage($"TestPassed: Output: {testPassed.Output}"); + LogMessage($"TestPassed: ExcecutionTime: {testPassed.ExecutionTime}"); + LogMessage($"TestPassed: Test.DisplayName: {testPassed.Test.DisplayName}"); + LogMessage($"TestPassed: TestCase.UniqueID: {testPassed.TestCase.UniqueID}"); + LogMessage($"TestPassed: TestCase.DisplayName: {testPassed.TestCase.DisplayName}"); + LogMessage($"TestPassed: TestCases.Count: {testPassed.TestCases.Count()}"); + + // Code to handle Xunit.Sdk.TestPassed case + break; + + case ITestFailed testFailed: + LogMessage($"TestFailed: ExecutionTime: {testFailed.ExecutionTime}"); + LogMessage($"TestFailed: Messages: {string.Join('\n', testFailed.Messages)}"); + LogMessage($"TestFailed: Output: {testFailed.Output}"); + // Code to handle Xunit.Sdk.TestFailed case + break; + + case ITestFinished testFinished: + // Code to handle Xunit.Sdk.TestFinished case + break; + + case ITestCaseFinished testCaseFinished: + // Code to handle Xunit.Sdk.TestCaseFinished case + break; + + + case ITestMethodFinished testMethodFinished: + // Code to handle Xunit.Sdk.TestMethodFinished case + break; + + case ITestClassStarting testClassStarting: + break; + + case ITestOutput TestOutput: + break; + + case ITestClassFinished testClassFinished: + break; + + case ITestCollectionFinished testCollectionFinished: + break; + + case ITestAssemblyFinished testAssemblyFinished: + LogMessage($"TestAssemblyFinished: TestsRun: {testAssemblyFinished.TestsRun}"); + LogMessage($"TestAssemblyFinished: TestsFailed: {testAssemblyFinished.TestsFailed}"); + LogMessage($"TestAssemblyFinished: TestsSkipped: {testAssemblyFinished.TestsSkipped}"); + LogMessage($"TestAssemblyFinished: ExecutionTime: {testAssemblyFinished.ExecutionTime}"); + break; + + default: + LogMessage($"UNKNOWN: {message.GetType().Name}"); + break; + } + } + } +} diff --git a/src/KiBoards/TestResultBus.cs b/src/KiBoards/TestResultBus.cs new file mode 100644 index 0000000..87a3000 --- /dev/null +++ b/src/KiBoards/TestResultBus.cs @@ -0,0 +1,28 @@ +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards +{ + internal class TestResultBus : IMessageBus + { + private IMessageBus _messageBus; + + public ITestResultMessage TestResult { get; private set; } + + internal TestResultBus(IMessageBus messsageBus) => _messageBus = messsageBus ?? throw new ArgumentNullException(nameof(messsageBus)); + + + public bool QueueMessage(IMessageSinkMessage message) + { + if (message is ITestResultMessage result) + TestResult = result; + + return _messageBus.QueueMessage(message); + } + + public void Dispose() + { + _messageBus.Dispose(); + } + } +} diff --git a/src/KiBoards/TestResultSink.cs b/src/KiBoards/TestResultSink.cs new file mode 100644 index 0000000..a49a4cd --- /dev/null +++ b/src/KiBoards/TestResultSink.cs @@ -0,0 +1,24 @@ +using Xunit.Abstractions; + +namespace KiBoards +{ + internal class TestResultSink : IMessageSink + { + private IMessageSink _messageSink; + + public ITestResultMessage TestResult { get; private set; } + + internal TestResultSink(IMessageSink messageSink) + { + _messageSink = messageSink; + } + + public bool OnMessage(IMessageSinkMessage message) + { + if (message is ITestResultMessage result) + TestResult = result; + + return _messageSink.OnMessage(message); + } + } +} From 002eeee4464811b5c08eefc8e47e408321315bdb Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 21 Sep 2023 23:55:40 +0100 Subject: [PATCH 09/12] Fix problem with error messages during bulk index to elastic serach --- src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs b/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs index dbde2f2..25bb63d 100644 --- a/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs +++ b/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs @@ -1,7 +1,6 @@ using KiBoards.Models; using Microsoft.Extensions.DependencyInjection; using Nest; -using System; namespace KiBoards.Services { @@ -12,6 +11,8 @@ internal static IServiceCollection AddElasticServices(this IServiceCollection se return services .AddSingleton(new ElasticClient(ConfigureIndexes(new ConnectionSettings(new Uri($"http://localhost:9200")) .MaxRetryTimeout(TimeSpan.FromMinutes(5)) + // This resolves internal errors with bulk index Invalid NEST response built from a successful (200) low level call on POST: /_bulk + .EnableApiVersioningHeader() .MaximumRetries(3)))) .AddTransient(); } From b4198b10c4e7d5e9c6709a7c7968e73559955be0 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 21 Sep 2023 23:56:04 +0100 Subject: [PATCH 10/12] Add new visualization to test case status dashboard --- res/TestCaseStatus.ndjson | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/TestCaseStatus.ndjson b/res/TestCaseStatus.ndjson index 3044bf3..87d6a87 100644 --- a/res/TestCaseStatus.ndjson +++ b/res/TestCaseStatus.ndjson @@ -1,5 +1,5 @@ -{"attributes":{"fieldAttrs":"{\"displayName\":{\"count\":2},\"state\":{\"count\":1},\"uniqueId\":{\"customLabel\":\"Id\",\"count\":1},\"status\":{\"customLabel\":\"Status\",\"count\":1},\"summary.time\":{\"count\":1}}","fieldFormatMap":"{\"status\":{\"id\":\"color\",\"params\":{\"parsedUrl\":{\"origin\":\"http://localhost:5601\",\"pathname\":\"/app/home\",\"basePath\":\"\"},\"fieldType\":\"string\",\"colors\":[{\"range\":\"-Infinity:Infinity\",\"regex\":\"Success\",\"text\":\"#459b83\",\"background\":\"#ffffff\"},{\"range\":\"-Infinity:Infinity\",\"regex\":\"Failure\",\"text\":\"#E7664C\",\"background\":\"#ffffff\"},{\"range\":\"-Infinity:Infinity\",\"regex\":\"Skipped\",\"text\":\"#D6BF57\",\"background\":\"#ffffff\"}]}}}","fields":"[]","name":"Test Case Status View","runtimeFieldMap":"{}","sourceFilters":"[]","timeFieldName":"","title":"kiboards-testcase-status-*","typeMeta":"{}"},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T21:26:05.088Z","id":"641b8927-249c-4669-9dea-a6bf989c8556","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2023-08-06T22:47:01.692Z","version":"WzM2NSwxXQ=="} -{"attributes":{"columns":["uniqueId","status","displayName"],"description":"","grid":{"columns":{"status":{"width":86},"uniqueId":{"width":313}}},"hideChart":false,"isTextBasedQuery":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"rowHeight":-1,"sort":[],"timeRestore":false,"title":"Test Case Status Search","usesAdHocDataView":false,"viewMode":"documents"},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T22:24:20.672Z","id":"fd2b4c00-34a7-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","typeMigrationVersion":"8.0.0","updated_at":"2023-08-06T22:46:19.042Z","version":"WzM2MywxXQ=="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"8.8.2\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":29,\"i\":\"f0134ca4-cbcd-483e-9107-6e93fba7de2f\"},\"panelIndex\":\"f0134ca4-cbcd-483e-9107-6e93fba7de2f\",\"embeddableConfig\":{\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Details\",\"panelRefName\":\"panel_f0134ca4-cbcd-483e-9107-6e93fba7de2f\"}]","timeRestore":false,"title":"Test Case Details","version":1},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T22:43:57.280Z","id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"fd2b4c00-34a7-11ee-8f8e-e312ee55ca24","name":"f0134ca4-cbcd-483e-9107-6e93fba7de2f:panel_f0134ca4-cbcd-483e-9107-6e93fba7de2f","type":"search"}],"type":"dashboard","typeMigrationVersion":"8.7.0","updated_at":"2023-08-06T22:43:57.280Z","version":"WzM1MiwxXQ=="} -{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":8,\"h\":6,\"i\":\"10c370c6-5da2-4507-ad86-af1119649a69\"},\"panelIndex\":\"10c370c6-5da2-4507-ad86-af1119649a69\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":1},{\"color\":\"#343741\",\"stop\":20}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#343741\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Total\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":8,\"y\":0,\"w\":8,\"h\":6,\"i\":\"0b4751ed-1f30-4405-9801-1ccf24a0b956\"},\"panelIndex\":\"0b4751ed-1f30-4405-9801-1ccf24a0b956\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":20},{\"color\":\"#6d7482\",\"stop\":50},{\"color\":\"#343741\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#6d7482\",\"stop\":20},{\"color\":\"#343741\",\"stop\":50}]}},\"titlePosition\":\"top\",\"size\":\"l\",\"textAlign\":\"center\"},\"query\":{\"query\":\"status.keyword : \\\"Discovered\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Discovered\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":16,\"y\":0,\"w\":8,\"h\":6,\"i\":\"408ce981-f6e4-48c8-85c0-78231aa10b65\"},\"panelIndex\":\"408ce981-f6e4-48c8-85c0-78231aa10b65\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":20},{\"color\":\"#6d7482\",\"stop\":50},{\"color\":\"#343741\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#6d7482\",\"stop\":20},{\"color\":\"#343741\",\"stop\":50}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Running\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Running\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"Running\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":8,\"h\":6,\"i\":\"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7\"},\"panelIndex\":\"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#00000054\",\"stop\":1},{\"color\":\"#209280\",\"stop\":18}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#00000054\",\"stop\":0},{\"color\":\"#209280\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Success\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Success\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":32,\"y\":0,\"w\":8,\"h\":6,\"i\":\"446f37b5-2f7f-4814-8d3f-f7b1cae9e007\"},\"panelIndex\":\"446f37b5-2f7f-4814-8d3f-f7b1cae9e007\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#27987e\",\"stop\":1},{\"color\":\"#E7664C\",\"stop\":18}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#27987e\",\"stop\":0},{\"color\":\"#E7664C\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Failure\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Failure\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":40,\"y\":0,\"w\":8,\"h\":6,\"i\":\"f33640a2-03d3-4cb8-9514-ac7eddb8342c\"},\"panelIndex\":\"f33640a2-03d3-4cb8-9514-ac7eddb8342c\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#0000003b\",\"stop\":1},{\"color\":\"#D6BF57\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#0000003b\",\"stop\":0},{\"color\":\"#D6BF57\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Skipped\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Skipped\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":6,\"w\":24,\"h\":15,\"i\":\"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5\"},\"panelIndex\":\"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Test Cases\",\"description\":\"\",\"visualizationType\":\"lnsPie\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"shape\":\"donut\",\"palette\":{\"type\":\"palette\",\"name\":\"positive\"},\"layers\":[{\"layerId\":\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"primaryGroups\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\"],\"metrics\":[\"742e3600-35ca-4446-aac6-519f26cb3b13\"],\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"hide\",\"nestedLegend\":false,\"layerType\":\"data\",\"emptySizeRatio\":0.54,\"truncateLegend\":true,\"legendPosition\":\"left\",\"allowMultipleMetrics\":false}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\":{\"columns\":{\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\":{\"label\":\"Top 6 values of status.keyword\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"status.keyword\",\"isBucketed\":true,\"params\":{\"size\":6,\"orderBy\":{\"type\":\"column\",\"columnId\":\"742e3600-35ca-4446-aac6-519f26cb3b13\"},\"orderDirection\":\"asc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}},\"742e3600-35ca-4446-aac6-519f26cb3b13\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"742e3600-35ca-4446-aac6-519f26cb3b13\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"bf63f130-7338-4092-ba4d-8b2b9a9d478c\",\"triggers\":[\"FILTER_TRIGGER\"],\"action\":{\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\",\"name\":\"Go to test case details...\",\"config\":{\"useCurrentFilters\":true,\"useCurrentDateRange\":false,\"openInNewTab\":false}}}]}},\"hidePanelTitles\":true}},{\"version\":\"8.8.2\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":6,\"w\":24,\"h\":15,\"i\":\"d0939bca-79c1-4c67-bdd6-51c445abcf56\"},\"panelIndex\":\"d0939bca-79c1-4c67-bdd6-51c445abcf56\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Test Cases\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"type\":\"index-pattern\",\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":false,\"position\":\"bottom\",\"showSingleSeries\":false,\"isInside\":false,\"shouldTruncate\":false},\"valueLabels\":\"show\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":false,\"yLeft\":false,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":false,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":false,\"yLeft\":false,\"yRight\":true},\"preferredSeriesType\":\"bar_horizontal_stacked\",\"layers\":[{\"layerId\":\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"seriesType\":\"bar_horizontal_stacked\",\"xAccessor\":\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"accessors\":[\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"64851214-2c34-44e3-838b-0af27323929b\",\"56018286-5231-4400-8d02-7653525b322a\",\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"2724574b-d6f9-4f13-8eb0-646a4b863619\"],\"yConfig\":[{\"forAccessor\":\"64851214-2c34-44e3-838b-0af27323929b\",\"color\":\"#54b399\"},{\"forAccessor\":\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"color\":\"#e7664c\"},{\"forAccessor\":\"56018286-5231-4400-8d02-7653525b322a\",\"color\":\"#d6bf57\"},{\"forAccessor\":\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"color\":\"#aaaaaa\",\"axisMode\":\"auto\"},{\"forAccessor\":\"2724574b-d6f9-4f13-8eb0-646a4b863619\",\"color\":\"#cccccc\"}],\"layerType\":\"data\"}],\"yLeftExtent\":{\"mode\":\"full\",\"niceValues\":false}},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\":{\"columns\":{\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\":{\"label\":\"Status\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"status.keyword\",\"isBucketed\":true,\"params\":{\"size\":6,\"orderBy\":{\"type\":\"custom\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"orderAgg\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}},\"secondaryFields\":[]},\"customLabel\":true},\"742e3600-35ca-4446-aac6-519f26cb3b13\":{\"label\":\"Failure\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0}}},\"customLabel\":true,\"filter\":{\"query\":\"status.keyword : \\\"Failure\\\" \",\"language\":\"kuery\"}},\"64851214-2c34-44e3-838b-0af27323929b\":{\"label\":\"Success\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Success\\\" \",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"56018286-5231-4400-8d02-7653525b322a\":{\"label\":\"Skipped\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Skipped\\\"\",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\":{\"label\":\"Running\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Running\\\"\",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2724574b-d6f9-4f13-8eb0-646a4b863619\":{\"label\":\"Discovered\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Discovered\\\" \",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true}},\"columnOrder\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"64851214-2c34-44e3-838b-0af27323929b\",\"56018286-5231-4400-8d02-7653525b322a\",\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"2724574b-d6f9-4f13-8eb0-646a4b863619\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"2b53c149-d516-401e-a487-c6efda1ade02\",\"triggers\":[\"FILTER_TRIGGER\"],\"action\":{\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\",\"name\":\"Go to test case details...\",\"config\":{\"useCurrentFilters\":true,\"useCurrentDateRange\":false,\"openInNewTab\":false}}}]}},\"hidePanelTitles\":true},\"title\":\"\"}]","timeRestore":false,"title":"Test Case Status","version":1},"coreMigrationVersion":"8.8.0","created_at":"2023-08-06T22:39:40.297Z","id":"1b934de0-34a9-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"10c370c6-5da2-4507-ad86-af1119649a69:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"0b4751ed-1f30-4405-9801-1ccf24a0b956:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"408ce981-f6e4-48c8-85c0-78231aa10b65:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"446f37b5-2f7f-4814-8d3f-f7b1cae9e007:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"f33640a2-03d3-4cb8-9514-ac7eddb8342c:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5:indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216","type":"index-pattern"},{"id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","name":"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:bf63f130-7338-4092-ba4d-8b2b9a9d478c:dashboardId","type":"dashboard"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"d0939bca-79c1-4c67-bdd6-51c445abcf56:indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216","type":"index-pattern"},{"id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","name":"d0939bca-79c1-4c67-bdd6-51c445abcf56:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:2b53c149-d516-401e-a487-c6efda1ade02:dashboardId","type":"dashboard"}],"type":"dashboard","typeMigrationVersion":"8.7.0","updated_at":"2023-08-06T22:39:40.297Z","version":"WzMzMiwxXQ=="} +{"attributes":{"fieldAttrs":"{\"displayName\":{\"count\":2},\"state\":{\"count\":1},\"uniqueId\":{\"customLabel\":\"Id\",\"count\":1},\"status\":{\"customLabel\":\"Status\",\"count\":1},\"summary.time\":{\"count\":1}}","fieldFormatMap":"{\"status\":{\"id\":\"color\",\"params\":{\"parsedUrl\":{\"origin\":\"http://localhost:5601\",\"pathname\":\"/app/home\",\"basePath\":\"\"},\"fieldType\":\"string\",\"colors\":[{\"range\":\"-Infinity:Infinity\",\"regex\":\"Success\",\"text\":\"#459b83\",\"background\":\"#ffffff\"},{\"range\":\"-Infinity:Infinity\",\"regex\":\"Failure\",\"text\":\"#E7664C\",\"background\":\"#ffffff\"},{\"range\":\"-Infinity:Infinity\",\"regex\":\"Skipped\",\"text\":\"#D6BF57\",\"background\":\"#ffffff\"}]}}}","fields":"[]","name":"Test Case Status View","runtimeFieldMap":"{}","sourceFilters":"[]","timeFieldName":"","title":"kiboards-testcase-status-*","typeMeta":"{}"},"coreMigrationVersion":"8.8.0","created_at":"2023-09-21T21:40:51.247Z","id":"641b8927-249c-4669-9dea-a6bf989c8556","managed":false,"references":[],"type":"index-pattern","typeMigrationVersion":"8.0.0","updated_at":"2023-09-21T21:40:51.247Z","version":"WzUsMl0="} +{"attributes":{"columns":["uniqueId","status","displayName"],"description":"","grid":{"columns":{"status":{"width":86},"uniqueId":{"width":313}}},"hideChart":false,"isTextBasedQuery":false,"kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}"},"rowHeight":-1,"sort":[],"timeRestore":false,"title":"Test Case Status Search","usesAdHocDataView":false,"viewMode":"documents"},"coreMigrationVersion":"8.8.0","created_at":"2023-09-21T21:40:51.247Z","id":"fd2b4c00-34a7-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"}],"type":"search","typeMigrationVersion":"8.0.0","updated_at":"2023-09-21T21:40:51.247Z","version":"WzYsMl0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"8.8.2\",\"type\":\"search\",\"gridData\":{\"x\":0,\"y\":0,\"w\":48,\"h\":29,\"i\":\"f0134ca4-cbcd-483e-9107-6e93fba7de2f\"},\"panelIndex\":\"f0134ca4-cbcd-483e-9107-6e93fba7de2f\",\"embeddableConfig\":{\"hidePanelTitles\":false,\"enhancements\":{}},\"title\":\"Details\",\"panelRefName\":\"panel_f0134ca4-cbcd-483e-9107-6e93fba7de2f\"}]","timeRestore":false,"title":"Test Case Details","version":1},"coreMigrationVersion":"8.8.0","created_at":"2023-09-21T21:40:51.247Z","id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"fd2b4c00-34a7-11ee-8f8e-e312ee55ca24","name":"f0134ca4-cbcd-483e-9107-6e93fba7de2f:panel_f0134ca4-cbcd-483e-9107-6e93fba7de2f","type":"search"}],"type":"dashboard","typeMigrationVersion":"8.9.0","updated_at":"2023-09-21T21:40:51.247Z","version":"WzcsMl0="} +{"attributes":{"description":"","kibanaSavedObjectMeta":{"searchSourceJSON":"{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}"},"optionsJSON":"{\"useMargins\":true,\"syncColors\":false,\"syncCursor\":true,\"syncTooltips\":false,\"hidePanelTitles\":false}","panelsJSON":"[{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":0,\"w\":8,\"h\":6,\"i\":\"10c370c6-5da2-4507-ad86-af1119649a69\"},\"panelIndex\":\"10c370c6-5da2-4507-ad86-af1119649a69\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":1},{\"color\":\"#343741\",\"stop\":20}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#343741\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Total\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":8,\"y\":0,\"w\":8,\"h\":6,\"i\":\"0b4751ed-1f30-4405-9801-1ccf24a0b956\"},\"panelIndex\":\"0b4751ed-1f30-4405-9801-1ccf24a0b956\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":20},{\"color\":\"#6d7482\",\"stop\":50},{\"color\":\"#343741\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#6d7482\",\"stop\":20},{\"color\":\"#343741\",\"stop\":50}]}},\"titlePosition\":\"top\",\"size\":\"l\",\"textAlign\":\"center\"},\"query\":{\"query\":\"status.keyword : \\\"Discovered\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Discovered\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":16,\"y\":0,\"w\":8,\"h\":6,\"i\":\"408ce981-f6e4-48c8-85c0-78231aa10b65\"},\"panelIndex\":\"408ce981-f6e4-48c8-85c0-78231aa10b65\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#afb8c6\",\"stop\":20},{\"color\":\"#6d7482\",\"stop\":50},{\"color\":\"#343741\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#afb8c6\",\"stop\":0},{\"color\":\"#6d7482\",\"stop\":20},{\"color\":\"#343741\",\"stop\":50}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Running\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Running\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"Running\"},{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":24,\"y\":0,\"w\":8,\"h\":6,\"i\":\"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7\"},\"panelIndex\":\"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#00000054\",\"stop\":1},{\"color\":\"#209280\",\"stop\":18}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#00000054\",\"stop\":0},{\"color\":\"#209280\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Success\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Success\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":32,\"y\":0,\"w\":8,\"h\":6,\"i\":\"446f37b5-2f7f-4814-8d3f-f7b1cae9e007\"},\"panelIndex\":\"446f37b5-2f7f-4814-8d3f-f7b1cae9e007\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#27987e\",\"stop\":1},{\"color\":\"#E7664C\",\"stop\":18}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#27987e\",\"stop\":0},{\"color\":\"#E7664C\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Failure\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Failure\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":40,\"y\":0,\"w\":8,\"h\":6,\"i\":\"f33640a2-03d3-4cb8-9514-ac7eddb8342c\"},\"panelIndex\":\"f33640a2-03d3-4cb8-9514-ac7eddb8342c\",\"embeddableConfig\":{\"attributes\":{\"title\":\"\",\"description\":\"\",\"visualizationType\":\"lnsLegacyMetric\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"layerId\":\"be565c3a-655e-4ed9-97f2-7b4435618318\",\"accessor\":\"c442ed00-679d-451f-b0b1-da6b8674d186\",\"layerType\":\"data\",\"colorMode\":\"Labels\",\"palette\":{\"name\":\"custom\",\"type\":\"palette\",\"params\":{\"steps\":3,\"name\":\"custom\",\"reverse\":false,\"rangeType\":\"number\",\"rangeMin\":0,\"rangeMax\":null,\"progression\":\"fixed\",\"stops\":[{\"color\":\"#0000003b\",\"stop\":1},{\"color\":\"#D6BF57\",\"stop\":100}],\"continuity\":\"above\",\"maxSteps\":5,\"colorStops\":[{\"color\":\"#0000003b\",\"stop\":0},{\"color\":\"#D6BF57\",\"stop\":1}]}},\"textAlign\":\"center\",\"size\":\"l\"},\"query\":{\"query\":\"status.keyword : \\\"Skipped\\\" \",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"be565c3a-655e-4ed9-97f2-7b4435618318\":{\"columns\":{\"c442ed00-679d-451f-b0b1-da6b8674d186\":{\"label\":\"Skipped\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0,\"suffix\":\"\"}}},\"customLabel\":true}},\"columnOrder\":[\"c442ed00-679d-451f-b0b1-da6b8674d186\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"hidePanelTitles\":true,\"description\":\"Currently running test cases\",\"enhancements\":{}},\"title\":\"\"},{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":0,\"y\":6,\"w\":16,\"h\":15,\"i\":\"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5\"},\"panelIndex\":\"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Test Cases\",\"description\":\"\",\"visualizationType\":\"lnsPie\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"shape\":\"donut\",\"palette\":{\"type\":\"palette\",\"name\":\"positive\"},\"layers\":[{\"layerId\":\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"primaryGroups\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\"],\"metrics\":[\"742e3600-35ca-4446-aac6-519f26cb3b13\"],\"numberDisplay\":\"percent\",\"categoryDisplay\":\"default\",\"legendDisplay\":\"hide\",\"nestedLegend\":false,\"layerType\":\"data\",\"emptySizeRatio\":0.54,\"truncateLegend\":true,\"legendPosition\":\"left\",\"allowMultipleMetrics\":false}]},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\":{\"columns\":{\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\":{\"label\":\"Top 6 values of status.keyword\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"status.keyword\",\"isBucketed\":true,\"params\":{\"size\":6,\"orderBy\":{\"type\":\"column\",\"columnId\":\"742e3600-35ca-4446-aac6-519f26cb3b13\"},\"orderDirection\":\"asc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false}},\"742e3600-35ca-4446-aac6-519f26cb3b13\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}}},\"columnOrder\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"742e3600-35ca-4446-aac6-519f26cb3b13\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"bf63f130-7338-4092-ba4d-8b2b9a9d478c\",\"triggers\":[\"FILTER_TRIGGER\"],\"action\":{\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\",\"name\":\"Go to test case details...\",\"config\":{\"useCurrentFilters\":true,\"useCurrentDateRange\":false,\"openInNewTab\":false}}}]}},\"hidePanelTitles\":true}},{\"version\":\"8.9.2\",\"type\":\"visualization\",\"gridData\":{\"x\":16,\"y\":6,\"w\":16,\"h\":15,\"i\":\"873943d5-ace4-4e99-bbd2-221623eaf293\"},\"panelIndex\":\"873943d5-ace4-4e99-bbd2-221623eaf293\",\"embeddableConfig\":{\"savedVis\":{\"id\":\"\",\"title\":\"\",\"description\":\"\",\"type\":\"tagcloud\",\"params\":{\"scale\":\"linear\",\"orientation\":\"single\",\"minFontSize\":26,\"maxFontSize\":72,\"showLabel\":false,\"palette\":{\"type\":\"palette\",\"name\":\"status\"}},\"uiState\":{},\"data\":{\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"params\":{\"emptyAsNull\":false},\"schema\":\"metric\"},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"params\":{\"field\":\"status.keyword\",\"orderBy\":\"1\",\"order\":\"desc\",\"size\":5,\"otherBucket\":true,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\",\"includeIsRegex\":true,\"excludeIsRegex\":true},\"schema\":\"segment\"}],\"searchSource\":{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}}},\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"a3885ac3-b583-429d-bfbd-36aa4b5ac2a3\",\"triggers\":[\"FILTER_TRIGGER\"],\"action\":{\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\",\"name\":\"Go to Dashboard\",\"config\":{\"useCurrentFilters\":false,\"useCurrentDateRange\":false,\"openInNewTab\":false}}}]}}}},{\"version\":\"8.9.2\",\"type\":\"lens\",\"gridData\":{\"x\":32,\"y\":6,\"w\":16,\"h\":15,\"i\":\"d0939bca-79c1-4c67-bdd6-51c445abcf56\"},\"panelIndex\":\"d0939bca-79c1-4c67-bdd6-51c445abcf56\",\"embeddableConfig\":{\"attributes\":{\"title\":\"Test Cases\",\"description\":\"\",\"visualizationType\":\"lnsXY\",\"type\":\"lens\",\"references\":[{\"id\":\"641b8927-249c-4669-9dea-a6bf989c8556\",\"name\":\"indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"type\":\"index-pattern\"}],\"state\":{\"visualization\":{\"legend\":{\"isVisible\":false,\"position\":\"bottom\",\"showSingleSeries\":false,\"isInside\":false,\"shouldTruncate\":false},\"valueLabels\":\"show\",\"fittingFunction\":\"None\",\"axisTitlesVisibilitySettings\":{\"x\":false,\"yLeft\":false,\"yRight\":true},\"tickLabelsVisibilitySettings\":{\"x\":true,\"yLeft\":false,\"yRight\":true},\"labelsOrientation\":{\"x\":0,\"yLeft\":0,\"yRight\":0},\"gridlinesVisibilitySettings\":{\"x\":false,\"yLeft\":false,\"yRight\":true},\"preferredSeriesType\":\"bar_horizontal_stacked\",\"layers\":[{\"layerId\":\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\",\"seriesType\":\"bar_horizontal_stacked\",\"xAccessor\":\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"accessors\":[\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"64851214-2c34-44e3-838b-0af27323929b\",\"56018286-5231-4400-8d02-7653525b322a\",\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"2724574b-d6f9-4f13-8eb0-646a4b863619\"],\"yConfig\":[{\"forAccessor\":\"64851214-2c34-44e3-838b-0af27323929b\",\"color\":\"#54b399\"},{\"forAccessor\":\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"color\":\"#e7664c\"},{\"forAccessor\":\"56018286-5231-4400-8d02-7653525b322a\",\"color\":\"#d6bf57\"},{\"forAccessor\":\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"color\":\"#aaaaaa\",\"axisMode\":\"auto\"},{\"forAccessor\":\"2724574b-d6f9-4f13-8eb0-646a4b863619\",\"color\":\"#cccccc\"}],\"layerType\":\"data\"}],\"yLeftExtent\":{\"mode\":\"full\",\"niceValues\":false}},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[],\"datasourceStates\":{\"formBased\":{\"layers\":{\"6f0b74bd-09b6-4d1a-a8b5-92e6cf653216\":{\"columns\":{\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\":{\"label\":\"Status\",\"dataType\":\"string\",\"operationType\":\"terms\",\"scale\":\"ordinal\",\"sourceField\":\"status.keyword\",\"isBucketed\":true,\"params\":{\"size\":6,\"orderBy\":{\"type\":\"custom\"},\"orderDirection\":\"desc\",\"otherBucket\":false,\"missingBucket\":false,\"parentFormat\":{\"id\":\"terms\"},\"include\":[],\"exclude\":[],\"includeIsRegex\":false,\"excludeIsRegex\":false,\"orderAgg\":{\"label\":\"Count of records\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"___records___\",\"params\":{\"emptyAsNull\":true}},\"secondaryFields\":[]},\"customLabel\":true},\"742e3600-35ca-4446-aac6-519f26cb3b13\":{\"label\":\"Failure\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"params\":{\"emptyAsNull\":false,\"format\":{\"id\":\"number\",\"params\":{\"decimals\":0}}},\"customLabel\":true,\"filter\":{\"query\":\"status.keyword : \\\"Failure\\\" \",\"language\":\"kuery\"}},\"64851214-2c34-44e3-838b-0af27323929b\":{\"label\":\"Success\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Success\\\" \",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"56018286-5231-4400-8d02-7653525b322a\":{\"label\":\"Skipped\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Skipped\\\"\",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\":{\"label\":\"Running\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Running\\\"\",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true},\"2724574b-d6f9-4f13-8eb0-646a4b863619\":{\"label\":\"Discovered\",\"dataType\":\"number\",\"operationType\":\"count\",\"isBucketed\":false,\"scale\":\"ratio\",\"sourceField\":\"status.keyword\",\"filter\":{\"query\":\"status.keyword : \\\"Discovered\\\" \",\"language\":\"kuery\"},\"params\":{\"emptyAsNull\":false},\"customLabel\":true}},\"columnOrder\":[\"6fc4244c-c2d2-4558-8016-cc3d656f4dba\",\"742e3600-35ca-4446-aac6-519f26cb3b13\",\"64851214-2c34-44e3-838b-0af27323929b\",\"56018286-5231-4400-8d02-7653525b322a\",\"ee233af9-d011-4bcd-a19e-275aaf9f36f1\",\"2724574b-d6f9-4f13-8eb0-646a4b863619\"],\"incompleteColumns\":{},\"sampling\":1}}},\"textBased\":{\"layers\":{}}},\"internalReferences\":[],\"adHocDataViews\":{}}},\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"2b53c149-d516-401e-a487-c6efda1ade02\",\"triggers\":[\"FILTER_TRIGGER\"],\"action\":{\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\",\"name\":\"Go to test case details...\",\"config\":{\"useCurrentFilters\":true,\"useCurrentDateRange\":false,\"openInNewTab\":false}}}]}},\"hidePanelTitles\":true},\"title\":\"\"}]","timeRestore":false,"title":"Test Case Status","version":1},"coreMigrationVersion":"8.8.0","created_at":"2023-09-21T22:06:31.557Z","id":"1b934de0-34a9-11ee-8f8e-e312ee55ca24","managed":false,"references":[{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"10c370c6-5da2-4507-ad86-af1119649a69:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"0b4751ed-1f30-4405-9801-1ccf24a0b956:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"408ce981-f6e4-48c8-85c0-78231aa10b65:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"ba96163c-6fff-4602-bbe1-bd6e4c1d01b7:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"446f37b5-2f7f-4814-8d3f-f7b1cae9e007:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"f33640a2-03d3-4cb8-9514-ac7eddb8342c:indexpattern-datasource-layer-be565c3a-655e-4ed9-97f2-7b4435618318","type":"index-pattern"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5:indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216","type":"index-pattern"},{"id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","name":"2be22eb0-e753-4d1d-8ec5-bdde80a69fd5:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:bf63f130-7338-4092-ba4d-8b2b9a9d478c:dashboardId","type":"dashboard"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"873943d5-ace4-4e99-bbd2-221623eaf293:kibanaSavedObjectMeta.searchSourceJSON.index","type":"index-pattern"},{"id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","name":"873943d5-ace4-4e99-bbd2-221623eaf293:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:a3885ac3-b583-429d-bfbd-36aa4b5ac2a3:dashboardId","type":"dashboard"},{"id":"641b8927-249c-4669-9dea-a6bf989c8556","name":"d0939bca-79c1-4c67-bdd6-51c445abcf56:indexpattern-datasource-layer-6f0b74bd-09b6-4d1a-a8b5-92e6cf653216","type":"index-pattern"},{"id":"00115f80-34a9-11ee-8f8e-e312ee55ca24","name":"d0939bca-79c1-4c67-bdd6-51c445abcf56:drilldown:DASHBOARD_TO_DASHBOARD_DRILLDOWN:2b53c149-d516-401e-a487-c6efda1ade02:dashboardId","type":"dashboard"}],"type":"dashboard","typeMigrationVersion":"8.9.0","updated_at":"2023-09-21T22:06:31.557Z","version":"WzE2OSwyXQ=="} {"excludedObjects":[],"excludedObjectsCount":0,"exportedCount":4,"missingRefCount":0,"missingReferences":[]} \ No newline at end of file From a62c38177df6b15a91f1039646b0c0637c802b56 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 21 Sep 2023 23:57:12 +0100 Subject: [PATCH 11/12] Upgrade to the latest xunit --- src/KiBoards.Tests/KiBoards.Tests.csproj | 8 ++++---- src/KiBoards/KiBoards.csproj | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/KiBoards.Tests/KiBoards.Tests.csproj b/src/KiBoards.Tests/KiBoards.Tests.csproj index 95900e8..ae75601 100644 --- a/src/KiBoards.Tests/KiBoards.Tests.csproj +++ b/src/KiBoards.Tests/KiBoards.Tests.csproj @@ -12,13 +12,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/KiBoards/KiBoards.csproj b/src/KiBoards/KiBoards.csproj index 1e8c934..6260214 100644 --- a/src/KiBoards/KiBoards.csproj +++ b/src/KiBoards/KiBoards.csproj @@ -36,7 +36,7 @@ - + From 8b7203e58ab2fae03a75f6f3cd43429a7ffe05e1 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 21 Sep 2023 23:57:40 +0100 Subject: [PATCH 12/12] Add test case context indexing --- src/KiBoards.Tests/UnitTest1.cs | 2 +- src/KiBoards.Tests/UnitTest3.cs | 49 +++++++++++++++++++ .../Models/KiBoardsModelsExtensions.cs | 12 +++-- .../Models/KiBoardsTestCaseStatusDto.cs | 1 + .../Services/IKiBoardsTestRunnerService.cs | 2 + .../Services/KiBoardsTestRunnerService.cs | 18 ++++--- src/KiBoards/TestFramework.cs | 7 ++- src/KiBoards/TestMessageSink.cs | 4 +- src/KiBoards/TestResultBus.cs | 2 +- 9 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 src/KiBoards.Tests/UnitTest3.cs diff --git a/src/KiBoards.Tests/UnitTest1.cs b/src/KiBoards.Tests/UnitTest1.cs index d71db3e..8ffea7b 100644 --- a/src/KiBoards.Tests/UnitTest1.cs +++ b/src/KiBoards.Tests/UnitTest1.cs @@ -16,7 +16,7 @@ public UnitTest1(TestContextFixture testContextFixture, ITestOutputHelper testOu _testContextFixture = testContextFixture; _testOutputHelper = testOutputHelper; - _testContextFixture.SetContext(new { Version = "Context via Fixture" }); + _testContextFixture.SetContext(new { Version = "Context via Fixture", Hello = "World", Input = 1 }); } [Fact] diff --git a/src/KiBoards.Tests/UnitTest3.cs b/src/KiBoards.Tests/UnitTest3.cs new file mode 100644 index 0000000..9918374 --- /dev/null +++ b/src/KiBoards.Tests/UnitTest3.cs @@ -0,0 +1,49 @@ +using Xunit.Abstractions; + +namespace KiBoards.Tests +{ + + public class UnitTest3 : IClassFixture + { + + public UnitTest3(TestContextFixture testContextFixture, ITestOutputHelper outputHelper) + { + // This is how to get messageBus + + testContextFixture.SetContext(new { Version = "1234" }); + + outputHelper.WriteLine("HELLO WORLD MESSAGE BUS"); + } + + [Fact(Timeout = 1000)] + public void Test5() + { + Thread.Sleep(5000); + + + } + + [Theory] + [InlineData(1, 2)] + [InlineData(2, 2)] + [InlineData(3, 3)] + public void Test6(int a, int b) + { + Assert.Equal(a, b); + } + + + [Fact] + public void Test7() + { + throw new NotImplementedException(); + } + + [Fact(Skip = "Not required.")] + public void Test8() + { + + } + + } +} \ No newline at end of file diff --git a/src/KiBoards/Models/KiBoardsModelsExtensions.cs b/src/KiBoards/Models/KiBoardsModelsExtensions.cs index 70b2532..5734afa 100644 --- a/src/KiBoards/Models/KiBoardsModelsExtensions.cs +++ b/src/KiBoards/Models/KiBoardsModelsExtensions.cs @@ -1,4 +1,5 @@ -using Xunit.Abstractions; +using Nest; +using Xunit.Abstractions; using Xunit.Sdk; namespace KiBoards.Models @@ -6,7 +7,7 @@ namespace KiBoards.Models internal static class KiBoardsModelsExtensions { - internal static KiBoardsTestCaseStatusDto ToKiBoardsTestCase(this IXunitTestCase testCase, ITestMethod testMethod, KiBoardsTestCaseStatus status, KiBoardsTestCaseState state) => new KiBoardsTestCaseStatusDto() + internal static KiBoardsTestCaseStatusDto ToKiBoardsTestCase(this IXunitTestCase testCase, ITestMethod testMethod, KiBoardsTestCaseStatus status, KiBoardsTestCaseState state, object context = null) => new KiBoardsTestCaseStatusDto() { UniqueId = testCase.UniqueID, DisplayName = testCase.DisplayName, @@ -24,12 +25,13 @@ internal static class KiBoardsModelsExtensions { Name = testMethod?.Method.Name } - } + }, + Context = context }; - internal static IEnumerable ToKiBoardsTestCases(this IEnumerable testCases, KiBoardsTestCaseStatus status, KiBoardsTestCaseState state) => - testCases.Select(x => x.ToKiBoardsTestCase(null, status, state)); + internal static IEnumerable ToKiBoardsTestCases(this IEnumerable testCases, KiBoardsTestCaseStatus status, KiBoardsTestCaseState state, object context = null) => + testCases.Select(x => x.ToKiBoardsTestCase(null, status, state, context)); internal static KiBoardsTestCaseStatus ToKiBoardsTestCaseStatus(this RunSummary summary) => summary.Failed > 0 ? KiBoardsTestCaseStatus.Failure : summary.Skipped > 0 ? KiBoardsTestCaseStatus.Skipped : KiBoardsTestCaseStatus.Success; diff --git a/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs b/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs index 4b5602c..11043de 100644 --- a/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs +++ b/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs @@ -9,5 +9,6 @@ class KiBoardsTestCaseStatusDto public string State { get; set; } public string SkipReason { get; set; } public KiBoardsTestMethodDto TestMethod { get; set; } + public object Context { get; set; } } } diff --git a/src/KiBoards/Services/IKiBoardsTestRunnerService.cs b/src/KiBoards/Services/IKiBoardsTestRunnerService.cs index f1f409d..4713b0b 100644 --- a/src/KiBoards/Services/IKiBoardsTestRunnerService.cs +++ b/src/KiBoards/Services/IKiBoardsTestRunnerService.cs @@ -6,11 +6,13 @@ namespace KiBoards.Services internal interface IKiBoardsTestRunnerService { Guid RunId { get; } + Task BeginTestCasesRunAsync(IEnumerable testCases); Task StartTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod); Task FinishTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod, ExceptionAggregator exceptionAggregator, RunSummary result); Task ErrorTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod, Exception ex); Task EndTestCasesRunAsync(RunSummary results); Task ErrorTestCasesRunAsync(IEnumerable testCases, Exception ex); + void SetContext(ITestContextMessage testContext); } } \ No newline at end of file diff --git a/src/KiBoards/Services/KiBoardsTestRunnerService.cs b/src/KiBoards/Services/KiBoardsTestRunnerService.cs index 6489269..cb767ac 100644 --- a/src/KiBoards/Services/KiBoardsTestRunnerService.cs +++ b/src/KiBoards/Services/KiBoardsTestRunnerService.cs @@ -1,10 +1,5 @@ using KiBoards.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; -using System.Security.Cryptography; -using System.Threading.Tasks; using Xunit.Abstractions; using Xunit.Sdk; @@ -17,6 +12,8 @@ internal class KiBoardsTestRunnerService : IKiBoardsTestRunnerService, IDisposab public Guid RunId { get; private set; } = Guid.NewGuid(); + public object Context { get; private set; } + public KiBoardsTestRunnerService(IMessageSink messageSink, IKiBoardsElasticService elasticService) { _messageSink = messageSink; @@ -38,7 +35,7 @@ public async Task BeginTestCasesRunAsync(IEnumerable testCases) //foreach (var testCase in testCases) // _messageSink.OnMessage(new DiagnosticMessage($"Discovered: {testCase.UniqueID} {testCase.DisplayName}")); - await _elasticService.IndexTestCasesAsync(testCases.ToKiBoardsTestCases(KiBoardsTestCaseStatus.Discovered, KiBoardsTestCaseState.Active)); + await _elasticService.IndexTestCasesAsync(testCases.ToKiBoardsTestCases(KiBoardsTestCaseStatus.Discovered, KiBoardsTestCaseState.Active, Context)); } @@ -51,13 +48,13 @@ public async Task ErrorTestCaseAsync(IXunitTestCase testCase, ITestMethod testMe public async Task FinishTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod, ExceptionAggregator exceptionAggregator, RunSummary summary) { //_messageSink.OnMessage(new DiagnosticMessage($"{(summary.Failed > 0 ? "Failure" : summary.Skipped > 0 ? "Skipped" : "Success")}: {testCase.UniqueID} {testCase.DisplayName} ({summary.Time}s)")); - await _elasticService.IndexTestCaseAsync(testCase.ToKiBoardsTestCase(testMethod, summary.ToKiBoardsTestCaseStatus(), KiBoardsTestCaseState.Inactive)); + await _elasticService.IndexTestCaseAsync(testCase.ToKiBoardsTestCase(testMethod, summary.ToKiBoardsTestCaseStatus(), KiBoardsTestCaseState.Inactive, Context)); } public async Task StartTestCaseAsync(IXunitTestCase testCase, ITestMethod testMethod) { //_messageSink.OnMessage(new DiagnosticMessage($"Started: {testCase.UniqueID} {testCase.DisplayName}")); - await _elasticService.IndexTestCaseAsync(testCase.ToKiBoardsTestCase(testMethod, KiBoardsTestCaseStatus.Running, KiBoardsTestCaseState.Active)); + await _elasticService.IndexTestCaseAsync(testCase.ToKiBoardsTestCase(testMethod, KiBoardsTestCaseStatus.Running, KiBoardsTestCaseState.Active, Context)); } @@ -73,5 +70,10 @@ public async Task ErrorTestCasesRunAsync(IEnumerable testCases, //_messageSink.OnMessage(new DiagnosticMessage($"Fatal: Run {RunId} failed. ({ex.Message})")); await Task.CompletedTask; } + + public void SetContext(ITestContextMessage testContext) + { + Context = testContext.Context; + } } } diff --git a/src/KiBoards/TestFramework.cs b/src/KiBoards/TestFramework.cs index b48949b..b6b9dd3 100644 --- a/src/KiBoards/TestFramework.cs +++ b/src/KiBoards/TestFramework.cs @@ -17,7 +17,7 @@ public TestFramework(IMessageSink messageSink) serviceCollection .AddSingleton(messageSink) - .AddElasticServices() + .AddElasticServices() .AddSingleton(); _serviceProvider = serviceCollection.BuildServiceProvider(); @@ -27,6 +27,7 @@ protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyNa { return new TestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink, _serviceProvider.GetRequiredService()); } + public new async void Dispose() { await Task.Delay(1); @@ -51,6 +52,7 @@ protected override async void RunTestCases(IEnumerable testCases { await _testRunner.BeginTestCasesRunAsync(testCases); using var assemblyRunner = new TestAssemblyRunner(TestAssembly, testCases, new TestMessageSink(DiagnosticMessageSink, _testRunner), executionMessageSink, executionOptions, _testRunner); + var results = await assemblyRunner.RunAsync(); await _testRunner.EndTestCasesRunAsync(results); } @@ -75,6 +77,9 @@ public TestAssemblyRunner(ITestAssembly testAssembly, IEnumerable RunTestCollectionAsync(IMessageBus messageBus, ITestCollection testCollection, IEnumerable testCases, CancellationTokenSource cancellationTokenSource) { var collectionRunner = new TestCollectionRunner(testCollection, testCases, DiagnosticMessageSink, messageBus, TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource, _testRunner); diff --git a/src/KiBoards/TestMessageSink.cs b/src/KiBoards/TestMessageSink.cs index cfcbf74..42139c2 100644 --- a/src/KiBoards/TestMessageSink.cs +++ b/src/KiBoards/TestMessageSink.cs @@ -47,6 +47,8 @@ private void HandleMessageSinkMessage(IMessageSinkMessage message) case ITestContextMessage testContext: LogMessage($"TestContext: {testContext}"); + _testRunner.SetContext(testContext); + break; case ITestAssemblyStarting testAssemblyStarting: @@ -148,7 +150,7 @@ private void HandleMessageSinkMessage(IMessageSinkMessage message) break; default: - LogMessage($"UNKNOWN: {message.GetType().Name}"); + LogMessage($"UNKNOWN: {message.GetType().Name}: {message}"); break; } } diff --git a/src/KiBoards/TestResultBus.cs b/src/KiBoards/TestResultBus.cs index 87a3000..6aa1c6b 100644 --- a/src/KiBoards/TestResultBus.cs +++ b/src/KiBoards/TestResultBus.cs @@ -5,7 +5,7 @@ namespace KiBoards { internal class TestResultBus : IMessageBus { - private IMessageBus _messageBus; + private readonly IMessageBus _messageBus; public ITestResultMessage TestResult { get; private set; }