From b0f4bf39d697e97fed88660b149b93d039e76a6f Mon Sep 17 00:00:00 2001 From: Matt Janda Date: Fri, 22 Sep 2023 00:02:20 +0100 Subject: [PATCH] Add test framework ground work (#1) * Add base code * Add test context message * Remove message bus * Resolve conflicts * Add more diagnostic messages * Consolidate framework classes * Add test context message * Add test result bus and sink * Fix problem with error messages during bulk index to elastic serach * Add new visualization to test case status dashboard * Upgrade to the latest xunit * Add test case context indexing --- 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 | 52 +++++ src/KiBoards.Tests/UnitTest2.cs | 53 +++++ src/KiBoards.Tests/UnitTest3.cs | 49 +++++ src/KiBoards.Tests/Usings.cs | 1 + src/KiBoards.sln | 18 +- src/KiBoards/Class1.cs | 7 - src/KiBoards/ITestContextMessage.cs | 9 + src/KiBoards/KiBoards.csproj | 14 +- .../Models/KiBoardsModelsExtensions.cs | 39 ++++ src/KiBoards/Models/KiBoardsTestCaseState.cs | 8 + src/KiBoards/Models/KiBoardsTestCaseStatus.cs | 11 ++ .../Models/KiBoardsTestCaseStatusDto.cs | 14 ++ src/KiBoards/Models/KiBoardsTestClassDto.cs | 10 + src/KiBoards/Models/KiBoardsTestMethodDto.cs | 8 + .../Models/KiBoardsTestMethodInfoDto.cs | 8 + .../Services/IKiBoardsElasticService.cs | 11 ++ .../Services/IKiBoardsTestRunnerService.cs | 18 ++ .../Services/KiBoardsElasticService.cs | 54 +++++ .../KiBoardsElasticServiceExtensions.cs | 29 +++ .../Services/KiBoardsTestRunnerService.cs | 79 ++++++++ src/KiBoards/TestContextFixture.cs | 19 ++ src/KiBoards/TestContextMessage.cs | 12 ++ src/KiBoards/TestExtensions.cs | 11 ++ src/KiBoards/TestFramework.cs | 184 ++++++++++++++++++ src/KiBoards/TestMessageSink.cs | 158 +++++++++++++++ src/KiBoards/TestResultBus.cs | 28 +++ src/KiBoards/TestResultSink.cs | 24 +++ 32 files changed, 1091 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/UnitTest3.cs create mode 100644 src/KiBoards.Tests/Usings.cs delete mode 100644 src/KiBoards/Class1.cs create mode 100644 src/KiBoards/ITestContextMessage.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/TestContextMessage.cs create mode 100644 src/KiBoards/TestExtensions.cs create mode 100644 src/KiBoards/TestFramework.cs create mode 100644 src/KiBoards/TestMessageSink.cs create mode 100644 src/KiBoards/TestResultBus.cs create mode 100644 src/KiBoards/TestResultSink.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 zcmeIb2UJsCw>AnfDu^gWK|!U9(tGb6LXqAf^iG5%AfZM@Q2_;{H>HZSC?JBASU`{t zQlzSM5Kssu)Vrd--+jOD-gEvj?mgo_=lh4lq1o>2z4qF3t-aSXpZUz0J6H5IsgE%o zBO@cD*49!pA|oTmk&zurp*RBeR0Ts>Tze;p$tBqGW$ zB*iZzVIm^TC8`V#5mgo!7Z8yYvifzrgPV)*?*{b{7!Pl62QCo}aRDLF)FpEdUuQ%h z5^U<5fPaLAz;00$um!%55c{=xO+xH4*rR;)s<(@|izCbf^g}~jR8l}x0_?s7(=yT1 zyiF|oyHEX4*nj0Yl3u7E+_}LU-yGD zus1by2(Yqu5)-#j^KcXu5%KwT9|11@NDqYX@7op@kPraZC!LH6y6W<4ud_>lhZDFU zuz@-->2KSCLwp@TKYrTu3NQ!1@UIg+{<5K^NNU_kQ3*>gV|^iW z6O^N_fu)72sS`L**~GwEOw7%|-$2#GRl+DR$O!DTR8{xT6H!$Mn@&LzK7s1W7W!zD zD?w()X4;-tG1@{f4-+>74QESL7_e5L7R*rv?TuD9ylN$)>E@~K;iRvvAuM*y7^PzA ztfr-F;EWRXxpK|(s`OQVWz{R@%ECr|##aImX6`{Sw2-d1C+doubfC9}le9>ngP)J3 znuL@k%ve*;5{VL0u~HTGF+(a_sY{!KYnd2{xtaRwSV#%$YUrAR9j5wjS3Etm5!aMm zjl_N3EUu_%Ng8;gF`(q>djF2196?s=Di_8=7evIbHL( z=AmJwuj!$M@zizD_JldQU9)mPp`UJrWRHR9UYj8r6a<}&;JS% zZD4{F*Eclw1+z;<#n0KtOckZ>quA_*!rj?X~kD-c-ma?(gH3wHUw5Ju)LKpRXp|eG$hP(k2W-9VVLswYa%RNX{h*(p%pQdil< z!!c0VC;*Li#rR7rtBZIB21+9|oRNVpnp)C67V0{BIxc!@L7tvgY9gMZhT>O1GY(e_ zRIciYX<)RB9T8e0m;j6fc(hf-jE$|_l#xz)YF-wi`r?i-@Rm^VGWA1SIe6=XA=D7Q zCh01Pc9B3zIy*_41c+Wi`MR1pp@l6Fs=7ibGYKJm-z!c*D$>FZCf+UqPRfq{-Uj}G zre@&bQ1Q``LOWWBf-QX~LoF98T`g%Nn4W~VIjLc1U3GKUK=AHS1Fs*_|9`!`f4z>t z|9`*aMb$3{wug|Bv65-4DVtogTgotaV)iMqI{AU(rJ@f?sz1+KkJm*bkpjIdxaZ zFkZ2eWf8R`xpQG+bG%|acpSMQvsm*zu51z0Ww%3IdX@dEOM26qJw%=LyT}{PR1PSE zGQ5>tp-nTGUCCV@yK-$PSK;xG_B2cxlA;K z`tNS}Syp)_o|C$&v^-wVE9pD>pvr47whXy6EdJ@4(`}o2jOh!+gu;*Q$+BwXtiG|q z`n|=WYTvPV@8rd z3b}E9lXJ7ZL+gvSwWuOGc-VE=YR?Md({pt~UR4Nj)iVS2;p1Z6k7njo;%s(Xs;Jvk z_hZ%PL2EP8bb54y3CUS>>%1`u`msfU@|Fb&1$V6utWz)DC)D&8o11gv#Ku1)@@jG` zl)@VMrnnvU!UW9P9QjHau!%`pYhg4NNV6>7qrA9XwF2gE*>33%wlPrJ3#_200!>K=z?HmUb58cGZQl6{H25H;LYWZAP=X8WS;oE z1ZRKRegyL3Cob%?U~)Sc=sjx;VdKVid>z+DSJ;&VLw=~EpTg2Z1d6t$*6Jf)4$)gId?C#D<+{1ZRHL4M2>zJhzPHr0P3bKR znS{C${c>OMLMTdjd-q~RwXm0acR!iz-x^QgHh4PXR@+)weT-ZFP+yFEI2%VjMSQl= z#TZfTC=5)LaVVq<->|#d*2Di{dyOlU%CNDwq8KGB9G;Yvg`I}L20tncOJVc(gN_WW zoD|9J;)=jKmPEZiRuVSCH^yT#x3gVsKhOUTC1OZEhpgD;isHQOQI<@lYv8LluJUpE z3BqIsp+0bMf-k&6_#n87P@<1OFIdMS8uwo8?r%1-)Z3TxICxmQ zCCH%z5{6}r@njIHv$6@xsbr8vX|h`^N64WP(dSYl1tApe=5{FSOXN^9ccDsgcL;@d z_YaYpG745)nU?4Y=)N`?_8AjvHv}{UQ4=61=OBl=LN%nJ%>WRTP*I=^$gt?H4BDew zWLRn;lL8Yt&{Bw+*c_G&vi5*Z{zMEJgxM;my^s++jEvuoGi89DG?1l)$wFx?WY5(c zgYp5W5y?`KB_dhM;tgQWA@mz}`+L21q`LLmI08GfZHIvOE5CAbFs zp(^|wIkdSpLTM9pXtVvSUj&q9h)mT*r-@z(-lVB^;{pY%(8Nu$16RutShB(7>3e+dFb_p+mlf=8+m$?1{^vxEBJO<(E2 zVc8%=lc*`>_h~UCIYO9ckjGib>_W$PbGEw~1!n$geg6h~%>N5Ln&< zTrVgJYhkCA=QK*~HDk}E@?_WIs3!j90 zjDlwDzN&CzEai7L;P5#Aa(cc%H@-GeNniaOVbc&&^VLMLBQK$|HGzBj^XnVA!|RKK zZ86M}Qvec{xA52+=NA|iWs~)tS$|e;S1%I}-%my5^zBy;cBD&oNjq>|UTpOO@VQ^E zx5}hoKDcPswAjpakoc{l>#6kIIds@Ove>-5OdsynnGvUY`$X$sm~^!(_~Xi~V-=r_ zU=>9>%&2_h4u03wZC)+|ze=C#+XCQJsl>WlS5}N~?q$5w``Fep+gHv_cTeY9M`=UR zkEihKH!H&r!lc9ZL(px)ikYDRYp!nnnAD-b#LI?k;W89LYnfz2FUCBk>#60;v*BE) zcdd;8 zIoshRy9OpQ+w6GO&K(eKs?1wL1Z2e6l8L zq59G~l33bpQ@2LR*FTLcpO8_9`y5>Iua^L?7YUD~;L@v*;zmO$fwW!c7XT$oBiQsY z4yuvg_g2CiYi+`q5xpAr$*Q$gDVqrst{<(h&+}%M5I9rsJsG#&gT6R}^@H$k-cISX z`-%JRUV*^;dk*?L6vJ~@z;wx-HRi$jb>RuA19{an>l?YpCINiq!19A$c2?w6xOK(a z1!WVC>%MQ9ko(w`7q%Y0IB7sPlx!bnDPPfRoj=d;)e+h(iaW#n=8Eeb{H^$@-8Bks zoHha?K-hZ~xMC(4JVghqW?vf#C87!ZczSOA7BD-f0m3(>BTn3(Mkvi7w)zn)KM`iI z@L1T#6`!$MG%B>dc?8kO-*~XMqKROffwU=_hg12D@~dSAE*Q>Mfl0N%b>DJ-&w4`f zy4;~fS?v6KO?Y3$8lm+yRlD(-ER5~9iNT;0Ua+Y5Ze92XF;I%Hnh#jKar7k5v5NhJ z&^+izijteB3Kq$+dha_%3TaZR-_2Evf~8;dW9iA80H#MLmCf&JiKg?^B5&~pWoWX zW#|mQ@b*$PSe=if7Z0)F2I3fkl%ZzMd}5{mO_`}2>syb&7fjA98B?@dI}%3Df|c>? z!oX1#cqs?}>UD~e77O>MP++@%LxV2lSKpdvgq){`3w}FujrlFD74xZ@BT#QBf$><_ zhIjjuTX29{GrzmkDZ@>?Gs-Uayh z?)|7E@}PkWMmg^vg9)Judq^Yz7`A>rQ~3sfU#}U-`VhCtAYQjQ%&`%XWF%IM0aEww zHB*F=Fu0(wVRw`pBm*y3sJUWC$tqOd+7oC9_8a(T%Ks@1KFd;vP@P4q`oM1y%` z!ARo{=7SeGdvZiX92rCul6wv^2@vAIVQ4MrP_0{M)FA-ikDTE#=E(vRM}eJ*0H#`y z)}0Ht!R(^uH=OCC0yBat;0U!ofT;Flx{c?7sm{mR9ELCeEUa?Rib5AmV+$slIncmj zmNdtS2LNotpXe4{0|#zJxpyA|SeK0pbB+mM=}NU!13}Pb!J)HaQshvE5OSft0PqwA zNco?pumC*+EFT*lcCLh+;uJutr|A#JT)T*;Y)4`U%ZUKYr=1IB1jOO#(?>g?z~a}T z9b#@UGHgeZp!sdQ6fixS9LoUOV_@~Cq&Nd?#3A&7O(>QO;$*7?-++ekuydZ zx6j8u(SBvuRITCd{Jkb}>^$h+{L3GgDRfo;1;M7>;>^ZIM6n7bkwa@a9%R3f3Pr!q zj60$OMncS@z?2V5;EQ&%Z_-e60)B^(pmxvf6^gmb-vZfJow7oyxr}Cd7{OpM5`EwI zH_Cpcg3zSs0`Kk10_#thy4sd3=r?p~bW4luFP8Rg$sdmPe<0<|my7;Q(prR7BPNmn z?2~Za*(D-BRU@*`DTdh$l-XK`F8}6Qd&F1078*+}D>MK#JAN%1)j^P6IskaiAD~c6 zz+leHoN5Gfh-iEI7m-Ih1hwKhwI}006%{%A?s3@PG(Em>m^(adS>q`A*miKsF zP$wm?wvoXV*?@0P%7WJy`k&4WS9#^G%!~VuzGN#lD}7qF1NdIkgHor3YyS}*73nlc z+upM&Noo=$SOJ{u@H;?I@|c82kHJ^Q>l4+ocf8IrR3Q0N zNHvYA^L-Y@3zU3{tsUGrljO~KD)Y!DWJRl@6@|CiNawfmdwAEbmp5r?Qk3D^a`POM zzMJ_gG4vJ+Ch_oiU4fkKr4O91P!MCk0!Ez~5+n_-30%nc@jr>k zg^Bfd{mqooZlH|^B#JuUlpWVgm#U}uvme##y`^s=8^Sl2#}-^p?pfouC$RZm?o{(! zC-+EXFt5ive;dG`Eq{l9+_+ujdNs}aF_n)Bz1C6N0h3@DpC-#~jXX1Fgh0|e3i_H% zX)PEZ?ywxfu4gNkpXb|H8N>L5HQ(UCojsKGWtw*A_!kD02h{A!8QaQu-*AO%-ybpg zf=*;KT#V3!+m^I^ipJty-&R!?lY09&+Y!8b9dm>vujAWWY{JN}HPJBzufXzE`$#Tb z7%ZGGlLAbkW>)M37JU=ph-EK+IEsvDEV0riV-Yaj1S#Jk3iC?2Ybuz;&os* z!|sA*=hsBr1~3q68Ok%AFSg))2VV<$4?{!CaPadm02FDE59WyOA}tP*;ta)k75R zF5Y5ehrzOPc>3SWmz8gONNKA0hDusr*^+pwLL68%!xl~ zi0@AIUjZY#Lfeg}0TyA)YdKd3&>0Efvjg--LjPER&JLYSnMVUmf_|H7$oc^6C^$ITcv$wv5rD?73z8K~oB)iXX?tBmj{Y-rMp_=T2^NSTz1W6(>|i?Iz2SNt zTvqwIYgz?xFAd=HCB8ij&;# zE1X*C(XU6q{hcVeK0K>0H?SPsz~I!}t4rX~cp~L~kpkdRPWJ+7Yv2RC2&s|zi(UTT zH^}W-cmwsRyr^?@aT9m7=!Oi`rjptH0n;kKBXNct@)nHEt;bQJPyW&ZByv|=PQZJy zuiB_J(8M*~X$e%HGGJe&rX?mt@iE3VKKvwOtNh3Y+~278oVUgQ3*YLXm-tEP5i>Y~ zxicC}CdZ`x>+4&&U;$^mzGzv2RC={%Pd@yG`oE{|*VmTz1D^1-8{7XPxJJ^J9W# z(F+etej!tZ?RG$jIs;BJ_n;wk=Y{v^OT*qF*}&zJ{Z~un+LJHjI|1oB1(-trFK-T8 zHiQs!1hef|Kk9;o|)f(8yC^fP_b0ZtfyUXmX&t#NT`L zqd8C*=#*q&pl13E72op2vD11B%{9L$$vO|wwsJ$p6yJyDWj3i54hyarpgs76b9mb> z(LikWu}-QuHRKqXGL`SI-Doo9E%vJESUY=z<^GjCFOI)2mQ|wIu^ObNgwL=^hoWNK z^n^iUPx$VS_qhoJAjJqehUn7!E0uC(UyV^<)I4Fl1B0|R+AB`Cb9e4qX84Zs+_%Zo+kT>0@j+2B8*h>^xuuIa zQsCIR*e6J_(s&TYHN~0b*Hv{f(|0!bNYX*NNc*gKHa=}N{o#aTI9v+Lp9Bxj)`agp zTk)UjgeEnHJf_#Jrs~t?7~9r~PuqYNu=jKoj38vp!rDX*s&_esmv^W#cbmr?&joJx z%o?E2#xf%sk_BeyQ|?MfeKL+S3B2R zs@}m7Zs?+bokmM5E*UrW-l4*xYh1R@P+^HJ9?xt8F5>*SGcapJjfYg;y%m?nl-56f zU&}rSAspu$8-P_ab7$sU^ywsS_AM1{ivrC>tSnYBG7PD`DEjp zDRp;(Po~usGak0%L+mdP6UPWU^ok1kg!GO?)P8Cp&ZOs7(;$D**`nw7I^^rqvK0@# zLe2LMtt=jqop?EKIhN-JU&~}|UN;QaPYhS6&wJbz+l%DQEY7l6b5q&An7!IxUOkTS zdg=zBgi7eo@FWu21r@RVUWs31SL#GD50WW28cZSHL5d$hppYAX|Wz75&O$m-ii^dy+qPRlIwcZqerT#P9mtleF~Efju~ zDMVRc$xoFUtq-oI>jyz94Me;r!?4$WfWz1LaNkkusL8E)N(q;o>YVk1&>u~Vb??5o zO{4}DQh3iq-8%!n2;p^f6{EebLSxgGF&t=0kw1_T$gf0k1 z25h{EeiETH0wDc}T8*6+;EDIadI5wRqt28#$~-p*xt+Up$5MiM z!A#>lQ$qn|qVF~yT2Y&NFSp~_9<4$VO^SH(9p8J!(ZEWEZG{d|oi96~f;=;PioY?0 zNOxQBb~=OG4~KoAUB$kbo)&o{?QlzcWJI0-2d5O82u-Q zLFT{2VW|D-Fz^9~LAp?|W1~G))PJs<%`)mBQ#No4;A8qh6>DivI{-*T%4@Xov_m<` zjtE8&+Izf$`m9dHw_+yQ2~cPoac!2Q7BSY#6A&7Eh+69dQFeKsCqU>CN6jo@vTEag zD6=5$Z+^p?Z}9kKMyN!`v1!pY@RSG-yl+2T&=`sst}Mz)&2CvG$%ymmKE7uOmy_|Z zCCRCM$E@}?%AbFb>>@CS?m-{e8^15k{@8oju)K7zH2Xr|Cb!QpQCp=vJ6o>LLR({E zf1_Hnu$Q>4h5Se#>o4W^_2xNwOy$>nZnC|ViQO5=+&;@avD`@@kJh^&ckRj#Q?pkA zOHcK6=P~PDgKJty%NqY__isRhYBrc=0JIN)D>uv}GF2XN#arVww zPqeJwT7;x;e9~^{nf==GzIQ(!zq(?b{V6Xd1n8G@R$J7E^X_kp7VoYB$;X|?`x$-! zv7SbDitb(izQ40#t}?K1YKB?RX@qlPr@QbA+}!n%#pr|?d2RTepw4oIhGS9(To(;x;C_{{SRVuMe$gQqf5IHyaK19&Aom=Si+RJ2ye|8PzVduDU+diXyfQwgu zxb5?nGYRGS0XgV3-6gX21D%;?oi%?{1;M!Bu?b{H$eD_6!3zT{m-OLgj?*7GaQ@Fz zT)2T+`6a!6s0va065~+btYGbrg`zLBiU-6w{+FD&s8@cyu1Sbk;=PM{5=(xQGYHiJ z`k}lSxyI7O`-Sy|T^}cyN~ri0`(K1Y7FFQVHy#GpMoRmJObgGOn0B4PcK8>6NBcl$ zc*{LrWrE>Aa23ol{?sWim^U)jrwGlTP0{!K=^5m^ac_suLSTZ2=Qat>h1}5u&xX4k zKw!;yq&d{yKz}VJJ*!_2b3{TLo&dbH!VikscJOXD$Msn`Oj;{qC1BXHbKFWZJO5+_Xh zce;fa5$9(@=jsTD&&UVmTbE6auYOFH?Vad}3BKnCVk8v|DH|o#@{2WHK$dOLO0pg8Uz>VE%-IZq}TbGRiXHP`*;PkQy7 z0K^jJIYz}Q^pH9s=oBu+{k0-MK8kO(MB$Tyyi1R#3>i#oJ#@*i;u`7>xf#t`qAbNB$z<_E_)IwE2k zODb>2Yg(Gj7YKu>#hKHQhiT4yxYa6m%tE*Fb2gw_vmNrz;(jD2Zd_TtbdP6D3^5?r|F zdN`nI!*9j8;+yTwhE-d0`JSTsQh-AfefJH7;<(FO=L?7VE?RvDl4W9-Q19`ftu~$D zOF<9S6MdP$1!4>hEy%Esy;ItABbwBx_JJ(q;H*X(IWU^X$^Vm$MtgWela?61pGzfu zHoH(*(g&+(RU*+{S3C!Q>v@paiPSe=DR4*b-E*d)jGQz z>%4CY^o@_$+vsO6ElF*aycE|`C8xMK;tp}PdUJ}@mf4%;6#+M*oAB`9~TN;w|whhp|@|@6r$PCD9Jv#P5`q;spB22TC_lB+W4!&j)pJ(qXlKSfKwRbPP$jxQg`a<@lN(ZZ<()S|+(ftk=v zl-_ABZ`@dMQl$HA`tr4pn(}8)zI=Fe9KugWQQcG75)0G22<}y#X6SE$pkqXC_Ei|I zG|(%}6ha`PoOq@Two!cYiN-Q^if`hyK?3adQ7sc{Q?J-pxoL^FqC#M5N%vapAqO-< z>!0Z1)SX#=?`YqY7gIp`B1`|FSbBZ%%co;63z->}CLe&$wx}LIgRxboO*yvM#lG6% zt$pxQwZ!}GWDsS7Gj-B~H{UT7^<_B}e3@?uSw9BVr&jFcH@_0Z>saRE-SQgwD~`bQ zTig&1gQfuHG!|XmUM1dGsP`Ipv5?VCHC(r2 z?z3)xvyn+AXIp7&-lPE9l*pvM;R}){se~n%sQBHgw=J- zvp{Qe8TgPMAsrG_*^1$I>v@xi(U;FUV3M_F_tQ0V_ZxT?(78cBzDANVaX}jEu1*)w zT_^ocvSsel9NbJ3_j)>t4)y)z=E1EJNJ$SM$+qRMbX1U@+qd15oeRW4slf<2ZB>W+ zUbqT$evr>_r3YUk$bLwF-Y4$_(ti6JUVyyPg|u~fQCrc{vF+^?La3^D3=F+IoQ+=b zmBZhBGY(DK_HaV7aN}$kY>!CCBAJmky4~`=7m{Acj<_>;>J0V)=W%+MxR%@D^tkKe zLA?O3$p$gJeh>fD1Y>EQ))=O@14G)vG4;ULiw!%g-FV8j?wTP;!M(D#>autEeQm*P zu_pY}Jm*1-xMEy?IIID){?wbK8voime6YWAkaVzh|KQqmWdh>T`ozP9#@4)vH|yKm z%!HSI>pR%F0f=@I7?UY-XTygS_O5to`lbYCG;-%91dv*6_8h-=VQYipu5hU*7ry z_cv(c+b7;?nl*ZhFgWM;%@u|E;i8NBf=6`8I%7#}u&v5x>XW8t;GU+cS2O*2?( zEjb&2YUoq|uJD4H%f5BZhEx5XM{a*f?R)W|HbD(EcKRR_nhWWvhlvhE6BdV_IX(9p zEYp!9@~hc0Zo_(BYO)b2ZOh~A1vA?Tm|BT_5LT=o&R$s5-7F+f1&=T0HLPQ5J56If z>N#*R%)IwzH;vXtZq#V4vZP<^!W&7gvs4pCZVNoJfd^&Y%7mI7gzZN=^dj2(#vz_B z#QALcCug2rMIMyQx#W8ILy9Nv!lV~99yRXGbX{JZhy`&qiTN6qcbi&O9H?ifj7Pb1AhHU4gvchV*gRS?9W-E|6 zStwCz-F|d!u~_YW>E-&cFv;Sudcrt1HgV;3(k5eCS++L1N&XP?Caaj@^33}sRF37` zS&Pus_1lk$t|H6Z9(`KC3HR$ms1w)Uk2R~oW0E`sne~jZ`PSEq6vkY8SoR6mHA2r% zL(*5y4&|*&X~WkU5BGMx2jQKWx=JkmX(f1CCZT5G&-nI?GFLd}gD0U$<^7d~b3RQV z!@8n&C)Xas{C#47Y2qoP#tgl_EqwlC0iE8C2i?%i2J><|`5%l$-yv-d`or6+WR(RV z#cSB?Xv;JjsW)|(`LYY9wEZWyEuVLNC5_t0C|fo{Wg zUdkR{r)T8GmD_!N!cr~HxrgmPs0U%Wxqjz1QC!HgDQ1mh79gL84e0y=zOBzPOCEI8 z?$-&7*-f2IL16o{jq@`m{tEilx`=j&;)nxI2|%9Mb=yckyew{97v`029ThVG_flVz zKh!qC`Z4)cub?ImP8)D4gRq@Eg&R8DI0BvK_Vne0FwBvSitN1-D~`!5Y`!cE=o({! z*M#dWao-VYcM!;PI=EF5wugGy zY2SQilff$Nz;eRQie~WS92T}FyiJcw2npS?b($t5@upREk$drc0?w!V|(27D5+>ccu~yo{EFY7cjpcRa78#yqmex!xn`00tqkRduGTzCT;k0_tRmC9n{+wwx|Id5}Qn^`Kvf3i4&Z^j(acO-sd=_LsDK?06=dQwj=lSm0wt z;N1*?_bxhJ zQ_eSEc78*0d6ymYD!!0hyyKD|a$FfmSIik;0XZzd z$)=3=n&>+Y+On8{#s1(R9i?`>=C<^0lAC(lwE4joQuA-P$EhQJI>r^aGlwD4Bro{K z-@Rb`Ig)$6x^nZU9b_!ckCSwiOexYp!H0aecalb6YCo<|IR+S!OPFND)7&^qK8`X< zERoc{1x+Rm1*sFG}T!hlgdZ1W8T6~v{ zl=gGzJaCWCD=h~{fn%sMe%Q0&nVb#VumAFQ8QP+}er3S_(!;KVyt~R4sGma4NE$TK z`-=LPgD%!~vr7r?N3!+3w@ro2zy_cvZxfZzLajJ~i9F)YC#UKD^!RtBNZDGzxXZM+ z&k2(_0JcGCP*VU5N`c$B;jNRTGau%6$idjbiI*w&BZ4WxuAvBXQDfdD(osX4xB4we zqj{?;A~ohD$!aXmUap9c+FBmuqra*JX2zrt$9;a%2((X%*lC#s+f0!G0h^c1iV<`<5k-m+*<{*<9iND2Uhb+kjI!?lS3ip^2ZLX%)zW zgLL_Qy8yN3qWFhe`#+eEyg>1{Ith8yYyY5bmLCf)K4^cd6OEw|1CI`qQcj*Er2I|` zl9s5Vwtta*;&hziofb*8DQouUHfsC5)`1;IT`zQ48d8EP1wR?l4K*bLtE1{uUiPgz zF5gemO7pTe&J`7U+;X|lcV$u(WGVtCEa;*B@2LF194RWVuWw)EGh?`|ldBjAnA=w^ zDiS4yjG?gvG%az*ysKU=v%$!{onva%rMCj;Ib79~7GG$yD%M|<3yqPD6uvKEPBC~4 z)Zd7V9-GeV6Xis7H7wv#Z?{cr_HltUIIaQ}gUP>=(A>axNQVn02#QKIAdH7T|K2t? zVesQHIfd>;yxrVYG!2lc6u1+o+mfZckNJjhl3}@EPkkPM3L^u*RKFT z!ki(x6p$b-tJ7`o2iy;+Y~3DH&WTqJ0w+@MoZDls<4Y4DLZ$XQN`+(MAA7gH*b>LV z5Su&f2eEEnPZPu9)2=)pWEGOFFjBzcb+jE{gtFoe|5M3?r|kyL#QBB4ihcRWxP)$f zxlJFL@(wxEepVVa_n^e4#vf(Xw^*dMMnCl2rEP}bzrJ7!n3-Vo^^f#Ji{*_1D|KtJ z-k+YkpyJcY!|OL*_>4@wzHu~Xavm*(-9svatQud1iaHrcI@g$gSqz?m#v+Wpk2(wp zR?A2C`(Wo}19bmZr7Mr#!WM2-SWUk&(WuCz*_iCh76xR(KMNvwV|srlY*}4U2(cK0 znAZ3X;U33le7LfBalJhB=`JbLY_EKP4M$2yORO-olvM_ySA|8|AvuV#_S{Svd-p7S zUMx4gAuJ|%`Qy}C3z??=!!Jl`*ScM%1ZYyVZFpFI;ic1Kz~#EQQ4VR#E)@?Nm_gn# zm=K4gXW33JFht1^`IAa5(M=havNktXK5DU zhp!!Z@c=JiTg&M+P;z$6wLKd94@H9?CR9Q;#{!EF29i}S z?$v)1N(x!Cyh`;JsFliDhj9}L6DTcJ?a=mr5;$$^d2ro zf@FD>=FYre5Xr=xi1>0F4v866r(4Dgg0Z~4 z(TA|%V67}U@+V>Je^kQQ-=W&yOIp275wfM=17m0{rXoP9%vE=hy-R(Hik6rj6=JTo z&&fVP6Nk9d;!jI#yKerN3?$lv#K32)tliY)@*d|;#g&J0@g@!{s!f$d?dGI20DtXg z?iMLuD>>pR24bKrSoE*)V$xn!8JZ-{g5kJ_ODa(6jKG}B|h$_?Wyki&%PtfMT z5ihghE*3v&XM&o!3it$`)_@Dz)jc?L^h67|6z?tK9X`dS47nhq6Bp#9p6V55f$CEA z?8PX(#I&sC1#Y~UM(8(CrYe>*CH$gd4@j!#%o26$YKcaBKDR>q9+12r?P?;r*T|%sud+FsOEQxxJ;}W4!MB5?nNN zIv}Gt;M2Qy5{Pj*Is3V z)D8SW_EHk4pI}}M>2vEn!^2TpL7^MmW1R|4VCjJUh4`G_hi`p%K)0EyzjAnc%QJSe zxhv>0qdc}C;R&h2)-GOi{uH)JOXeoNcS-T|jjV^O2?@<|%hFfEsDxX&GAq;gVs(&p5Zk<{3J0C=GsGQ<#e7wb47B?jyOXL2o&W>Tv@~4Wz_>WR{JhUJf-xgEx-9g9W30$#t)wL9T_b#EaF_Tr8^#y4`A6B6iYrN2o zCj4!Cl|r%5ui{qY|5V(n>34CfeTnfrMo$0MIb;>e>)H7IX$D7nZ2scx2+8Z5Ci9!p9m6}al|QViWj5mI01!!c>hk_{Uf6AF5eV#OP6LHTYj z^J2h)^I_k&K6-=q>8Dlx=>-R<#JnEK1MV2vPeoBH_Xnpx4K&tsiXt}1t3+qL1mqu=fRL|s>6!G%TCUaQ2NiepR7R7D6)fW za$)q$s0@(C$ruSx02Be-Ra!&9q=1dcvxel@7hvPX9sl|VV1aKLN=0>n&n|MIT_GSg za+qr23jqT1hSi)A6>yx&jmM?R^h)p>vB|AyPyq?8p618;-2hZP>L>dTD<1tjl(pKw z#C~9Nw4VyRm{@QS_vG--U0PN z?;ZNzSRA$DKT59YYM|DLz~e{*Hr?v|;XkW>>heP0oaRz8xF<Fm{ok znFGZ?7H^5>D*a~hZhb9hUp=pH&v$}C7o^tcy^k?ahBHAh$NFX+>_Luy`1BMJ`$UdDms`j!H{^ybdBjir(2ev{43 z$Fmf}1$H);5+>i@Zv!HdDLnR&|K_qS$g#LpV*4rpl?fQR*4Xp1Q-I%j4hp8;8Dt5p z2U#;|n5XtO?;FsINg1+%`T%|KYTmz)Y5Y8FZ~N)QZzTD&HXoK8yYvIV$$lF_o0qJh z;24W_ZU|#-r%J>+6DX@nw-nkdMP-}260QkoC!xJ93U5q6mcqOdTpB*c`3p|^v2bT} zDeUNmZM|iQRa+-jLW8kja%Z=I5dYJJ=q#)Mxafc1 zA`n-VZtnxN!%T)*?`7liwPt2S%WQVIf(%xV&VsJ%FR2yK-bk;Rw$5_nT-uU491=0G z!JxhM!RgGv@zlPNkdQUvCHwjl+_)Fv&NX)QfD)kOIuO4Bggt;bMExWV?fQlYYM?xV zfaNpCCZPHW|9*poR8zCq+6TjIDCw|=+1+{u3MmxO4dwYY+ZreqSFbMvMsY!NksyN! z7PeiP?<+JN0~P+Q?ks(6x|gVHdUu`)L-ni(-yBms0js7_+~1n?)aQ|qzeD00^|KZD zL9$JWZ_m@+zAYZr(sac5IuYoinQsoBB~=#uw0+?r9z{Q(XCi48dLl`miidKKY1787 zSF~7h_shw|l5vne6ZcJF_xsz0U?4Hel3 z=ie5O8^I+J;~A>*V@xnX$2rA<6+OC?fhRx9{`WMORFfmIG0d9NX5p7P>)*xQ&lj|r z5|o}g2mprdfiYvKDg}u;qx_;iL5KCDr{O8lWuE!*WTWYi0`j zZQuzrwt&*S_YC_`1_m|r6j|C3zl6P2v5B@Zwwp^m%WR0`y(9ODDU{xfw6 z!$6ZVJ*i8VGv3?IB|IUD6Kve|M-}@Dci|aiu=(^Zwe_irhd{wukYFD&UetveF|zz| zykv~UtZV>CoxM6gAg4bAnGj6iZ}t8we=N4DO0E(v+6v%))%y=1)%$PCN0<~;v-1o3 z@o@^(zxcpAMrQ-cg&p(mty{MuhK!TcB#rC&H2Wvo*BHK31VU#-CA|ih54&axt<$*c zL?lb4#q*S(_*Ec51zz#!gZNQWvFjMxKgF*9n~PoluYVTjpUU_ju)LMTxz}cyc7WfP 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..87d6a87 --- /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-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 diff --git a/src/KiBoards.Tests/KiBoards.Tests.csproj b/src/KiBoards.Tests/KiBoards.Tests.csproj new file mode 100644 index 0000000..ae75601 --- /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..8ffea7b --- /dev/null +++ b/src/KiBoards.Tests/UnitTest1.cs @@ -0,0 +1,52 @@ +using Xunit.Abstractions; +using Xunit.Sdk; + +[assembly: TestFramework("KiBoards.TestFramework", "KiBoards")] + +namespace KiBoards.Tests +{ + + public class UnitTest1 : IClassFixture + { + readonly TestContextFixture _testContextFixture; + readonly ITestOutputHelper _testOutputHelper; + + public UnitTest1(TestContextFixture testContextFixture, ITestOutputHelper testOutputHelper) + { + _testContextFixture = testContextFixture; + _testOutputHelper = testOutputHelper; + + _testContextFixture.SetContext(new { Version = "Context via Fixture", Hello = "World", Input = 1 }); + } + + [Fact] + public void Test1() + { + + var testCase = _testOutputHelper.GetTestCase(); + + _testContextFixture.SetContext(new { Version = "12345", TestCase = testCase }) ; + 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..19ea6ec --- /dev/null +++ b/src/KiBoards.Tests/UnitTest2.cs @@ -0,0 +1,53 @@ + +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 + + 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.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.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/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/KiBoards.csproj b/src/KiBoards/KiBoards.csproj index c8246b3..6260214 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..5734afa --- /dev/null +++ b/src/KiBoards/Models/KiBoardsModelsExtensions.cs @@ -0,0 +1,39 @@ +using Nest; +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, object context = null) => 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 + } + }, + Context = context + }; + + + 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/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..11043de --- /dev/null +++ b/src/KiBoards/Models/KiBoardsTestCaseStatusDto.cs @@ -0,0 +1,14 @@ +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; } + public object Context { 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..4713b0b --- /dev/null +++ b/src/KiBoards/Services/IKiBoardsTestRunnerService.cs @@ -0,0 +1,18 @@ +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); + void SetContext(ITestContextMessage testContext); + } +} \ 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..25bb63d --- /dev/null +++ b/src/KiBoards/Services/KiBoardsElasticServiceExtensions.cs @@ -0,0 +1,29 @@ +using KiBoards.Models; +using Microsoft.Extensions.DependencyInjection; +using Nest; + +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)) + // 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(); + } + + 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..cb767ac --- /dev/null +++ b/src/KiBoards/Services/KiBoardsTestRunnerService.cs @@ -0,0 +1,79 @@ +using KiBoards.Models; +using System.Reflection; +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 object Context { get; private set; } + + 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, Context)); + } + + + 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, 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, Context)); + } + + + 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; + } + + public void SetContext(ITestContextMessage testContext) + { + Context = testContext.Context; + } + } +} diff --git a/src/KiBoards/TestContextFixture.cs b/src/KiBoards/TestContextFixture.cs new file mode 100644 index 0000000..8da59cf --- /dev/null +++ b/src/KiBoards/TestContextFixture.cs @@ -0,0 +1,19 @@ +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/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; + } + } +} diff --git a/src/KiBoards/TestExtensions.cs b/src/KiBoards/TestExtensions.cs new file mode 100644 index 0000000..454fe79 --- /dev/null +++ b/src/KiBoards/TestExtensions.cs @@ -0,0 +1,11 @@ +using System.Reflection; +using Xunit.Abstractions; + +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; + } +} diff --git a/src/KiBoards/TestFramework.cs b/src/KiBoards/TestFramework.cs new file mode 100644 index 0000000..b6b9dd3 --- /dev/null +++ b/src/KiBoards/TestFramework.cs @@ -0,0 +1,184 @@ +using System.Reflection; +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(); + } + + + 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; + } + } + } + } +} + diff --git a/src/KiBoards/TestMessageSink.cs b/src/KiBoards/TestMessageSink.cs new file mode 100644 index 0000000..42139c2 --- /dev/null +++ b/src/KiBoards/TestMessageSink.cs @@ -0,0 +1,158 @@ +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}"); + _testRunner.SetContext(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}: {message}"); + break; + } + } + } +} diff --git a/src/KiBoards/TestResultBus.cs b/src/KiBoards/TestResultBus.cs new file mode 100644 index 0000000..6aa1c6b --- /dev/null +++ b/src/KiBoards/TestResultBus.cs @@ -0,0 +1,28 @@ +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace KiBoards +{ + internal class TestResultBus : IMessageBus + { + private readonly 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); + } + } +}