From 33d7bcb665746e4bf3472a43869fada6fd79f2ae Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 00:50:52 +0900 Subject: [PATCH 01/30] =?UTF-8?q?test:=20=E6=98=94=E3=81=AEMastodon?= =?UTF-8?q?=E4=BA=92=E6=8F=9BAPI=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=82=92=E5=BE=A9=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../src/test/resources/media/400x400.png | Bin 0 -> 7227 bytes hideout-mastodon/build.gradle.kts | 5 + .../StatusQueryServiceImplTest.kt | 11 + .../account/AccountApiPaginationTest.kt | 160 ++++ .../kotlin/mastodon/account/AccountApiTest.kt | 471 ++++++++++++ .../src/test/kotlin/mastodon/apps/AppTest.kt | 135 ++++ .../test/kotlin/mastodon/filter/FilterTest.kt | 710 ++++++++++++++++++ .../test/kotlin/mastodon/media/MediaTest.kt | 129 ++++ .../ExposedNotificationsApiPaginationTest.kt | 179 +++++ .../MongodbNotificationsApiPaginationTest.kt | 179 +++++ .../test/kotlin/mastodon/status/StatusTest.kt | 232 ++++++ .../mastodon/timelines/TimelineApiTest.kt | 131 ++++ hideout-mastodon/src/test/kotlin/util/Json.kt | 8 + .../kotlin/util/SpringApplicationTestBase.kt | 22 + .../src/test/kotlin/util/TestTransaction.kt | 26 + .../src/test/kotlin/util/WithHttpSignature.kt | 31 + ...WithHttpSignatureSecurityContextFactory.kt | 52 ++ .../test/kotlin/util/WithMockHttpSignature.kt | 35 + ...MockHttpSignatureSecurityContextFactory.kt | 55 ++ .../src/test/resources/application.yml | 4 +- ...iV1AccountsIdFollowPost フォローできる.sql | 17 + .../sql/accounts/test-accounts-statuses.sql | 201 +++++ .../test/resources/sql/filter/test-filter.sql | 4 + ...でフォロワーがfollowers投稿を取得できる.sql | 28 + ...証でフォロワーがpublic投稿を取得できる.sql | 29 + ...でフォロワーがunlisted投稿を取得できる.sql | 29 + ...稿はattachmentにDocumentとして画像が存在する.sql | 25 + ...イになっている投稿はinReplyToが存在する.sql | 20 + ...でfollowers投稿を取得しようとすると404.sql | 17 + .../sql/note/匿名でpublic投稿を取得できる.sql | 17 + .../note/匿名でunlisted投稿を取得できる.sql | 17 + .../test-mastodon_notifications.sql | 66 ++ .../sql/notification/test-notifications.sql | 66 ++ .../src/test/resources/sql/posts.sql | 10 +- .../test/resources/sql/test-custom-emoji.sql | 3 + .../src/test/resources/sql/test-post.sql | 4 + .../src/test/resources/sql/test-user.sql | 11 + .../src/test/resources/sql/test-user2.sql | 10 + .../src/test/resources/sql/userdetail.sql | 2 + 40 files changed, 3146 insertions(+), 6 deletions(-) create mode 100644 hideout-core/src/test/resources/media/400x400.png create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiPaginationTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/apps/AppTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/notifications/ExposedNotificationsApiPaginationTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/notifications/MongodbNotificationsApiPaginationTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt create mode 100644 hideout-mastodon/src/test/kotlin/util/Json.kt create mode 100644 hideout-mastodon/src/test/kotlin/util/SpringApplicationTestBase.kt create mode 100644 hideout-mastodon/src/test/kotlin/util/TestTransaction.kt create mode 100644 hideout-mastodon/src/test/kotlin/util/WithHttpSignature.kt create mode 100644 hideout-mastodon/src/test/kotlin/util/WithHttpSignatureSecurityContextFactory.kt create mode 100644 hideout-mastodon/src/test/kotlin/util/WithMockHttpSignature.kt create mode 100644 hideout-mastodon/src/test/kotlin/util/WithMockHttpSignatureSecurityContextFactory.kt create mode 100644 hideout-mastodon/src/test/resources/sql/accounts/apiV1AccountsIdFollowPost フォローできる.sql create mode 100644 hideout-mastodon/src/test/resources/sql/accounts/test-accounts-statuses.sql create mode 100644 hideout-mastodon/src/test/resources/sql/filter/test-filter.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがfollowers投稿を取得できる.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがpublic投稿を取得できる.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがunlisted投稿を取得できる.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/匿名でfollowers投稿を取得しようとすると404.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/匿名でpublic投稿を取得できる.sql create mode 100644 hideout-mastodon/src/test/resources/sql/note/匿名でunlisted投稿を取得できる.sql create mode 100644 hideout-mastodon/src/test/resources/sql/notification/test-mastodon_notifications.sql create mode 100644 hideout-mastodon/src/test/resources/sql/notification/test-notifications.sql create mode 100644 hideout-mastodon/src/test/resources/sql/test-custom-emoji.sql create mode 100644 hideout-mastodon/src/test/resources/sql/test-post.sql create mode 100644 hideout-mastodon/src/test/resources/sql/test-user.sql create mode 100644 hideout-mastodon/src/test/resources/sql/test-user2.sql create mode 100644 hideout-mastodon/src/test/resources/sql/userdetail.sql diff --git a/.gitignore b/.gitignore index e3b32bdc..ecde199b 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ out/ /hideout-mastodon/.kotlin/sessions/ /http-client.private.env.json /logs/ +/hideout-mastodon/logs/ diff --git a/hideout-core/src/test/resources/media/400x400.png b/hideout-core/src/test/resources/media/400x400.png new file mode 100644 index 0000000000000000000000000000000000000000..0d2e71bee323fed58e3aab0a839c0c2044bba54f GIT binary patch literal 7227 zcmeHM`8$+d+~?`hLQ0!tt0W>JyTKrmEh5>MWFK3ykFD}ZVo;XSFp@3%mLX$I@z|4P zVvLDVV~H`Q84U)*d%E7=-+$nJez>o>uDQ>B&i8!JclmriC*_vK4Srr>UM?;!eiLIu zYc4MC%sme`qUtG7& z>v3_({(X>3FX_KQ|GD7*Uld5h^6XkzSd`dSai~6Lp|P3va%v630cuF=3Y(H~m`MvM zC#dD}_xtv5N8kN>@2ZL9@y7Oc?NJZKr3lQQA)~&=V2DNe1=J!(yEaN&KF{1}Y)K_) z4Y|dfPgM~{Byd)A_t+U4>Bf#=*wKX#ga;2)OsKgxjhbJhXpL3e?oqEgbL}r-p0l z=rr$79sb1BC^r&9gF!i~+%7ZqIF-@I9H zZX#w64h~kt+BQ4pG&Ly$e;e$nqZUoDt}o$OdGPAb*iqjwiNN@;0)Z_g>q{p~Y-Ib_ z*U@tF@=#=3QH-z5M4cPX6h|)H^f|@Lqp7Ves;RwOVO!PjmcY5lg6q^%U@F2)f?EPY zRDAF2QrO()W)w{SuoxkHo{rl?_2sbYzI^%e=iicFn|DgBpIa6}O`3>@S6YLDgXi(( zmL4vTn!#4JwX=b@eQs<0{q)oP{Cr}_tVwHI8*lX_a43aB(M!h=0|rJ%t?qI=$_bWF zV7h;TX?vDG9;N~hbR_JF_r(BfG$D{JLVc|**dT@C5#pkr>2diaFOx=U@v+i6?0)8% zpK!ts5-B2clD7kwWiEB`xv{af_-R6T>2#18_{g=+XNMDyQ@C;C29rU#!Mbl-j*nK+ z-mk7kVYL3!<-QaKd61AmCtVQzCgR}YQrfp*TxxxFW|41-#cDp8+FeA&lIeTZkxp0E zfiYlD8E17XgX>!yYi@L15KQG%Z```{dkt0S7UkmXY^)+&u*vCnxS$s=(+9k4F(0}E zpG!?mZER?8&mWp=tIZzt0+#l;KLjQ%E-p4=FjWxr;Gmhm-gSv%(X8bh&n5@TP^VGx z`Ij$WP87Wduc8@0uFrZ9M*dg|heL9P8B{qhr8E7DYcEVo(^&B!%Rh@jztp69cwCAlU0QIK`{0ZelS|w6ZTvm ze8>+kGm*`C!QsU9dpGqEwmG}Sb}p|_e$$JX*4FwNHwP!DEG$;XBkJ&STwvhM^^J`h zu?%olA8@#{?AFTh%5ZOYiRYOcbh49{nS_LynOP$arvQSuhk%)`b#`;pT@sei+a-em zYWVVbkNw3CyQ0oD?%3+$%8|79f&i$eK`@jNvu2A^Y!YO}k( z*SE)QPe9g|K^3|E0jF~L@25K&6_);GnKd_lXr#BtbKoT#&%pTQ@yitdA#eN?M(G0< z+wA%b2WP?N+{-~SizrMV7{=UHwJN?C*);O3R%9wp0 zoWH=?x&tSjNpz_!lW_#ySn^)r$~a85{)~dqO&nQ$W)b;s<$g{)8IrvPj2y>4VzI)h zIrjxv9j&dtSor#hj9#z6z@aS%{3{6^zG0}Iyu5rGr5r8ZtpTza;qj&DRv(;vR|u@M zxdv;7gnhTI8h<_$BSZ|C*c5B4)oPYTF@np>%X_48|GbTl#Q?drz1 z0l&xe%#3jGa`LsJhO+ZU633{wf1*F~zNWT~!J5-Qb|0pfuH1kW<)a z1%_DCa=1PE_0Hl8NIb0hH6xgASJ(Bl`(ESw_bPaJA=*a^K~PJ&`rJ58TTM&O>6l-P z$G&t*-`Lm-2Iq3lK(V{8R&8l%X+!xrc?AU#p9p?oMhW2vQ`<5MUQ5+SQDr zCnoOmu&=JIO^>zof8kh@%YeE;3UXtiXEy~>scjSAt3s$cf~h8u0=4z!|DCpK!(2)^ zLg&w{T7fyHUOx}*!)5tI^ZbZL<>%*X{|ryQc0PJ-VaU(|2Kp4lOX=yje;~s9)e-_t z&YKHiZF4GqkBRj*Jo$HMXvp{kfBc4CVC@Q`8o$R;DXxw+L8JUGuvku8K#mqu~W$f3OQJ5LorSlljeX=#y0UwlXlMw(0Qi?07t zH^VvnL`C`zosW-iB7v-Z#6O)%VlSiI+L)J^e;aT^*r6u@q*6>ZG;R0$&KZ#ju(4hO5%P{JB5&?x-QfVlMgRvV!;o zaB#t6ROK_^ygEBOCwouvCM~?3DW7-X>ATBIsncN^OG;>IX`SE%I1OKVCq8?(tHO$p zuuVre3q!~hdc=ZVt9}FarCVa-sqjqd9pa4t zl;zJOYLZHzmy5w1GQ6AoMBA8r?;IGIVfCf+YRhr!EGYl5l-|I6V~Ed2ivP)(_ zmvNK4Gb!X|anbNw{rR?J<)q?EhmT=hM2bZN9`Z{CyulAOZSBxrFn zMPxx+lS#|UZ}gWHC8a3!?GKDmz;!lb1w9j)+v;B`t-xL>0cY^Hau=f~;*`-XEsL;( zEP$dYcg7^kS9S;JfA8i~3%J-rlM$!$*E18{5_ubMlr6E%i}l%9LbWi6{>Jsb)b1ZR z)B}027_yES5K&#K@EAa^xrK#=Ps5=fz8RLUSkt?}@Y+`CrT+bWcO&)jvY0GXqn4@u zaN7-U{}p}lmu{5&o+n0XDTbYGqPzY5DXq1aK@p!kl-FZ3X*HRS-V^<$c)-bn`{I%0I~~W%20etq+HA zikAdady1-9ESBEHOe@a}OEL@N!{`>w#7Bt3EUT>97N8A?5>Msdzy=Ti0 zb4;QV_7xa;YycM{O@H3{3d4`)g%^9{bgdP_qzcYJ*Oqur<9Bspop)HA7HLqt8? z*;ksOvZNR`>tLYr*kf&Zk`V-t5>qknQV+joxVxeFeP(9n+eD1y@#g_*Rh5yrs(-h) zW2oc-8#f zD7$lCxA9E5NXdL2C&u5zHz24IL_ zzqZ=?H0y=7+Dd)m#6BtuKCvN^6L^Li?RRTBDDtPvp%^SGzo5WsM7eeY6j)ISzNBj% zI&q|sW)khA_r0MQ?12=nypTjCmj!=N6Fv6b7wwHSN+(-9DZ742HGr;M(=B(_V=BsI zu6JKznMmO{Ec{*7spYr_tRVP(>$zT?GdScpy5NA$FyD&nQad3g^I)b-1I=NE%KD4w z+cTkh#Q!2>bfPj^~*D{N$scBH!2spB0S*s;)&r6ts& zgLMAN>Z+rU0MTNS5#=l>D41qoi!kz7xtP>b6NyjI?T1^I<3D%4_F+V6|8h8jX0I%T zIkFt`%zNzb&OdOlwYB})OQdfgu)fF6$l3%VYF+Eh>IfqK3=@14Zb4 zXM3lDKoT&Q@Z|>#{%Ok3X|Asq@XeSA-bn}vu?lAndMfpB0r2d>1BkIIYQ>;vWP}@V zGx42v+o}|5n}<%_)jAeb=CJ$C=QX3>W@ge=MFEjclkRl4RBEvQJel=d+tRf3#a1gE zi((9Tk398RT3#NAI_~J~99wVqxwG?e_<^pqwKcu+htOnrosFyqzekSgMUUBwS^Y(* zk1ZTm9JyuxM@2xf!_DR#2-_tB=Wb`4OCh?{D5!Tgkq1-KCa4XZS{gRlO8zC{lVEDM zWRB_33VkF%4MD;`>2jy8zh}qJ2sLuz3mqH;K~w3evLl3#OT%zzr2$j!tap*51f;Pf zYEJo_#NT~iiSS0iN-9wSASKpI4p@Fa>K`6HuHi|5H3OcU9_x&C9d0$P?#tM|({zud z>^#@YTtq*C+OJQ0DrP4olk;f7anaEguccf;Jayemr=*2h`o_gg+tVW>BP-8D0L0YF zn4E1w$^PXz&`7LiFp1$Vnp#>Se)4eOVtE(c&3vmM>l?*Z{?~xdS7Ea}N->qnn#kfdaPao`_wU)3239#@)WGCX^iFzc0H8XoXV=&2e=aRm zgbPKx+Q}dMi(84Npe>4aP5KH`)zs8HBWnnHv#6-3kmXp>En_Bor?1yLX7v-WMngjg z*4D5X{ouiadtz^+0L1y6dj^Nas@8_jx9D!w1=z^|h~8Sd61u37uKLQXbZq44eKq7w z@S!5AM6B0}#av^zGlGHUF#qe<{dWQ(E_Ue|88sVF722;BNTJmaJgAY?p`(NIjiO>= z4(0nm+3LP$1x?ru&?yQI2zZyfmfn4D;xRo8!ep=cuy;8a)!AiMo2an^YBm9D?*MZ%stn(d!u@VS`4(Z=RLpR6e z8j_ND{9BtHudsL6P4p4Z8e35E_5m58hX8Va5yrD<5;c}8^QG#(h8zZiVUqWD2~j*& zb%goZS-ltibHgI{Iq_})M}x9NZlL7koT8rkqUhQYD+5|_6wg)r9?I61BPap?QbGqH{+Z4z!ZEdjj*B^k!10Xk^qp^UXXfy)Q zTBw_#_NAk89A;fL4&s>;3-$f=kOov2dRh%=A`Os>03QSXADq9R43v(!IYS^6OXism zfP{)dNf%fwj>0p5)P%uo&!Ou%r?{0aG}xO*L`H)17?~;#RzqI6BK^W#s;23wQA1PH zg&Nzzsmm*2kPC>7qY+Hxcw*xG1ESE=c)Jr_`BAXusYJTFVz#QnV8?JO@E-vG2+^}= zov7GR-?ZO~EBzpx1(@mfno3mt7zhMi&IyfAT zUfJdq1%<)g-S~4lJHW^E87$x2_i~`MZEtVCuqgLoibX=is2VZQLOb2G(?^o$SyVy~ z;Z=@TZoj8zaBy(-f!hZFgo~4;l*IC5Q*DM#|czK zXzb=2@ylY`m|yEOl3t89K;x^cwSWdYikV)%e3|*ZD>)Ck76OOEM44+yE7fXqDUSm8 zu4=ia($b6UO-AvSCk@c%xNTd2`u2$(L4ehI&nEOOER;dA0qU6VNMC+a{)ybQ(yvMBBn4;4o21|$#9S5gWOW@^qwqd?pN9pWVr zDQl@fqC4IjA}OA+*IuN~x3RGSLP7xul3Sb(5Cz}wZ!SK#1gb?pS;Md%s8>Lpsj)R{ zo38y0*Ey8j1tbAEIXPpcynJHTw;}H}Hs&__U1x literal 0 HcmV?d00001 diff --git a/hideout-mastodon/build.gradle.kts b/hideout-mastodon/build.gradle.kts index 2265937b..12ad6ee8 100644 --- a/hideout-mastodon/build.gradle.kts +++ b/hideout-mastodon/build.gradle.kts @@ -60,9 +60,14 @@ dependencies { implementation(libs.bundles.coroutines) testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.springframework.security:spring-security-test") + testImplementation(libs.bundles.spring.boot.oauth2) testImplementation(libs.kotlin.junit) testImplementation(libs.coroutines.test) testImplementation(libs.h2db) + testImplementation(libs.flyway.core) + testImplementation(libs.http.signature) + testRuntimeOnly(libs.flyway.postgresql) } diff --git a/hideout-mastodon/src/test/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/StatusQueryServiceImplTest.kt b/hideout-mastodon/src/test/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/StatusQueryServiceImplTest.kt index da7ef30c..abf5bea5 100644 --- a/hideout-mastodon/src/test/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/StatusQueryServiceImplTest.kt +++ b/hideout-mastodon/src/test/kotlin/dev/usbharu/hideout/mastodon/infrastructure/exposedquery/StatusQueryServiceImplTest.kt @@ -6,6 +6,8 @@ import dev.usbharu.hideout.core.domain.model.support.acct.Acct import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId import kotlinx.coroutines.test.runTest +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired @@ -30,4 +32,13 @@ class StatusQueryServiceImplTest { assertNull(status) } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } } \ No newline at end of file diff --git a/hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiPaginationTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiPaginationTest.kt new file mode 100644 index 00000000..b2057786 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiPaginationTest.kt @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.account + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status +import org.assertj.core.api.Assertions.assertThat +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +@Sql("/sql/accounts/test-accounts-statuses.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class AccountApiPaginationTest { + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @Test + fun `apiV1AccountsIdStatusesGet 投稿を取得できる`() { + val content = mockMvc + .get("/api/v1/accounts/1/statuses"){ + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + .andExpect { header { string("Link","; rel=\"next\", ; rel=\"prev\"") } } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + assertThat(value.first().id).isEqualTo("100") + assertThat(value.last().id).isEqualTo("81") + assertThat(value).size().isEqualTo(20) + } + + @Test + fun `apiV1AccountsIdStatusesGet 結果が0件のときはLinkヘッダーがない`() { + val content = mockMvc + .get("/api/v1/accounts/1/statuses?min_id=100"){ + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andDo { print() } + .asyncDispatch() + .andExpect { status { isOk() } } + .andExpect { header { doesNotExist("Link") } } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + + assertThat(value).isEmpty() + } + + @Test + fun `apiV1AccountsIdStatusesGet maxIdを指定して取得`() { + val content = mockMvc + .get("/api/v1/accounts/1/statuses?max_id=100"){ + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + .andExpect { header { string("Link","; rel=\"next\", ; rel=\"prev\"") } } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + assertThat(value.first().id).isEqualTo("99") + assertThat(value.last().id).isEqualTo("80") + assertThat(value).size().isEqualTo(20) + } + + @Test + fun `apiV1AccountsIdStatusesGet minIdを指定して取得`() { + val content = mockMvc + .get("/api/v1/accounts/1/statuses?min_id=1"){ + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + .andExpect { header { string("Link","; rel=\"next\", ; rel=\"prev\"") } } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + assertThat(value.first().id).isEqualTo("21") + assertThat(value.last().id).isEqualTo("2") + assertThat(value).size().isEqualTo(20) + } + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} \ No newline at end of file diff --git a/hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiTest.kt new file mode 100644 index 00000000..c1e5c1be --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/account/AccountApiTest.kt @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.account + +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.actor.ActorRepository +import dev.usbharu.hideout.core.infrastructure.exposedrepository.ExposedRelationshipRepository +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.post +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class AccountApiTest { + + @Autowired + private lateinit var actorRepository: ActorRepository + + @Autowired + lateinit var relationshipRepository: ExposedRelationshipRepository + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(springSecurity()) + .build() + } + + @Test + fun `apiV1AccountsVerifyCredentialsGetにreadでアクセスできる`() { + mockMvc + .get("/api/v1/accounts/verify_credentials") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsVerifyCredentialsGetにread_accountsでアクセスできる`() { + mockMvc + .get("/api/v1/accounts/verify_credentials") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:accounts"))) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + } + + @Test + @WithAnonymousUser + fun apiV1AccountsVerifyCredentialsGetに匿名でアクセスすると401() { + mockMvc + .get("/api/v1/accounts/verify_credentials") + .andExpect { status { isUnauthorized() } } + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostに匿名でPOSTしたらアカウントを作成できる() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-1") + param("password", "very-secure-password") + param("email", "test@example.com") + param("agreement", "true") + param("locale", "") + with(csrf()) + } + .asyncDispatch() + .andExpect { status { isFound() } } + + actorRepository.findByNameAndDomain("api-test-user-1", "example.com") + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostで必須パラメーター以外を省略しても作成できる() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-2") + param("password", "very-secure-password") + with(csrf()) + } + .asyncDispatch() + .andExpect { status { isFound() } } + + actorRepository.findByNameAndDomain("api-test-user-2", "example.com") + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostでusernameパラメーターを省略したら400() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("password", "api-test-user-3") + with(csrf()) + } + .andDo { print() } + .andExpect { status { isUnprocessableEntity() } } + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostでpasswordパラメーターを省略したら400() = runTest { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-4") + with(csrf()) + } + .andExpect { status { isUnprocessableEntity() } } + } + + @Test + @Disabled("JSONでも作れるようにするため") + @WithAnonymousUser + fun apiV1AccountsPostでJSONで作ろうとしても400() { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_JSON + content = """{"username":"api-test-user-5","password":"very-very-secure-password"}""" + with(csrf()) + } + .andExpect { status { isUnsupportedMediaType() } } + } + + @Test + @WithAnonymousUser + fun apiV1AccountsPostにCSRFトークンは必要() { + mockMvc + .post("/api/v1/accounts") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("username", "api-test-user-2") + param("password", "very-secure-password") + } + .andExpect { status { isForbidden() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AccountsIdGet 匿名でアカウント情報を取得できる`() { + mockMvc + .get("/api/v1/accounts/1") + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsIdFollowPost write_follows権限でPOSTでフォローできる`() { + mockMvc + .post("/api/v1/accounts/2/follow") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:follows"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsIdFollowPost write権限でPOSTでフォローできる`() { + mockMvc + .post("/api/v1/accounts/2/follow") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsIdFollowPost read権限でだと403`() { + mockMvc + .post("/api/v1/accounts/2/follow") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .andExpect { status { isForbidden() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AAccountsIdFollowPost 匿名だと401`() { + mockMvc + .post("/api/v1/accounts/2/follow") { + contentType = MediaType.APPLICATION_JSON + with(csrf()) + } + .andExpect { status { isUnauthorized() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AAccountsIdFollowPost 匿名の場合通常csrfトークンは持ってないので403`() { + mockMvc + .post("/api/v1/accounts/2/follow") { + contentType = MediaType.APPLICATION_JSON + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV1AccountsRelationshipsGet 匿名だと401`() { + mockMvc + .get("/api/v1/accounts/relationships") + .andExpect { status { isUnauthorized() } } + } + + @Test + fun `apiV1AccountsRelationshipsGet read_follows権限を持っていたら取得できる`() { + mockMvc + .get("/api/v1/accounts/relationships") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:follows"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsRelationshipsGet read権限を持っていたら取得できる`() { + mockMvc + .get("/api/v1/accounts/relationships") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsRelationshipsGet write権限だと403`() { + mockMvc + .get("/api/v1/accounts/relationships") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .andExpect { status { isForbidden() } } + } + + @Test + @Sql("/sql/accounts/apiV1AccountsIdFollowPost フォローできる.sql") + fun `apiV1AccountsIdFollowPost フォローできる`() = runTest { + mockMvc + .post("/api/v1/accounts/3733363/follow") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "37335363") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + + + val alreadyFollow = relationshipRepository.findByActorIdAndTargetId(ActorId(3733363),ActorId(37335363))?.following + + + assertThat(alreadyFollow).isTrue() + } + + @Test + fun `apiV1AccountsIdMutePost write権限でミュートできる`() { + mockMvc + .post("/api/v1/accounts/2/mute") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsIdMutePost write_mutes権限でミュートできる`() { + mockMvc + .post("/api/v1/accounts/2/mute") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:mutes"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsIdMutePost read権限だと403`() = runTest { + mockMvc + .post("/api/v1/accounts/2/mute") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .andExpect { status { isForbidden() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AccountsIdMutePost 匿名だと401`() = runTest { + mockMvc + .post("/api/v1/accounts/2/mute") { + contentType = MediaType.APPLICATION_JSON + with(csrf()) + } + .andExpect { status { isUnauthorized() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AccountsIdMutePost csrfトークンがないと403`() = runTest { + mockMvc + .post("/api/v1/accounts/2/mute") { + contentType = MediaType.APPLICATION_JSON + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV1AccountsIdUnmutePost write権限でアンミュートできる`() { + mockMvc + .post("/api/v1/accounts/2/unmute") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsIdUnmutePost write_mutes権限でアンミュートできる`() { + mockMvc + .post("/api/v1/accounts/2/unmute") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:mutes"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1AccountsIdUnmutePost read権限だと403`() = runTest { + mockMvc + .post("/api/v1/accounts/2/unmute") { + contentType = MediaType.APPLICATION_JSON + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .andExpect { status { isForbidden() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AccountsIdUnmutePost 匿名だと401`() = runTest { + mockMvc + .post("/api/v1/accounts/2/unmute") { + contentType = MediaType.APPLICATION_JSON + with(csrf()) + } + .andExpect { status { isUnauthorized() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AccountsIdUnmutePost csrfトークンがないと403`() = runTest { + mockMvc + .post("/api/v1/accounts/2/unmute") { + contentType = MediaType.APPLICATION_JSON + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV1MutesGet read権限でミュートしているアカウント一覧を取得できる`() { + mockMvc + .get("/api/v1/mutes") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1MutesGet read_mutes権限でミュートしているアカウント一覧を取得できる`() { + mockMvc + .get("/api/v1/mutes") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:mutes"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1MutesGet write権限だと403`() { + mockMvc + .get("/api/v1/mutes") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .andExpect { status { isForbidden() } } + } + + @Test + @WithAnonymousUser + fun `apiV1MutesGet 匿名だと401`() { + mockMvc + .get("/api/v1/mutes") + .andExpect { status { isUnauthorized() } } + } + + @Test + fun `apiV1AccountsIdStatusesGet read権限で取得できる`() { + mockMvc + .get("/api/v1/accounts/1/statuses") + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + @WithAnonymousUser + fun `apiV1AccountsIdStatusesGet 匿名でもpublic投稿を取得できる`() { + mockMvc + .get("/api/v1/accounts/1/statuses") + .asyncDispatch() + .andExpect { status { isOk() } } + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} diff --git a/hideout-mastodon/src/test/kotlin/mastodon/apps/AppTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/apps/AppTest.kt new file mode 100644 index 00000000..1b80163c --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/apps/AppTest.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.apps + +import dev.usbharu.hideout.SpringApplication +import org.assertj.core.api.Assertions.assertThat +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.jdbc.core.JdbcOperations +import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository +import org.springframework.security.test.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.post +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext +import util.objectMapper +import kotlin.test.assertNotNull + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +class AppTest { + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @Autowired + lateinit var jdbcOperations: JdbcOperations + + + val registeredClientRepository: JdbcRegisteredClientRepository by lazy { + JdbcRegisteredClientRepository( + jdbcOperations + ) + } + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + @WithAnonymousUser + fun apiV1AppsPostにformで匿名でappを作成できる() { + val contentAsString = mockMvc + .post("/api/v1/apps") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("client_name", "test-client") + param("redirect_uris", "https://example.com") + param("scopes", "write read") + param("website", "https://example.com") + } + .asyncDispatch() + .andExpect { status { isOk() } } + .andReturn() + .response + .contentAsString + + val clientId = objectMapper().readTree(contentAsString)["client_id"].asText() + + + val registeredClient = registeredClientRepository.findByClientId(clientId) + + assertNotNull(registeredClient) + assertThat(registeredClient.clientName).isEqualTo("test-client") + assertThat(registeredClient.redirectUris.joinToString(",")).isEqualTo("https://example.com") + assertThat(registeredClient.scopes.joinToString(",")).isEqualTo("read,write") + } + + @Test + @WithAnonymousUser + fun apiV1AppsPostにjsonで匿名でappを作成できる() { + val contentAsString = mockMvc + .post("/api/v1/apps") { + contentType = MediaType.APPLICATION_JSON + content = """{ + "client_name": "test-client-2", + "redirect_uris": "https://example.com", + "scopes": "write read", + "website": "https;//example.com" +}""" + } + .asyncDispatch() + .andExpect { status { isOk() } } + .andReturn() + .response + .contentAsString + + val clientId = objectMapper().readTree(contentAsString)["client_id"].asText() + + + val registeredClient = registeredClientRepository.findByClientId(clientId) + + assertNotNull(registeredClient) + assertThat(registeredClient.clientName).isEqualTo("test-client-2") + assertThat(registeredClient.redirectUris.joinToString(",")).isEqualTo("https://example.com") + assertThat(registeredClient.scopes.joinToString(",")).isEqualTo("read,write") + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} diff --git a/hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt new file mode 100644 index 00000000..73615a07 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt @@ -0,0 +1,710 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.filter + +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.FilterKeywordsPostRequest +import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.FilterPostRequest +import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.FilterPostRequestKeyword +import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.V1FilterPostRequest +import kotlinx.coroutines.test.runTest +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.delete +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.post +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext +import util.objectMapper + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/actors.sql", "/sql/userdetail.sql","/sql/filter/test-filter.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class FilterTest { + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + fun `apiV2FiltersPost write権限で追加できる`() { + mockMvc + .post("/api/v2/filters") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + FilterPostRequest( + title = "mute test", + context = listOf(FilterPostRequest.Context.home, FilterPostRequest.Context.public), + filterAction = FilterPostRequest.FilterAction.warn, + expiresIn = null, + keywordsAttributes = listOf( + FilterPostRequestKeyword( + keyword = "hoge", + wholeWord = false, + regex = true + ) + ) + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + .andExpect { + content { + jsonPath("$.keywords[0].keyword") { + value("hoge") + } + } + } + } + + @Test + fun `apiV2FiltersPost write_filters権限で追加できる`() { + mockMvc + .post("/api/v2/filters") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + FilterPostRequest( + title = "mute test", + context = listOf(FilterPostRequest.Context.home, FilterPostRequest.Context.public), + filterAction = FilterPostRequest.FilterAction.warn, + expiresIn = null, + keywordsAttributes = listOf( + FilterPostRequestKeyword( + keyword = "fuga", + wholeWord = true, + regex = false + ) + ) + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + .andExpect { + content { + jsonPath("$.keywords[0].keyword") { + value("fuga") + } + } + } + } + + @Test + fun `apiV2FiltersPost read権限で401`() { + mockMvc + .post("/api/v2/filters") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + FilterPostRequest( + title = "mute test", + context = listOf(FilterPostRequest.Context.home, FilterPostRequest.Context.public), + filterAction = FilterPostRequest.FilterAction.warn, + expiresIn = null, + keywordsAttributes = listOf( + FilterPostRequestKeyword( + keyword = "fuga", + wholeWord = true, + regex = false + ) + ) + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersGet read権限で取得できる`() { + mockMvc + .get("/api/v2/filters") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersGet read_filters権限で取得できる`() { + mockMvc + .get("/api/v2/filters") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersGet write権限で401`() { + mockMvc + .get("/api/v2/filters") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersIdGet read権限で取得できる`() { + mockMvc + .get("/api/v2/filters/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + + @Test + fun `apiV2FiltersIdGet read_filters権限で取得できる`() { + mockMvc + .get("/api/v2/filters/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersIdGet write権限で401`() { + mockMvc + .get("/api/v2/filters/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersFilterIdKeywordsGet read権限で取得できる`() { + mockMvc + .get("/api/v2/filters/1/keywords") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersFilterIdKeywordsGet read_filters権限で取得できる`() { + mockMvc + .get("/api/v2/filters/1/keywords") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersFilterIdKeywordsGet writeで403`() { + mockMvc + .get("/api/v2/filters/1/keywords") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersFilterIdKeywordsPost writeで追加できる`() { + mockMvc + .post("/api/v2/filters/1/keywords") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + FilterKeywordsPostRequest( + "hage", false, false + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersFilterIdKeywordsPost write_filtersで追加できる`() { + mockMvc + .post("/api/v2/filters/1/keywords") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + FilterKeywordsPostRequest( + "hage", false, false + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersFilterIdKeywordsPost readで403`() { + mockMvc + .post("/api/v2/filters/1/keywords") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + FilterKeywordsPostRequest( + "hage", false, false + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersKeywordsIdGet readで取得できる`() { + mockMvc + .get("/api/v2/filters/keywords/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersKeywordsIdGet read_filtersで取得できる`() { + mockMvc + .get("/api/v2/filters/keywords/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersKeywordsIdGet writeだと403`() { + mockMvc + .get("/api/v2/filters/keywords/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersKeyowrdsIdDelete writeで削除できる`() = runTest { + mockMvc + .delete("/api/v2/filters/keywords/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersKeyowrdsIdDelete write_filtersで削除できる`() = runTest { + mockMvc + .delete("/api/v2/filters/keywords/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersKeyowrdsIdDelete readで403`() = runTest { + mockMvc + .delete("/api/v2/filters/keywords/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersFilterIdStatuses readで取得できる`() { + mockMvc + .get("/api/v2/filters/1/statuses") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersFilterIdStatuses read_filtersで取得できる`() { + mockMvc + .get("/api/v2/filters/1/statuses") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersFilterIdStatuses writeで403`() { + mockMvc + .get("/api/v2/filters/1/statuses") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersStatusesIdGet readで取得できる`() { + mockMvc + .get("/api/v2/filters/statuses/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersStatusesIdGet read_filtersで取得できる`() { + mockMvc + .get("/api/v2/filters/statuses/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersStatusesIdGet writeで403`() { + mockMvc + .get("/api/v2/filters/statuses/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV2FiltersStatusesIdDelete writeで削除できる`() { + mockMvc + .delete("/api/v2/filters/statuses/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersStatusesIdDelete write_filtersで削除できる`() { + mockMvc + .delete("/api/v2/filters/statuses/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV2FiltersStatusesIdDelete readで403`() { + mockMvc + .delete("/api/v2/filters/statuses/1") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV1FiltersGet readで取得できる`() { + mockMvc + .get("/api/v1/filters") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersGet read_filtersで取得できる`() { + mockMvc + .get("/api/v1/filters") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersGet writeで403`() { + mockMvc + .get("/api/v1/filters") { + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV1FiltersPost writeで新規作成`() { + mockMvc + .post("/api/v1/filters") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + V1FilterPostRequest( + phrase = "hoge", + context = listOf(V1FilterPostRequest.Context.home), + irreversible = false, + wholeWord = false, + expiresIn = null + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersPost write_filtersで新規作成`() { + mockMvc + .post("/api/v1/filters") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + V1FilterPostRequest( + phrase = "hoge", + context = listOf(V1FilterPostRequest.Context.home), + irreversible = false, + wholeWord = false, + expiresIn = null + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersPost readで403`() { + mockMvc + .post("/api/v1/filters") { + contentType = MediaType.APPLICATION_JSON + content = objectMapper().writeValueAsString( + V1FilterPostRequest( + phrase = "hoge", + context = listOf(V1FilterPostRequest.Context.home), + irreversible = false, + wholeWord = false, + expiresIn = null + ) + ) + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV1FiltersIdGet readで取得できる`() { + mockMvc + .get("/api/v1/filters/1") { + with( + jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersIdGet read_filtersで取得できる`() { + mockMvc + .get("/api/v1/filters/1") { + with( + jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersIdGet writeで403`() { + mockMvc + .get("/api/v1/filters/1") { + with( + jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + fun `apiV1FiltersIdDelete writeで削除できる`() { + mockMvc + .delete("/api/v1/filters/1") { + with( + jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersIdDelete write_filtersで削除できる`() { + mockMvc + .delete("/api/v1/filters/1") { + with( + jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:filters")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1FiltersIdDelete readで403`() { + mockMvc + .delete("/api/v1/filters/1") { + with( + jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} \ No newline at end of file diff --git a/hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt new file mode 100644 index 00000000..13d2bd55 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.media + +import dev.usbharu.hideout.SpringApplication +import kotlinx.coroutines.test.runTest +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.mock.web.MockMultipartFile +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.multipart +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class MediaTest { + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + fun メディアをアップロードできる() = runTest { + + + mockMvc + .multipart("/api/v1/media") { + + file( + MockMultipartFile( + "file", + "400x400.png", + "image/png", + String.javaClass.classLoader.getResourceAsStream("media/400x400.png") + ) + ) + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun write_mediaスコープでメディアをアップロードできる() = runTest { + + + mockMvc + .multipart("/api/v1/media") { + + file( + MockMultipartFile( + "file", + "400x400.png", + "image/png", + String.javaClass.classLoader.getResourceAsStream("media/400x400.png") + ) + ) + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:media"))) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun 権限がないと403() = runTest { + + + mockMvc + .multipart("/api/v1/media") { + + file( + MockMultipartFile( + "file", + "400x400.png", + "image/png", + String.javaClass.classLoader.getResourceAsStream("media/400x400.png") + ) + ) + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read"))) + } + .andExpect { status { isForbidden() } } + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } + +} diff --git a/hideout-mastodon/src/test/kotlin/mastodon/notifications/ExposedNotificationsApiPaginationTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/notifications/ExposedNotificationsApiPaginationTest.kt new file mode 100644 index 00000000..97f6f8f1 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/notifications/ExposedNotificationsApiPaginationTest.kt @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.notifications + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Notification +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions.assertThat +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class], properties = ["hideout.use-mongodb=false"]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +//@Sql("/sql/notification/test-notifications.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +//@Sql("/sql/notification/test-mastodon_notifications.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class ExposedNotificationsApiPaginationTest { + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @Test + fun `通知を取得できる`() = runTest { + val content = mockMvc + .get("/api/v1/notifications") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { + header { + string( + "Link", + "; rel=\"next\", ; rel=\"prev\"" + ) + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + assertThat(value.first().id).isEqualTo("65") + assertThat(value.last().id).isEqualTo("26") + } + + @Test + fun maxIdを指定して通知を取得できる() = runTest { + val content = mockMvc + .get("/api/v1/notifications?max_id=26") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { + header { + string( + "Link", + "; rel=\"next\", ; rel=\"prev\"" + ) + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + assertThat(value.first().id).isEqualTo("25") + assertThat(value.last().id).isEqualTo("1") + + } + + @Test + fun minIdを指定して通知を取得できる() = runTest { + val content = mockMvc + .get("/api/v1/notifications?min_id=25") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { + header { + string( + "Link", + "; rel=\"next\", ; rel=\"prev\"" + ) + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + assertThat(value.first().id).isEqualTo("65") + assertThat(value.last().id).isEqualTo("26") + } + + @Test + fun 結果が0件のときはページネーションのヘッダーがない() = runTest { + val content = mockMvc + .get("/api/v1/notifications?max_id=1") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { + header { + doesNotExist("Link") + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + assertThat(value).size().isZero() + } + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} \ No newline at end of file diff --git a/hideout-mastodon/src/test/kotlin/mastodon/notifications/MongodbNotificationsApiPaginationTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/notifications/MongodbNotificationsApiPaginationTest.kt new file mode 100644 index 00000000..c0debcd5 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/notifications/MongodbNotificationsApiPaginationTest.kt @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.notifications + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Notification +import kotlinx.coroutines.test.runTest +import org.assertj.core.api.Assertions +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class], properties = ["hideout.use-mongodb=true"]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +//@Sql("/sql/notification/test-notifications.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class MongodbNotificationsApiPaginationTest { + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @Test + fun `通知を取得できる`() = runTest { + val content = mockMvc + .get("/api/v1/notifications") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andDo { print() } + .andExpect { + header { + string( + "Link", + "; rel=\"next\", ; rel=\"prev\"" + ) + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + Assertions.assertThat(value.first().id).isEqualTo("65") + Assertions.assertThat(value.last().id).isEqualTo("26") + } + + @Test + fun maxIdを指定して通知を取得できる() = runTest { + val content = mockMvc + .get("/api/v1/notifications?max_id=26") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { + header { + string( + "Link", + "; rel=\"next\", ; rel=\"prev\"" + ) + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + Assertions.assertThat(value.first().id).isEqualTo("25") + Assertions.assertThat(value.last().id).isEqualTo("1") + + } + + @Test + fun minIdを指定して通知を取得できる() = runTest { + val content = mockMvc + .get("/api/v1/notifications?min_id=25") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { + header { + string( + "Link", + "; rel=\"next\", ; rel=\"prev\"" + ) + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + Assertions.assertThat(value.first().id).isEqualTo("65") + Assertions.assertThat(value.last().id).isEqualTo("26") + } + + @Test + fun 結果が0件のときはページネーションのヘッダーがない() = runTest { + val content = mockMvc + .get("/api/v1/notifications?max_id=1") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { + header { + doesNotExist("Link") + } + } + .andReturn() + .response + .contentAsString + + val value = jacksonObjectMapper().readValue(content, object : TypeReference>() {}) + + Assertions.assertThat(value).size().isZero() + } + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} \ No newline at end of file diff --git a/hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt new file mode 100644 index 00000000..790c3cc6 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.status + +import dev.usbharu.hideout.SpringApplication +import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji +import dev.usbharu.hideout.core.infrastructure.exposedrepository.CustomEmojis +import dev.usbharu.hideout.core.infrastructure.exposedrepository.Reactions +import dev.usbharu.hideout.core.infrastructure.exposedrepository.toReaction +import org.assertj.core.api.Assertions.assertThat +import org.flywaydb.core.Flyway +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.selectAll +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.post +import org.springframework.test.web.servlet.put +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class]) +@AutoConfigureMockMvc +@Transactional +@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +@Sql("/sql/posts.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +@Sql("/sql/test-custom-emoji.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class StatusTest { + + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + + @BeforeEach + fun setUp() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + fun 投稿できる() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun write_statusesスコープで投稿できる() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:statuses")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun 権限がないと403() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .andExpect { status { isForbidden() } } + } + + @Test + @WithAnonymousUser + fun 匿名だと401() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + with(csrf()) + } + .andExpect { status { isUnauthorized() } } + } + + @Test + @WithAnonymousUser + fun 匿名の場合通常はcsrfが無いので403() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + content = """{"status":"hello"}""" + } + .andExpect { status { isForbidden() } } + } + + @Test + fun formでも投稿できる() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_FORM_URLENCODED + param("status", "hello") + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write:statuses")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun in_reply_to_idを指定したら返信として処理される() { + mockMvc + .post("/api/v1/statuses") { + contentType = MediaType.APPLICATION_JSON + //language=JSON + content = """{ + "status": "hello", + "in_reply_to_id": "1" +}""" + with( + jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + ) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + .andExpect { jsonPath("\$.in_reply_to_id") { value("1") } } + } + + @Test + fun ユニコード絵文字をリアクションできる() { + mockMvc + .put("/api/v1/statuses/1/emoji_reactions/😭") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .andDo { print() } + .asyncDispatch() + .andExpect { status { isOk() } } + + val reaction = + Reactions.selectAll().where { Reactions.postId eq 1 and (Reactions.actorId eq 1) }.single().toReaction() + assertThat(reaction.unicodeEmoji).isEqualTo(UnicodeEmoji("😭")) + assertThat(reaction.postId).isEqualTo(1) + assertThat(reaction.actorId).isEqualTo(1) + } + + @Test + fun 存在しない絵文字はフォールバックされる() { + mockMvc + .put("/api/v1/statuses/1/emoji_reactions/hoge") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .andDo { print() } + .asyncDispatch() + .andExpect { status { isOk() } } + + val reaction = + Reactions.selectAll().where { Reactions.postId eq 1 and (Reactions.actorId eq 1) }.single().toReaction() + assertThat(reaction.unicodeEmoji).isEqualTo(UnicodeEmoji("❤")) + assertThat(reaction.postId).isEqualTo(1) + assertThat(reaction.actorId).isEqualTo(1) + } + + @Test + fun カスタム絵文字をリアクションできる() { + mockMvc + .put("/api/v1/statuses/1/emoji_reactions/kotlin") { + with(jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write"))) + } + .andDo { print() } + .asyncDispatch() + .andExpect { status { isOk() } } + + val reaction = + Reactions.leftJoin(CustomEmojis).selectAll().where { Reactions.postId eq 1 and (Reactions.actorId eq 1) } + .single() + .toReaction() + + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} diff --git a/hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt new file mode 100644 index 00000000..4d20bcfb --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package mastodon.timelines + +import dev.usbharu.hideout.SpringApplication +import org.flywaydb.core.Flyway +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.test.context.support.WithAnonymousUser +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers +import org.springframework.test.context.jdbc.Sql +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.get +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.context.WebApplicationContext + +@SpringBootTest(classes = [SpringApplication::class]) +@Transactional +@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +class TimelineApiTest { + @Autowired + private lateinit var context: WebApplicationContext + + private lateinit var mockMvc: MockMvc + + @BeforeEach + fun beforeEach() { + mockMvc = MockMvcBuilders.webAppContextSetup(context) + .apply(SecurityMockMvcConfigurers.springSecurity()) + .build() + } + + @Test + fun `apiV1TimelinesHomeGetにreadでアクセスできる`() { + mockMvc + .get("/api/v1/timelines/home") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1TimelinesHomeGetにread statusesでアクセスできる`() { + mockMvc + .get("/api/v1/timelines/home") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:statuses")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + @WithAnonymousUser + fun apiV1TimelineHomeGetに匿名でアクセスすると401() { + mockMvc + .get("/api/v1/timelines/home") + .andExpect { status { isUnauthorized() } } + } + + @Test + fun apiV1TimelinesPublicGetにreadでアクセスできる() { + mockMvc + .get("/api/v1/timelines/public") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + fun `apiV1TimelinesPublicGetにread statusesでアクセスできる`() { + mockMvc + .get("/api/v1/timelines/public") { + with( + SecurityMockMvcRequestPostProcessors.jwt() + .jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read:statuses")) + ) + } + .asyncDispatch() + .andExpect { status { isOk() } } + } + + @Test + @WithAnonymousUser + fun apiV1TimeinesPublicGetに匿名でアクセスできる() { + mockMvc + .get("/api/v1/timelines/public") + .asyncDispatch() + .andExpect { status { isOk() } } + } + + companion object { + @JvmStatic + @AfterAll + fun dropDatabase(@Autowired flyway: Flyway) { + flyway.clean() + flyway.migrate() + } + } +} diff --git a/hideout-mastodon/src/test/kotlin/util/Json.kt b/hideout-mastodon/src/test/kotlin/util/Json.kt new file mode 100644 index 00000000..fe49c2ca --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/util/Json.kt @@ -0,0 +1,8 @@ +package util + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper + +fun objectMapper(): ObjectMapper { + return jacksonObjectMapper() +} \ No newline at end of file diff --git a/hideout-mastodon/src/test/kotlin/util/SpringApplicationTestBase.kt b/hideout-mastodon/src/test/kotlin/util/SpringApplicationTestBase.kt new file mode 100644 index 00000000..158f8c7a --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/util/SpringApplicationTestBase.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest +abstract class SpringApplicationTestBase diff --git a/hideout-mastodon/src/test/kotlin/util/TestTransaction.kt b/hideout-mastodon/src/test/kotlin/util/TestTransaction.kt new file mode 100644 index 00000000..8830ba4e --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/util/TestTransaction.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +import dev.usbharu.hideout.core.application.shared.Transaction + + +object TestTransaction : Transaction { + override suspend fun transaction(block: suspend () -> T): T = block() + + override suspend fun transaction(transactionLevel: Int, block: suspend () -> T): T = block() +} diff --git a/hideout-mastodon/src/test/kotlin/util/WithHttpSignature.kt b/hideout-mastodon/src/test/kotlin/util/WithHttpSignature.kt new file mode 100644 index 00000000..d7e58abc --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/util/WithHttpSignature.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +//@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE) +//@Retention(AnnotationRetention.RUNTIME) +//@Inherited +//@MustBeDocumented +//@WithSecurityContext(factory = WithHttpSignatureSecurityContextFactory::class) +//annotation class WithHttpSignature( +// @get:AliasFor( +// annotation = WithSecurityContext::class +// ) val setupBefore: TestExecutionEvent = TestExecutionEvent.TEST_METHOD, +// val keyId: String = "https://example.com/users/test-user#pubkey", +// val url: String = "https://example.com/inbox", +// val method: String = "GET" +//) diff --git a/hideout-mastodon/src/test/kotlin/util/WithHttpSignatureSecurityContextFactory.kt b/hideout-mastodon/src/test/kotlin/util/WithHttpSignatureSecurityContextFactory.kt new file mode 100644 index 00000000..626cf79e --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/util/WithHttpSignatureSecurityContextFactory.kt @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +//class WithHttpSignatureSecurityContextFactory( +// private val actorRepository: ActorRepository, +// private val transaction: Transaction +//) : WithSecurityContextFactory { +// +// private val securityContextStrategy = SecurityContextHolder.getContextHolderStrategy() +// +// override fun createSecurityContext(annotation: WithHttpSignature): SecurityContext = runBlocking { +// val preAuthenticatedAuthenticationToken = PreAuthenticatedAuthenticationToken( +// annotation.keyId, HttpRequest( +// URL("https://example.com/inbox"), +// HttpHeaders(mapOf()), HttpMethod.GET +// ) +// ) +// val httpSignatureUser = transaction.transaction { +// val findByKeyId = +// actorRepository.findByKeyId(annotation.keyId) ?: throw IllegalArgumentException(annotation.keyId) +// HttpSignatureUser( +// findByKeyId.name, +// findByKeyId.domain, +// findByKeyId.id, +// true, +// true, +// mutableListOf() +// ) +// } +// preAuthenticatedAuthenticationToken.details = httpSignatureUser +// preAuthenticatedAuthenticationToken.isAuthenticated = true +// val emptyContext = securityContextStrategy.createEmptyContext() +// emptyContext.authentication = preAuthenticatedAuthenticationToken +// return@runBlocking emptyContext +// } +// +//} diff --git a/hideout-mastodon/src/test/kotlin/util/WithMockHttpSignature.kt b/hideout-mastodon/src/test/kotlin/util/WithMockHttpSignature.kt new file mode 100644 index 00000000..fcaba839 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/util/WithMockHttpSignature.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util + +// +//@Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE) +//@Retention(AnnotationRetention.RUNTIME) +//@Inherited +//@MustBeDocumented +//@WithSecurityContext(factory = WithMockHttpSignatureSecurityContextFactory::class) +//annotation class WithMockHttpSignature( +// @get:AliasFor( +// annotation = WithSecurityContext::class +// ) val setupBefore: TestExecutionEvent = TestExecutionEvent.TEST_METHOD, +// val username: String = "test-user", +// val domain: String = "example.com", +// val keyId: String = "https://example.com/users/test-user#pubkey", +// val id: Long = 1234L, +// val url: String = "https://example.com/inbox", +// val method: String = "GET" +//) diff --git a/hideout-mastodon/src/test/kotlin/util/WithMockHttpSignatureSecurityContextFactory.kt b/hideout-mastodon/src/test/kotlin/util/WithMockHttpSignatureSecurityContextFactory.kt new file mode 100644 index 00000000..bf5218f6 --- /dev/null +++ b/hideout-mastodon/src/test/kotlin/util/WithMockHttpSignatureSecurityContextFactory.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024 usbharu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package util +// +//import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUser +//import dev.usbharu.httpsignature.common.HttpHeaders +//import dev.usbharu.httpsignature.common.HttpMethod +//import dev.usbharu.httpsignature.common.HttpRequest +//import org.springframework.security.core.context.SecurityContext +//import org.springframework.security.core.context.SecurityContextHolder +//import org.springframework.security.test.context.support.WithSecurityContextFactory +//import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken +//import java.net.URL +// +//class WithMockHttpSignatureSecurityContextFactory : +// WithSecurityContextFactory { +// +// private val securityContextStrategy = SecurityContextHolder.getContextHolderStrategy() +// +// override fun createSecurityContext(annotation: WithMockHttpSignature): SecurityContext { +// val preAuthenticatedAuthenticationToken = PreAuthenticatedAuthenticationToken( +// annotation.keyId, HttpRequest( +// URL(annotation.url), +// HttpHeaders(mapOf()), HttpMethod.valueOf(annotation.method.uppercase()) +// ) +// ) +// val httpSignatureUser = HttpSignatureUser( +// annotation.username, +// annotation.domain, +// annotation.id, +// true, +// true, +// mutableListOf() +// ) +// preAuthenticatedAuthenticationToken.details = httpSignatureUser +// preAuthenticatedAuthenticationToken.isAuthenticated = true +// val emptyContext = securityContextStrategy.createEmptyContext() +// emptyContext.authentication = preAuthenticatedAuthenticationToken +// return emptyContext +// } +//} diff --git a/hideout-mastodon/src/test/resources/application.yml b/hideout-mastodon/src/test/resources/application.yml index 05671a3f..0f4fd0e1 100644 --- a/hideout-mastodon/src/test/resources/application.yml +++ b/hideout-mastodon/src/test/resources/application.yml @@ -2,6 +2,8 @@ spring: datasource: url: "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;" driver-class-name: org.h2.Driver + flyway: + clean-disabled: false hideout: url: "https://test-hideout-dev.usbharu.dev" security: @@ -9,4 +11,4 @@ hideout: generate: true key-id: a private-key: "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvuNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulgp2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlRZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwiVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskVlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83HmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwYdgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cwta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2TN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPvt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDUAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISLDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnKxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEAmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfzet6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhrVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicDTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cncdn/RsYEONbwQSjIfMPkvxF+8HQ==" - public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB" \ No newline at end of file + public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB" diff --git a/hideout-mastodon/src/test/resources/sql/accounts/apiV1AccountsIdFollowPost フォローできる.sql b/hideout-mastodon/src/test/resources/sql/accounts/apiV1AccountsIdFollowPost フォローできる.sql new file mode 100644 index 00000000..a2b01c22 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/accounts/apiV1AccountsIdFollowPost フォローできる.sql @@ -0,0 +1,17 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (3733363, 'follow-test-user-1', 'example.com', 'follow-test-user-1-name', '', + 'https://example.com/users/follow-test-user-1/inbox', + 'https://example.com/users/follow-test-user-1/outbox', 'https://example.com/users/follow-test-user-1', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/follow-test-user-1#pubkey', 'https://example.com/users/follow-test-user-1/following', + 'https://example.com/users/follow-test-user-1/followers', 0, false, 0, 0, 0, null), + (37335363, 'follow-test-user-2', 'example.com', 'follow-test-user-2-name', '', + 'https://example.com/users/follow-test-user-2/inbox', + 'https://example.com/users/follow-test-user-2/outbox', 'https://example.com/users/follow-test-user-2', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/follow-test-user-2#pubkey', 'https://example.com/users/follow-test-user-2/following', + 'https://example.com/users/follow-test-user-2/followers', 0, false, 0, 0, 0, null); diff --git a/hideout-mastodon/src/test/resources/sql/accounts/test-accounts-statuses.sql b/hideout-mastodon/src/test/resources/sql/accounts/test-accounts-statuses.sql new file mode 100644 index 00000000..058a3e81 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/accounts/test-accounts-statuses.sql @@ -0,0 +1,201 @@ +insert into posts (id, actor_id, instance_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id, deleted, hide, move_to) +VALUES (1, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/1', + null, null, false, 'https://example.com/users/1/posts/1', false,false,null), + (2, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/2', + null, 1, false, 'https://example.com/users/1/posts/2', false,false,null), + (3, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/3', + null, null, false, 'https://example.com/users/1/posts/3', false,false,null), + (4, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/4', + null, 3, false, 'https://example.com/users/1/posts/4', false,false,null), + (5, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/5', + null, null, false, 'https://example.com/users/1/posts/5', false,false,null), + (6, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/6', + null, null, false, 'https://example.com/users/1/posts/6', false,false,null), + (7, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/7', + null, null, false, 'https://example.com/users/1/posts/7', false,false,null), + (8, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/8', + null, 7, false, 'https://example.com/users/1/posts/8', false,false,null), + (9, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/9', + null, null, false, 'https://example.com/users/1/posts/9', false,false,null), + (10, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/10', + null, 9, false, 'https://example.com/users/1/posts/10', false,false,null), + (11, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/11', + null, null, false, 'https://example.com/users/1/posts/11', false,false,null), + (12, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/12', + null, null, false, 'https://example.com/users/1/posts/12', false,false,null), + (13, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/13', + null, null, false, 'https://example.com/users/1/posts/13', false,false,null), + (14, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/14', + null, 13, false, 'https://example.com/users/1/posts/14', false,false,null), + (15, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/15', + null, null, false, 'https://example.com/users/1/posts/15', false,false,null), + (16, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/16', + null, 15, false, 'https://example.com/users/1/posts/16', false,false,null), + (17, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/17', + null, null, false, 'https://example.com/users/1/posts/17', false,false,null), + (18, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/18', + null, null, false, 'https://example.com/users/1/posts/18', false,false,null), + (19, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/19', + null, null, false, 'https://example.com/users/1/posts/19', false,false,null), + (20, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/20', + null, 19, false, 'https://example.com/users/1/posts/20', false,false,null), + (21, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/21', + null, null, false, 'https://example.com/users/1/posts/21', false,false,null), + (22, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/22', + null, 21, false, 'https://example.com/users/1/posts/22', false,false,null), + (23, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/23', + null, null, false, 'https://example.com/users/1/posts/23', false,false,null), + (24, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/24', + null, null, false, 'https://example.com/users/1/posts/24', false,false,null), + (25, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/25', + null, null, false, 'https://example.com/users/1/posts/25', false,false,null), + (26, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/26', + null, 25, false, 'https://example.com/users/1/posts/26', false,false,null), + (27, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/27', + null, null, false, 'https://example.com/users/1/posts/27', false,false,null), + (28, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/28', + null, 27, false, 'https://example.com/users/1/posts/28', false,false,null), + (29, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/29', + null, null, false, 'https://example.com/users/1/posts/29', false,false,null), + (30, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/30', + null, null, false, 'https://example.com/users/1/posts/30', false,false,null), + (31, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/31', + null, null, false, 'https://example.com/users/1/posts/31', false,false,null), + (32, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/32', + null, 31, false, 'https://example.com/users/1/posts/32', false,false,null), + (33, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/33', + null, null, false, 'https://example.com/users/1/posts/33', false,false,null), + (34, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/34', + null, 33, false, 'https://example.com/users/1/posts/34', false,false,null), + (35, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/35', + null, null, false, 'https://example.com/users/1/posts/35', false,false,null), + (36, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/36', + null, null, false, 'https://example.com/users/1/posts/36', false,false,null), + (37, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/37', + null, null, false, 'https://example.com/users/1/posts/37', false,false,null), + (38, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/38', + null, 37, false, 'https://example.com/users/1/posts/38', false,false,null), + (39, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/39', + null, null, false, 'https://example.com/users/1/posts/39', false,false,null), + (40, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/40', + null, 39, false, 'https://example.com/users/1/posts/40', false,false,null), + (41, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/41', + null, null, false, 'https://example.com/users/1/posts/41', false,false,null), + (42, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/42', + null, null, false, 'https://example.com/users/1/posts/42', false,false,null), + (43, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/43', + null, null, false, 'https://example.com/users/1/posts/43', false,false,null), + (44, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/44', + null, 43, false, 'https://example.com/users/1/posts/44', false,false,null), + (45, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/45', + null, null, false, 'https://example.com/users/1/posts/45', false,false,null), + (46, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/46', + null, 45, false, 'https://example.com/users/1/posts/46', false,false,null), + (47, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/47', + null, null, false, 'https://example.com/users/1/posts/47', false,false,null), + (48, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/48', + null, null, false, 'https://example.com/users/1/posts/48', false,false,null), + (49, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/49', + null, null, false, 'https://example.com/users/1/posts/49', false,false,null), + (50, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/50', + null, 49, false, 'https://example.com/users/1/posts/50', false,false,null), + (51, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/51', + null, null, false, 'https://example.com/users/1/posts/51', false,false,null), + (52, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/52', + null, 51, false, 'https://example.com/users/1/posts/52', false,false,null), + (53, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/53', + null, null, false, 'https://example.com/users/1/posts/53', false,false,null), + (54, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/54', + null, null, false, 'https://example.com/users/1/posts/54', false,false,null), + (55, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/55', + null, null, false, 'https://example.com/users/1/posts/55', false,false,null), + (56, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/56', + null, 55, false, 'https://example.com/users/1/posts/56', false,false,null), + (57, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/57', + null, null, false, 'https://example.com/users/1/posts/57', false,false,null), + (58, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/58', + null, 57, false, 'https://example.com/users/1/posts/58', false,false,null), + (59, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/59', + null, null, false, 'https://example.com/users/1/posts/59', false,false,null), + (60, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/60', + null, null, false, 'https://example.com/users/1/posts/60', false,false,null), + (61, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/61', + null, null, false, 'https://example.com/users/1/posts/61', false,false,null), + (62, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/62', + null, 61, false, 'https://example.com/users/1/posts/62', false,false,null), + (63, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/63', + null, null, false, 'https://example.com/users/1/posts/63', false,false,null), + (64, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/64', + null, 63, false, 'https://example.com/users/1/posts/64', false,false,null), + (65, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/65', + null, null, false, 'https://example.com/users/1/posts/65', false,false,null), + (66, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/66', + null, null, false, 'https://example.com/users/1/posts/66', false,false,null), + (67, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/67', + null, null, false, 'https://example.com/users/1/posts/67', false,false,null), + (68, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/68', + null, 67, false, 'https://example.com/users/1/posts/68', false,false,null), + (69, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/69', + null, null, false, 'https://example.com/users/1/posts/69', false,false,null), + (70, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/70', + null, 69, false, 'https://example.com/users/1/posts/70', false,false,null), + (71, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/71', + null, null, false, 'https://example.com/users/1/posts/71', false,false,null), + (72, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/72', + null, null, false, 'https://example.com/users/1/posts/72', false,false,null), + (73, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/73', + null, null, false, 'https://example.com/users/1/posts/73', false,false,null), + (74, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/74', + null, 73, false, 'https://example.com/users/1/posts/74', false,false,null), + (75, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/75', + null, null, false, 'https://example.com/users/1/posts/75', false,false,null), + (76, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/76', + null, 75, false, 'https://example.com/users/1/posts/76', false,false,null), + (77, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/77', + null, null, false, 'https://example.com/users/1/posts/77', false,false,null), + (78, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/78', + null, null, false, 'https://example.com/users/1/posts/78', false,false,null), + (79, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/79', + null, null, false, 'https://example.com/users/1/posts/79', false,false,null), + (80, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/80', + null, 79, false, 'https://example.com/users/1/posts/80', false,false,null), + (81, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/81', + null, null, false, 'https://example.com/users/1/posts/81', false,false,null), + (82, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/82', + null, 81, false, 'https://example.com/users/1/posts/82', false,false,null), + (83, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/83', + null, null, false, 'https://example.com/users/1/posts/83', false,false,null), + (84, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/84', + null, null, false, 'https://example.com/users/1/posts/84', false,false,null), + (85, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/85', + null, null, false, 'https://example.com/users/1/posts/85', false,false,null), + (86, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/86', + null, 85, false, 'https://example.com/users/1/posts/86', false,false,null), + (87, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/87', + null, null, false, 'https://example.com/users/1/posts/87', false,false,null), + (88, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/88', + null, 87, false, 'https://example.com/users/1/posts/88', false,false,null), + (89, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/89', + null, null, false, 'https://example.com/users/1/posts/89', false,false,null), + (90, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/90', + null, null, false, 'https://example.com/users/1/posts/90', false,false,null), + (91, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/91', + null, null, false, 'https://example.com/users/1/posts/91', false,false,null), + (92, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/92', + null, 91, false, 'https://example.com/users/1/posts/92', false,false,null), + (93, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/93', + null, null, false, 'https://example.com/users/1/posts/93', false,false,null), + (94, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/94', + null, 93, false, 'https://example.com/users/1/posts/94', false,false,null), + (95, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/95', + null, null, false, 'https://example.com/users/1/posts/95', false,false,null), + (96, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/96', + null, null, false, 'https://example.com/users/1/posts/96', false,false,null), + (97, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/97', + null, null, false, 'https://example.com/users/1/posts/97', false,false,null), + (98, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/98', + null, 97, false, 'https://example.com/users/1/posts/98', false,false,null), + (99, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'FOLLOWERS', 'https://example.com/users/1/posts/99', + null, null, false, 'https://example.com/users/1/posts/99', false,false,null), + (100, 1,1,null, '

this is test

', 'this is test', current_timestamp, 'PUBLIC', 'https://example.com/users/1/posts/100', + null, 99, false, 'https://example.com/users/1/posts/100', false,false,null); \ No newline at end of file diff --git a/hideout-mastodon/src/test/resources/sql/filter/test-filter.sql b/hideout-mastodon/src/test/resources/sql/filter/test-filter.sql new file mode 100644 index 00000000..d06d6bc0 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/filter/test-filter.sql @@ -0,0 +1,4 @@ +insert into filters (id, user_id, name, context, action) +VALUES (1, 1, 'test filter', 'home', 'warn'); +insert into filter_keywords(id, filter_id, keyword, mode) +VALUES (1, 1, 'hoge', 'NONE') \ No newline at end of file diff --git a/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがfollowers投稿を取得できる.sql b/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがfollowers投稿を取得できる.sql new file mode 100644 index 00000000..dc2ab9f1 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがfollowers投稿を取得できる.sql @@ -0,0 +1,28 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (8, 'test-user8', 'example.com', 'Im test-user8.', 'THis account is test-user8.', + 'https://example.com/users/test-user8/inbox', + 'https://example.com/users/test-user8/outbox', 'https://example.com/users/test-user8', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user8#pubkey', 'https://example.com/users/test-user8/following', + 'https://example.com/users/test-user8/followers', 0, false, 0, 0, 0, null), + (9, 'test-user9', 'follower.example.com', 'Im test-user9.', 'THis account is test-user9.', + 'https://follower.example.com/users/test-user9/inbox', + 'https://follower.example.com/users/test-user9/outbox', 'https://follower.example.com/users/test-user9', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + null, 12345678, + 'https://follower.example.com/users/test-user9#pubkey', + 'https://follower.example.com/users/test-user9/following', + 'https://follower.example.com/users/test-user9/followers', 0, false, 0, 0, 0, null); + +insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request, + ignore_follow_request) +VALUES (9, 8, true, false, false, false, false); + +insert into POSTS (ID, ACTOR_ID, OVERVIEW, CONTENT, TEXT, CREATED_AT, VISIBILITY, URL, REPLY_ID, REPOST_ID, SENSITIVE, + AP_ID) +VALUES (1239, 8, null, '

test post

', 'test post', 12345680, 2, 'https://example.com/users/test-user8/posts/1239', + null, null, false, + 'https://example.com/users/test-user8/posts/1239'); diff --git a/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがpublic投稿を取得できる.sql b/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがpublic投稿を取得できる.sql new file mode 100644 index 00000000..a44861f4 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがpublic投稿を取得できる.sql @@ -0,0 +1,29 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (4, 'test-user4', 'example.com', 'Im test user4.', 'THis account is test user4.', + 'https://example.com/users/test-user4/inbox', + 'https://example.com/users/test-user4/outbox', 'https://example.com/users/test-user4', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user4#pubkey', 'https://example.com/users/test-user4/following', + 'https://example.com/users/test-user4/followers', 0, false, 0, 0, 0, null), + (5, 'test-user5', 'follower.example.com', 'Im test user5.', 'THis account is test user5.', + 'https://follower.example.com/users/test-user5/inbox', + 'https://follower.example.com/users/test-user5/outbox', 'https://follower.example.com/users/test-user5', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + null, 12345678, + 'https://follower.example.com/users/test-user5#pubkey', + 'https://follower.example.com/users/test-user5/following', + 'https://follower.example.com/users/test-user5/followers', 0, false, 0, 0, 0, null); + +insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request, + ignore_follow_request) +VALUES (5, 4, true, false, false, false, false); + +insert into POSTS (ID, "actor_id", OVERVIEW, CONTENT, TEXT, "created_at", VISIBILITY, URL, "repost_id", "reply_id", + SENSITIVE, + AP_ID) +VALUES (1237, 4, null, '

test post

', 'test post', 12345680, 0, 'https://example.com/users/test-user4/posts/1237', + null, null, false, + 'https://example.com/users/test-user4/posts/1237'); diff --git a/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがunlisted投稿を取得できる.sql b/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがunlisted投稿を取得できる.sql new file mode 100644 index 00000000..77cb3395 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/httpSignature認証でフォロワーがunlisted投稿を取得できる.sql @@ -0,0 +1,29 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (6, 'test-user6', 'example.com', 'Im test-user6.', 'THis account is test-user6.', + 'https://example.com/users/test-user6/inbox', + 'https://example.com/users/test-user6/outbox', 'https://example.com/users/test-user6', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user6#pubkey', 'https://example.com/users/test-user6/following', + 'https://example.com/users/test-user6/followers', 0, false, 0, 0, 0, null), + (7, 'test-user7', 'follower.example.com', 'Im test-user7.', 'THis account is test-user7.', + 'https://follower.example.com/users/test-user7/inbox', + 'https://follower.example.com/users/test-user7/outbox', 'https://follower.example.com/users/test-user7', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + null, 12345678, + 'https://follower.example.com/users/test-user7#pubkey', + 'https://follower.example.com/users/test-user7/following', + 'https://follower.example.com/users/test-user7/followers', 0, false, 0, 0, 0, null); + +insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request, + ignore_follow_request) +VALUES (7, 6, true, false, false, false, false); + +insert into POSTS (ID, "actor_ID", OVERVIEW, CONTENT, TEXT, "CREATED_AT", VISIBILITY, URL, "REPOST_ID", "REPLY_ID", + SENSITIVE, + AP_ID) +VALUES (1238, 6, null, '

test post

', 'test post', 12345680, 1, 'https://example.com/users/test-user6/posts/1238', + null, null, false, + 'https://example.com/users/test-user6/posts/1238'); diff --git a/hideout-mastodon/src/test/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql b/hideout-mastodon/src/test/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql new file mode 100644 index 00000000..6cc9db8c --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql @@ -0,0 +1,25 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (11, 'test-user11', 'example.com', 'Im test-user11.', 'THis account is test-user11.', + 'https://example.com/users/test-user11/inbox', + 'https://example.com/users/test-user11/outbox', 'https://example.com/users/test-user11', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user11#pubkey', 'https://example.com/users/test-user11/following', + 'https://example.com/users/test-user11/followers', 0, false, 0, 0, 0, null); + +insert into POSTS (id, actor_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive, + ap_id, + deleted) +VALUES (1242, 11, null, '

test post

', 'test post', 12345680, 0, + 'https://example.com/users/test-user11/posts/1242', null, null, false, + 'https://example.com/users/test-user11/posts/1242', false); + +insert into MEDIA (ID, NAME, URL, REMOTE_URL, THUMBNAIL_URL, TYPE, BLURHASH, MIME_TYPE, DESCRIPTION) +VALUES (1, 'test-media', 'https://example.com/media/test-media.png', null, null, 0, null, 'image/png', null), + (2, 'test-media2', 'https://example.com/media/test-media2.png', null, null, 0, null, 'image/png', null); + +insert into POSTS_MEDIA(POST_ID, MEDIA_ID) +VALUES (1242, 1), + (1242, 2); diff --git a/hideout-mastodon/src/test/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql b/hideout-mastodon/src/test/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql new file mode 100644 index 00000000..41ac73a4 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql @@ -0,0 +1,20 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (10, 'test-user10', 'example.com', 'Im test-user10.', 'THis account is test-user10.', + 'https://example.com/users/test-user10/inbox', + 'https://example.com/users/test-user10/outbox', 'https://example.com/users/test-user10', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user10#pubkey', 'https://example.com/users/test-user10/following', + 'https://example.com/users/test-user10/followers', 0, false, 0, 0, 0, null); + +insert into POSTS (id, actor_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive, + ap_id, + deleted) +VALUES (1240, 10, null, '

test post

', 'test post', 12345680, 0, + 'https://example.com/users/test-user10/posts/1240', null, null, false, + 'https://example.com/users/test-user10/posts/1240', false), + (1241, 10, null, '

test post

', 'test post', 12345680, 0, + 'https://example.com/users/test-user10/posts/1241', null, 1240, false, + 'https://example.com/users/test-user10/posts/1241', false); diff --git a/hideout-mastodon/src/test/resources/sql/note/匿名でfollowers投稿を取得しようとすると404.sql b/hideout-mastodon/src/test/resources/sql/note/匿名でfollowers投稿を取得しようとすると404.sql new file mode 100644 index 00000000..250cfb5a --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/匿名でfollowers投稿を取得しようとすると404.sql @@ -0,0 +1,17 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (3, 'test-user3', 'example.com', 'Im test user3.', 'THis account is test user3.', + 'https://example.com/users/test-user3/inbox', + 'https://example.com/users/test-user3/outbox', 'https://example.com/users/test-user3', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user3#pubkey', 'https://example.com/users/test-user3/following', + 'https://example.com/users/test-user3/followers', 0, false, 0, 0, 0, null); + +insert into POSTS (id, actor_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive, + ap_id, + deleted) +VALUES (1236, 3, null, '

test post

', 'test post', 12345680, 2, 'https://example.com/users/test-user3/posts/1236', + null, null, false, + 'https://example.com/users/test-user3/posts/1236', false) diff --git a/hideout-mastodon/src/test/resources/sql/note/匿名でpublic投稿を取得できる.sql b/hideout-mastodon/src/test/resources/sql/note/匿名でpublic投稿を取得できる.sql new file mode 100644 index 00000000..777f9244 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/匿名でpublic投稿を取得できる.sql @@ -0,0 +1,17 @@ +insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at, + key_id, following, followers, instance, locked, following_count, followers_count, posts_count, + last_post_at) +VALUES (1, 'test-user', 'example.com', 'Im test user.', 'THis account is test user.', + 'https://example.com/users/test-user/inbox', + 'https://example.com/users/test-user/outbox', 'https://example.com/users/test-user', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user#pubkey', 'https://example.com/users/test-user/following', + 'https://example.com/users/test-users/followers', 0, false, 0, 0, 0, null); + +insert into POSTS (id, actor_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive, + ap_id, + deleted) +VALUES (1234, 1, null, '

test post

', 'test post', 12345680, 0, 'https://example.com/users/test-user/posts/1234', + null, null, false, + 'https://example.com/users/test-user/posts/1234', false) diff --git a/hideout-mastodon/src/test/resources/sql/note/匿名でunlisted投稿を取得できる.sql b/hideout-mastodon/src/test/resources/sql/note/匿名でunlisted投稿を取得できる.sql new file mode 100644 index 00000000..b132734d --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/note/匿名でunlisted投稿を取得できる.sql @@ -0,0 +1,17 @@ +insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at, + key_id, following, followers, instance, locked, following_count, followers_count, posts_count, + last_post_at) +VALUES (2, 'test-user2', 'example.com', 'Im test user2.', 'THis account is test user2.', + 'https://example.com/users/test-user2/inbox', + 'https://example.com/users/test-user2/outbox', 'https://example.com/users/test-user2', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user2#pubkey', 'https://example.com/users/test-user2/following', + 'https://example.com/users/test-user2/followers', 0, false, 0, 0, 0, null); + +insert into POSTS (id, actor_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive, + ap_id, + deleted) +VALUES (1235, 2, null, '

test post

', 'test post', 12345680, 1, 'https://example.com/users/test-user2/posts/1235', + null, null, false, + 'https://example.com/users/test-user2/posts/1235', false) diff --git a/hideout-mastodon/src/test/resources/sql/notification/test-mastodon_notifications.sql b/hideout-mastodon/src/test/resources/sql/notification/test-mastodon_notifications.sql new file mode 100644 index 00000000..c97a25a7 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/notification/test-mastodon_notifications.sql @@ -0,0 +1,66 @@ +insert into mastodon_notifications (id, user_id, type, created_at, account_id, status_id, report_id, relationship_serverance_event_id) +values (1, 1, 'follow', current_timestamp, 2, null, null, null), + (2, 1, 'follow', current_timestamp, 2, null, null, null), + (3, 1, 'follow', current_timestamp, 2, null, null, null), + (4, 1, 'follow', current_timestamp, 2, null, null, null), + (5, 1, 'follow', current_timestamp, 2, null, null, null), + (6, 1, 'follow', current_timestamp, 2, null, null, null), + (7, 1, 'follow', current_timestamp, 2, null, null, null), + (8, 1, 'follow', current_timestamp, 2, null, null, null), + (9, 1, 'follow', current_timestamp, 2, null, null, null), + (10, 1, 'follow', current_timestamp, 2, null, null, null), + (11, 1, 'follow', current_timestamp, 2, null, null, null), + (12, 1, 'follow', current_timestamp, 2, null, null, null), + (13, 1, 'follow', current_timestamp, 2, null, null, null), + (14, 1, 'follow', current_timestamp, 2, null, null, null), + (15, 1, 'follow', current_timestamp, 2, null, null, null), + (16, 1, 'follow', current_timestamp, 2, null, null, null), + (17, 1, 'follow', current_timestamp, 2, null, null, null), + (18, 1, 'follow', current_timestamp, 2, null, null, null), + (19, 1, 'follow', current_timestamp, 2, null, null, null), + (20, 1, 'follow', current_timestamp, 2, null, null, null), + (21, 1, 'follow', current_timestamp, 2, null, null, null), + (22, 1, 'follow', current_timestamp, 2, null, null, null), + (23, 1, 'follow', current_timestamp, 2, null, null, null), + (24, 1, 'follow', current_timestamp, 2, null, null, null), + (25, 1, 'follow', current_timestamp, 2, null, null, null), + (26, 1, 'follow', current_timestamp, 2, null, null, null), + (27, 1, 'follow', current_timestamp, 2, null, null, null), + (28, 1, 'follow', current_timestamp, 2, null, null, null), + (29, 1, 'follow', current_timestamp, 2, null, null, null), + (30, 1, 'follow', current_timestamp, 2, null, null, null), + (31, 1, 'follow', current_timestamp, 2, null, null, null), + (32, 1, 'follow', current_timestamp, 2, null, null, null), + (33, 1, 'follow', current_timestamp, 2, null, null, null), + (34, 1, 'follow', current_timestamp, 2, null, null, null), + (35, 1, 'follow', current_timestamp, 2, null, null, null), + (36, 1, 'follow', current_timestamp, 2, null, null, null), + (37, 1, 'follow', current_timestamp, 2, null, null, null), + (38, 1, 'follow', current_timestamp, 2, null, null, null), + (39, 1, 'follow', current_timestamp, 2, null, null, null), + (40, 1, 'follow', current_timestamp, 2, null, null, null), + (41, 1, 'follow', current_timestamp, 2, null, null, null), + (42, 1, 'follow', current_timestamp, 2, null, null, null), + (43, 1, 'follow', current_timestamp, 2, null, null, null), + (44, 1, 'follow', current_timestamp, 2, null, null, null), + (45, 1, 'follow', current_timestamp, 2, null, null, null), + (46, 1, 'follow', current_timestamp, 2, null, null, null), + (47, 1, 'follow', current_timestamp, 2, null, null, null), + (48, 1, 'follow', current_timestamp, 2, null, null, null), + (49, 1, 'follow', current_timestamp, 2, null, null, null), + (50, 1, 'follow', current_timestamp, 2, null, null, null), + (51, 1, 'follow', current_timestamp, 2, null, null, null), + (52, 1, 'follow', current_timestamp, 2, null, null, null), + (53, 1, 'follow', current_timestamp, 2, null, null, null), + (54, 1, 'follow', current_timestamp, 2, null, null, null), + (55, 1, 'follow', current_timestamp, 2, null, null, null), + (56, 1, 'follow', current_timestamp, 2, null, null, null), + (57, 1, 'follow', current_timestamp, 2, null, null, null), + (58, 1, 'follow', current_timestamp, 2, null, null, null), + (59, 1, 'follow', current_timestamp, 2, null, null, null), + (60, 1, 'follow', current_timestamp, 2, null, null, null), + (61, 1, 'follow', current_timestamp, 2, null, null, null), + (62, 1, 'follow', current_timestamp, 2, null, null, null), + (63, 1, 'follow', current_timestamp, 2, null, null, null), + (64, 1, 'follow', current_timestamp, 2, null, null, null), + (65, 1, 'follow', current_timestamp, 2, null, null, null); \ No newline at end of file diff --git a/hideout-mastodon/src/test/resources/sql/notification/test-notifications.sql b/hideout-mastodon/src/test/resources/sql/notification/test-notifications.sql new file mode 100644 index 00000000..38982603 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/notification/test-notifications.sql @@ -0,0 +1,66 @@ +insert into notifications(id, type, user_id, source_actor_id, post_id, text, reaction_id, created_at) +VALUES (1, 'follow', 1, 2, null, null, null, current_timestamp), + (2, 'follow', 1, 2, null, null, null, current_timestamp), + (3, 'follow', 1, 2, null, null, null, current_timestamp), + (4, 'follow', 1, 2, null, null, null, current_timestamp), + (5, 'follow', 1, 2, null, null, null, current_timestamp), + (6, 'follow', 1, 2, null, null, null, current_timestamp), + (7, 'follow', 1, 2, null, null, null, current_timestamp), + (8, 'follow', 1, 2, null, null, null, current_timestamp), + (9, 'follow', 1, 2, null, null, null, current_timestamp), + (10, 'follow', 1, 2, null, null, null, current_timestamp), + (11, 'follow', 1, 2, null, null, null, current_timestamp), + (12, 'follow', 1, 2, null, null, null, current_timestamp), + (13, 'follow', 1, 2, null, null, null, current_timestamp), + (14, 'follow', 1, 2, null, null, null, current_timestamp), + (15, 'follow', 1, 2, null, null, null, current_timestamp), + (16, 'follow', 1, 2, null, null, null, current_timestamp), + (17, 'follow', 1, 2, null, null, null, current_timestamp), + (18, 'follow', 1, 2, null, null, null, current_timestamp), + (19, 'follow', 1, 2, null, null, null, current_timestamp), + (20, 'follow', 1, 2, null, null, null, current_timestamp), + (21, 'follow', 1, 2, null, null, null, current_timestamp), + (22, 'follow', 1, 2, null, null, null, current_timestamp), + (23, 'follow', 1, 2, null, null, null, current_timestamp), + (24, 'follow', 1, 2, null, null, null, current_timestamp), + (25, 'follow', 1, 2, null, null, null, current_timestamp), + (26, 'follow', 1, 2, null, null, null, current_timestamp), + (27, 'follow', 1, 2, null, null, null, current_timestamp), + (28, 'follow', 1, 2, null, null, null, current_timestamp), + (29, 'follow', 1, 2, null, null, null, current_timestamp), + (30, 'follow', 1, 2, null, null, null, current_timestamp), + (31, 'follow', 1, 2, null, null, null, current_timestamp), + (32, 'follow', 1, 2, null, null, null, current_timestamp), + (33, 'follow', 1, 2, null, null, null, current_timestamp), + (34, 'follow', 1, 2, null, null, null, current_timestamp), + (35, 'follow', 1, 2, null, null, null, current_timestamp), + (36, 'follow', 1, 2, null, null, null, current_timestamp), + (37, 'follow', 1, 2, null, null, null, current_timestamp), + (38, 'follow', 1, 2, null, null, null, current_timestamp), + (39, 'follow', 1, 2, null, null, null, current_timestamp), + (40, 'follow', 1, 2, null, null, null, current_timestamp), + (41, 'follow', 1, 2, null, null, null, current_timestamp), + (42, 'follow', 1, 2, null, null, null, current_timestamp), + (43, 'follow', 1, 2, null, null, null, current_timestamp), + (44, 'follow', 1, 2, null, null, null, current_timestamp), + (45, 'follow', 1, 2, null, null, null, current_timestamp), + (46, 'follow', 1, 2, null, null, null, current_timestamp), + (47, 'follow', 1, 2, null, null, null, current_timestamp), + (48, 'follow', 1, 2, null, null, null, current_timestamp), + (49, 'follow', 1, 2, null, null, null, current_timestamp), + (50, 'follow', 1, 2, null, null, null, current_timestamp), + (51, 'follow', 1, 2, null, null, null, current_timestamp), + (52, 'follow', 1, 2, null, null, null, current_timestamp), + (53, 'follow', 1, 2, null, null, null, current_timestamp), + (54, 'follow', 1, 2, null, null, null, current_timestamp), + (55, 'follow', 1, 2, null, null, null, current_timestamp), + (56, 'follow', 1, 2, null, null, null, current_timestamp), + (57, 'follow', 1, 2, null, null, null, current_timestamp), + (58, 'follow', 1, 2, null, null, null, current_timestamp), + (59, 'follow', 1, 2, null, null, null, current_timestamp), + (60, 'follow', 1, 2, null, null, null, current_timestamp), + (61, 'follow', 1, 2, null, null, null, current_timestamp), + (62, 'follow', 1, 2, null, null, null, current_timestamp), + (63, 'follow', 1, 2, null, null, null, current_timestamp), + (64, 'follow', 1, 2, null, null, null, current_timestamp), + (65, 'follow', 1, 2, null, null, null, current_timestamp); \ No newline at end of file diff --git a/hideout-mastodon/src/test/resources/sql/posts.sql b/hideout-mastodon/src/test/resources/sql/posts.sql index f8dec6b9..cf8c71bf 100644 --- a/hideout-mastodon/src/test/resources/sql/posts.sql +++ b/hideout-mastodon/src/test/resources/sql/posts.sql @@ -1,15 +1,15 @@ insert into posts (id, actor_id, instance_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id, deleted, hide, move_to) values (1, 1, 1, null, 'content', 'text', current_timestamp, 'PUBLIC', 'https://example.com', null, null, false, - 'https://example.com', false, false, null), + 'https://example.com/1', false, false, null), (2, 2, 2, null, 'content', 'text', current_timestamp, 'FOLLOWERS', 'https://example.com', null, null, false, - 'https://example.com', false, false, null), + 'https://example.com/2', false, false, null), (3, 3, 1, null, 'content', 'text', current_timestamp, 'PUBLIC', 'https://example.com', null, null, false, - 'https://example.com', false, false, null), + 'https://example.com/3', false, false, null), (4, 4, 1, null, 'content', 'text', current_timestamp, 'FOLLOWERS', 'https://example.com', null, null, false, - 'https://example.com', false, false, null), + 'https://example.com/4', false, false, null), (5, 4, 1, null, 'content', 'text', current_timestamp, 'DIRECT', 'https://example.com', null, null, false, - 'https://example.com', false, false, null); + 'https://example.com/5', false, false, null); insert into posts_visible_actors(post_id, actor_id) VALUES (5, 2); \ No newline at end of file diff --git a/hideout-mastodon/src/test/resources/sql/test-custom-emoji.sql b/hideout-mastodon/src/test/resources/sql/test-custom-emoji.sql new file mode 100644 index 00000000..83c2747a --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/test-custom-emoji.sql @@ -0,0 +1,3 @@ +insert into emojis(id, name, domain, instance_id, url, category, created_at) +VALUES (1, 'kotlin', 'example.com', null, 'https://example.com/emojis/kotlin', null, + TIMESTAMP '2024-01-08 07:51:30.036Z'); diff --git a/hideout-mastodon/src/test/resources/sql/test-post.sql b/hideout-mastodon/src/test/resources/sql/test-post.sql new file mode 100644 index 00000000..da7c5343 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/test-post.sql @@ -0,0 +1,4 @@ +insert into posts (id, actor_id, instance_id, overview, content, text, created_at, visibility, url, repost_id, reply_id, + sensitive, ap_id, deleted, hide, move_to) +VALUES (1, 1, 0, null,'

test post

', 'hello', 1234455, 0, 'https://localhost/users/1/posts/1', null, null, false, + 'https://users/1/posts/1'); diff --git a/hideout-mastodon/src/test/resources/sql/test-user.sql b/hideout-mastodon/src/test/resources/sql/test-user.sql new file mode 100644 index 00000000..728af6f5 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/test-user.sql @@ -0,0 +1,11 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (1, 'test-user', 'example.com', 'Im test user.', 'THis account is test user.', + 'https://example.com/users/test-user/inbox', + 'https://example.com/users/test-user/outbox', 'https://example.com/users/test-user', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user#pubkey', 'https://example.com/users/test-user/following', + 'https://example.com/users/test-users/followers', 0, false, 0, 0, 0, null); + diff --git a/hideout-mastodon/src/test/resources/sql/test-user2.sql b/hideout-mastodon/src/test/resources/sql/test-user2.sql new file mode 100644 index 00000000..0f736704 --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/test-user2.sql @@ -0,0 +1,10 @@ +insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, + created_at, key_id, following, followers, instance, locked, following_count, followers_count, + posts_count, last_post_at) +VALUES (2, 'test-user2', 'example.com', 'Im test user.', 'THis account is test user.', + 'https://example.com/users/test-user2/inbox', + 'https://example.com/users/test-user2/outbox', 'https://example.com/users/test-user2', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user2#pubkey', 'https://example.com/users/test-user2/following', + 'https://example.com/users/test-user2s/followers', 0, false, 0, 0, 0, null); diff --git a/hideout-mastodon/src/test/resources/sql/userdetail.sql b/hideout-mastodon/src/test/resources/sql/userdetail.sql new file mode 100644 index 00000000..c0b3ee2d --- /dev/null +++ b/hideout-mastodon/src/test/resources/sql/userdetail.sql @@ -0,0 +1,2 @@ +insert into user_details(id, actor_id, password, auto_accept_followee_follow_request, last_migration, home_timeline_id) +VALUES (1, 1, 'veeeeeeeeeeryStrongPassword', false, null, null); \ No newline at end of file From 5cc82671357fb777f3d0ad81fd9ab4f05ed8e587 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 01:08:25 +0900 Subject: [PATCH 02/30] =?UTF-8?q?test:=20MediaAPI=E3=81=AE=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=92=E5=BE=A9=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../mastodon/interfaces/api/SpringMediaApi.kt | 14 ++++++++++++++ .../src/test/kotlin/mastodon/media/MediaTest.kt | 2 +- .../src/test/resources/media/400x400.png | Bin 4 files changed, 16 insertions(+), 1 deletion(-) rename {hideout-core => hideout-mastodon}/src/test/resources/media/400x400.png (100%) diff --git a/.gitignore b/.gitignore index ecde199b..99c1c155 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ out/ /http-client.private.env.json /logs/ /hideout-mastodon/logs/ +/hideout-mastodon/files/ diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt index d5bed541..a28dafbb 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt @@ -21,9 +21,12 @@ import dev.usbharu.hideout.core.application.media.UploadMediaApplicationService import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.SpringSecurityOauth2PrincipalContextHolder import dev.usbharu.hideout.mastodon.interfaces.api.generated.MediaApi import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.MediaAttachment +import org.slf4j.LoggerFactory +import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.stereotype.Controller import org.springframework.web.multipart.MultipartFile +import org.springframework.web.server.ResponseStatusException import java.nio.file.Files @Controller @@ -37,6 +40,13 @@ class SpringMediaApi( description: String?, focus: String?, ): ResponseEntity { + + if (file.size == 0L) { + logger.warn("File is empty.") + throw ResponseStatusException(HttpStatus.BAD_REQUEST, "File is empty.") + } + + val tempFile = Files.createTempFile("hideout-tmp-file", ".tmp") Files.newOutputStream(tempFile).use { outputStream -> @@ -73,4 +83,8 @@ class SpringMediaApi( ) ) } + + companion object { + private val logger = LoggerFactory.getLogger(SpringMediaApi::class.java) + } } diff --git a/hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt index 13d2bd55..7e4755d9 100644 --- a/hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt +++ b/hideout-mastodon/src/test/kotlin/mastodon/media/MediaTest.kt @@ -40,7 +40,7 @@ import org.springframework.web.context.WebApplicationContext @SpringBootTest(classes = [SpringApplication::class]) @AutoConfigureMockMvc @Transactional -@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +@Sql("/sql/actors.sql","/sql/userdetail.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) class MediaTest { @Autowired diff --git a/hideout-core/src/test/resources/media/400x400.png b/hideout-mastodon/src/test/resources/media/400x400.png similarity index 100% rename from hideout-core/src/test/resources/media/400x400.png rename to hideout-mastodon/src/test/resources/media/400x400.png From cb52248b1c24619c1a7e2cfb95374afa18dabb37 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 01:43:00 +0900 Subject: [PATCH 03/30] =?UTF-8?q?test:=20Filter=20API=E3=81=AE=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=92=E4=B8=80=E9=83=A8=E5=BE=A9=E6=B4=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/PermissionDeniedException.kt | 3 +++ .../filter/UserGetFilterApplicationService.kt | 3 ++- .../DeleteFilterV1ApplicationService.kt | 2 +- .../filter/GetFilterV1ApplicationService.kt | 2 +- .../interfaces/api/SpringFilterApi.kt | 5 +++-- .../test/kotlin/mastodon/filter/FilterTest.kt | 19 ++++++++++--------- .../test/kotlin/mastodon/status/StatusTest.kt | 2 +- .../mastodon/timelines/TimelineApiTest.kt | 2 +- .../test/resources/sql/filter/test-filter.sql | 2 +- 9 files changed, 23 insertions(+), 17 deletions(-) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt index e59663be..53613621 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/exception/PermissionDeniedException.kt @@ -16,7 +16,10 @@ package dev.usbharu.hideout.core.application.exception +import dev.usbharu.hideout.core.domain.model.support.principal.Principal + class PermissionDeniedException : RuntimeException { + constructor(principal: Principal) : super("Permission Denied $principal") constructor() : super() constructor(message: String?) : super(message) constructor(message: String?, cause: Throwable?) : super(message, cause) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/filter/UserGetFilterApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/filter/UserGetFilterApplicationService.kt index e97209fc..b6682c64 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/filter/UserGetFilterApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/filter/UserGetFilterApplicationService.kt @@ -34,7 +34,8 @@ class UserGetFilterApplicationService(private val filterRepository: FilterReposi ) { override suspend fun internalExecute(command: GetFilter, principal: LocalUser): Filter { val filter = - filterRepository.findByFilterId(FilterId(command.filterId)) ?: throw IllegalArgumentException("Not Found") + filterRepository.findByFilterId(FilterId(command.filterId)) + ?: throw IllegalArgumentException("Filter ${command.filterId} not found.") if (filter.userDetailId != principal.userDetailId) { throw PermissionDeniedException() } diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/DeleteFilterV1ApplicationService.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/DeleteFilterV1ApplicationService.kt index 4961d383..53ed42ff 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/DeleteFilterV1ApplicationService.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/DeleteFilterV1ApplicationService.kt @@ -33,7 +33,7 @@ class DeleteFilterV1ApplicationService(private val filterRepository: FilterRepos ) { override suspend fun internalExecute(command: DeleteFilterV1, principal: LocalUser) { val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId)) - ?: throw IllegalArgumentException("Filter ${command.filterKeywordId} not found") + ?: throw IllegalArgumentException("Filter ${command.filterKeywordId} by KeywordId not found") if (principal.userDetailId != filter.userDetailId) { throw PermissionDeniedException() } diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/GetFilterV1ApplicationService.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/GetFilterV1ApplicationService.kt index 6f485361..25e7f658 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/GetFilterV1ApplicationService.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/application/filter/GetFilterV1ApplicationService.kt @@ -39,7 +39,7 @@ class GetFilterV1ApplicationService(private val filterRepository: FilterReposito ?: throw IllegalArgumentException("Filter ${command.filterKeywordId} not found") if (filter.userDetailId != principal.userDetailId) { - throw PermissionDeniedException() + throw PermissionDeniedException(principal) } val filterKeyword = filter.filterKeywords.find { it.id.id == command.filterKeywordId } diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringFilterApi.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringFilterApi.kt index 1734be87..8e92209e 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringFilterApi.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringFilterApi.kt @@ -84,6 +84,7 @@ class SpringFilterApi( account -> FilterContext.ACCOUNT } }.toSet() + val principal = principalContextHolder.getPrincipal() val filter = userRegisterFilterApplicationService.execute( RegisterFilter( v1FilterPostRequest.phrase, @@ -91,12 +92,12 @@ class SpringFilterApi( FilterAction.WARN, setOf(RegisterFilterKeyword(v1FilterPostRequest.phrase, filterMode)) ), - principalContextHolder.getPrincipal() + principal ) return ResponseEntity.ok( getFilterV1ApplicationService.execute( GetFilterV1(filter.filterKeywords.first().id), - principalContextHolder.getPrincipal() + principal ) ) } diff --git a/hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt index 73615a07..8052c258 100644 --- a/hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt +++ b/hideout-mastodon/src/test/kotlin/mastodon/filter/FilterTest.kt @@ -418,7 +418,7 @@ class FilterTest { ) } .asyncDispatch() - .andExpect { status { isOk() } } + .andExpect { status { isNotFound() } } } @Test @@ -431,7 +431,7 @@ class FilterTest { ) } .asyncDispatch() - .andExpect { status { isOk() } } + .andExpect { status { isNotFound() } } } @Test @@ -456,7 +456,7 @@ class FilterTest { ) } .asyncDispatch() - .andExpect { status { isOk() } } + .andExpect { status { isNotFound() } } } @Test @@ -469,7 +469,7 @@ class FilterTest { ) } .asyncDispatch() - .andExpect { status { isOk() } } + .andExpect { status { isNotFound() } } } @Test @@ -494,7 +494,7 @@ class FilterTest { ) } .asyncDispatch() - .andExpect { status { isOk() } } + .andExpect { status { isNotFound() } } } @Test @@ -507,7 +507,7 @@ class FilterTest { ) } .asyncDispatch() - .andExpect { status { isOk() } } + .andExpect { status { isNotFound() } } } @Test @@ -664,6 +664,7 @@ class FilterTest { } @Test + @Sql("/sql/filter/test-filter.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) fun `apiV1FiltersIdDelete writeで削除できる`() { mockMvc .delete("/api/v1/filters/1") { @@ -676,6 +677,7 @@ class FilterTest { } @Test + @Sql("/sql/filter/test-filter.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) fun `apiV1FiltersIdDelete write_filtersで削除できる`() { mockMvc .delete("/api/v1/filters/1") { @@ -692,11 +694,10 @@ class FilterTest { mockMvc .delete("/api/v1/filters/1") { with( - jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_write")) + jwt().jwt { it.claim("uid", "1") }.authorities(SimpleGrantedAuthority("SCOPE_read")) ) } - .asyncDispatch() - .andExpect { status { isOk() } } + .andExpect { status { isForbidden() } } } companion object { diff --git a/hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt index 790c3cc6..35a4a8a6 100644 --- a/hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt +++ b/hideout-mastodon/src/test/kotlin/mastodon/status/StatusTest.kt @@ -49,7 +49,7 @@ import org.springframework.web.context.WebApplicationContext @SpringBootTest(classes = [SpringApplication::class]) @AutoConfigureMockMvc @Transactional -@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +@Sql("/sql/actors.sql", "/sql/userdetail.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) @Sql("/sql/posts.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) @Sql("/sql/test-custom-emoji.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) class StatusTest { diff --git a/hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt b/hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt index 4d20bcfb..3f6bf40a 100644 --- a/hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt +++ b/hideout-mastodon/src/test/kotlin/mastodon/timelines/TimelineApiTest.kt @@ -37,7 +37,7 @@ import org.springframework.web.context.WebApplicationContext @SpringBootTest(classes = [SpringApplication::class]) @Transactional -@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) +@Sql("/sql/actors.sql", "/sql/userdetail.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_CLASS) class TimelineApiTest { @Autowired private lateinit var context: WebApplicationContext diff --git a/hideout-mastodon/src/test/resources/sql/filter/test-filter.sql b/hideout-mastodon/src/test/resources/sql/filter/test-filter.sql index d06d6bc0..8eab045a 100644 --- a/hideout-mastodon/src/test/resources/sql/filter/test-filter.sql +++ b/hideout-mastodon/src/test/resources/sql/filter/test-filter.sql @@ -1,4 +1,4 @@ insert into filters (id, user_id, name, context, action) -VALUES (1, 1, 'test filter', 'home', 'warn'); +VALUES (1, 1, 'test filter', 'HOME', 'WARN'); insert into filter_keywords(id, filter_id, keyword, mode) VALUES (1, 1, 'hoge', 'NONE') \ No newline at end of file From f83d47e8779e89748af92f61c66651c3305815fa Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 22:34:24 +0900 Subject: [PATCH 04/30] =?UTF-8?q?chore:=20CI=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hideout-core-pull-request-merge-check.yml | 163 ++++++++++++++++++ hideout-core/build.gradle.kts | 8 +- 2 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/hideout-core-pull-request-merge-check.yml diff --git a/.github/workflows/hideout-core-pull-request-merge-check.yml b/.github/workflows/hideout-core-pull-request-merge-check.yml new file mode 100644 index 00000000..ecdbd654 --- /dev/null +++ b/.github/workflows/hideout-core-pull-request-merge-check.yml @@ -0,0 +1,163 @@ +name: hideout-core-pull-request-merge-check.yml +on: + pull_request: + branches: + - "develop" + types: + - opened + - reopened + - synchronize + - ready_for_review + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + change: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + outputs: + core: ${{ steps.filter.outputs.core }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Check Changes + uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + core: + - 'hideout-core/**' + - 'libs.versions.toml' + ap: + - 'hideout-activitypub/**' + - 'libs.versions.toml' + mastodon: + - 'hideout-mastodon/**' + - 'libs.versions.toml' + owl: + - 'owl/**' + - 'libs.versions.toml' + + hideout-core-setup: + needs: + - change + if: github.event.pull_request.draft == false && needs.change.outputs.core == true + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Gradle Wrapper Validation + uses: gradle/actions/wrapper-validation@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Build + run: ./gradlew classes --no-daemon + + hideout-core-unit-test: + needs: + - hideout-core-setup + - change + if: github.event.pull_request.draft == false && needs.change.outputs.core == true + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Unit Test + run: ./hideout-core/gradlew :hideout-core:koverXmlReport + + - name: JUnit Test Report + uses: mikepenz/action-junit-report@v4 + with: + report_paths: '**/TEST-*.xml' + check_name: 'hideout-core JUnit Test Report' + + - name: Upload Coverage Report + uses: actions/upload-artifact@v4 + with: + name: 'hideout-core.xml' + path: 'hideout-core/build/reports/kover/hideout-core.xml' + + coverage: + needs: + - change + - hideout-core-unit-test + runs-on: ubuntu-latest + steps: + - name: Download Coverage Report + uses: actions/download-artifact@v4 + with: + name: 'hideout-core.xml' + path: 'hideout-core/build/reports/kover/hideout-core.xml' + - name: Report Coverage + uses: madrapps/jacoco-report@v1.7.0 + with: + paths: | + ${{ github.workspace }}/hideout-core/build/reports/kover/**.xml + token: ${{ secrets.GITHUB_TOKEN }} + title: Code Coverage + update-comment: true + min-coverage-overall: 50 + min-coverage-changed-files: 80 + + lint: + needs: + - change + - hideout-core-setup + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + token: ${{ secrets.PAT }} + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Lint + run: ./gradlew :hideout-core:detektMain :hideout-mastodon:detektMain + + - name: Auto Commit + if: ${{ always() }} + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "style: fix lint (CI)" \ No newline at end of file diff --git a/hideout-core/build.gradle.kts b/hideout-core/build.gradle.kts index a9247b41..9be112b5 100644 --- a/hideout-core/build.gradle.kts +++ b/hideout-core/build.gradle.kts @@ -211,12 +211,17 @@ kover { reports { verify { rule { - bound{ + bound { minValue = 50 coverageUnits = CoverageUnit.INSTRUCTION } } } + total { + xml { + xmlFile = file("$buildDir/reports/kover/hideout-core.xml") + } + } filters { excludes { annotatedBy("org.springframework.context.annotation.Configuration") @@ -229,6 +234,7 @@ kover { packages("org.jetbrains") } } + } } From f7e151b575e718d7e351bfddff43d7f241aafa22 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 22:37:44 +0900 Subject: [PATCH 05/30] =?UTF-8?q?chore:=20CI=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/hideout-core-pull-request-merge-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/hideout-core-pull-request-merge-check.yml b/.github/workflows/hideout-core-pull-request-merge-check.yml index ecdbd654..9b58425a 100644 --- a/.github/workflows/hideout-core-pull-request-merge-check.yml +++ b/.github/workflows/hideout-core-pull-request-merge-check.yml @@ -46,7 +46,7 @@ jobs: hideout-core-setup: needs: - change - if: github.event.pull_request.draft == false && needs.change.outputs.core == true + if: github.event.pull_request.draft == false && needs.change.outputs.core == 'true' runs-on: ubuntu-latest steps: - name: Checkout @@ -76,7 +76,7 @@ jobs: needs: - hideout-core-setup - change - if: github.event.pull_request.draft == false && needs.change.outputs.core == true + if: github.event.pull_request.draft == false && needs.change.outputs.core == 'true' runs-on: ubuntu-latest steps: - name: Checkout From 572ceacc676edbb877e1781bd4908d13da5248ee Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 13:40:48 +0000 Subject: [PATCH 06/30] style: fix lint (CI) --- .../usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt index a28dafbb..3834f11e 100644 --- a/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt +++ b/hideout-mastodon/src/main/kotlin/dev/usbharu/hideout/mastodon/interfaces/api/SpringMediaApi.kt @@ -40,13 +40,11 @@ class SpringMediaApi( description: String?, focus: String?, ): ResponseEntity { - if (file.size == 0L) { logger.warn("File is empty.") throw ResponseStatusException(HttpStatus.BAD_REQUEST, "File is empty.") } - val tempFile = Files.createTempFile("hideout-tmp-file", ".tmp") Files.newOutputStream(tempFile).use { outputStream -> From 26e06794356a82703d10bd68f285d867fff7bab4 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 22:43:47 +0900 Subject: [PATCH 07/30] =?UTF-8?q?chore:=20Java=E3=81=AE=E3=83=90=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=92=E6=8C=87=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/hideout-core-pull-request-merge-check.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/hideout-core-pull-request-merge-check.yml b/.github/workflows/hideout-core-pull-request-merge-check.yml index 9b58425a..921ab8d7 100644 --- a/.github/workflows/hideout-core-pull-request-merge-check.yml +++ b/.github/workflows/hideout-core-pull-request-merge-check.yml @@ -84,6 +84,12 @@ jobs: with: token: ${{ secrets.PAT }} + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 with: From a4cfbe81a1032c4dd74667f4c55caef5cfead707 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 22:51:46 +0900 Subject: [PATCH 08/30] =?UTF-8?q?chore:=20=E3=82=AB=E3=83=90=E3=83=AC?= =?UTF-8?q?=E3=83=83=E3=82=B8=E3=83=AC=E3=83=9D=E3=83=BC=E3=83=88=E3=81=AE?= =?UTF-8?q?=E9=9B=86=E8=A8=88=E5=A0=B4=E6=89=80=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hideout-core-pull-request-merge-check.yml | 169 ------------------ .../workflows/pull-request-merge-check.yml | 108 +++++++---- 2 files changed, 73 insertions(+), 204 deletions(-) delete mode 100644 .github/workflows/hideout-core-pull-request-merge-check.yml diff --git a/.github/workflows/hideout-core-pull-request-merge-check.yml b/.github/workflows/hideout-core-pull-request-merge-check.yml deleted file mode 100644 index 921ab8d7..00000000 --- a/.github/workflows/hideout-core-pull-request-merge-check.yml +++ /dev/null @@ -1,169 +0,0 @@ -name: hideout-core-pull-request-merge-check.yml -on: - pull_request: - branches: - - "develop" - types: - - opened - - reopened - - synchronize - - ready_for_review - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - change: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - outputs: - core: ${{ steps.filter.outputs.core }} - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - token: ${{ secrets.PAT }} - - - name: Check Changes - uses: dorny/paths-filter@v2 - id: filter - with: - filters: | - core: - - 'hideout-core/**' - - 'libs.versions.toml' - ap: - - 'hideout-activitypub/**' - - 'libs.versions.toml' - mastodon: - - 'hideout-mastodon/**' - - 'libs.versions.toml' - owl: - - 'owl/**' - - 'libs.versions.toml' - - hideout-core-setup: - needs: - - change - if: github.event.pull_request.draft == false && needs.change.outputs.core == 'true' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - token: ${{ secrets.PAT }} - - - name: Gradle Wrapper Validation - uses: gradle/actions/wrapper-validation@v4 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - with: - cache-read-only: false - gradle-home-cache-cleanup: true - - - name: Build - run: ./gradlew classes --no-daemon - - hideout-core-unit-test: - needs: - - hideout-core-setup - - change - if: github.event.pull_request.draft == false && needs.change.outputs.core == 'true' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - token: ${{ secrets.PAT }} - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - with: - cache-read-only: false - gradle-home-cache-cleanup: true - - - name: Unit Test - run: ./hideout-core/gradlew :hideout-core:koverXmlReport - - - name: JUnit Test Report - uses: mikepenz/action-junit-report@v4 - with: - report_paths: '**/TEST-*.xml' - check_name: 'hideout-core JUnit Test Report' - - - name: Upload Coverage Report - uses: actions/upload-artifact@v4 - with: - name: 'hideout-core.xml' - path: 'hideout-core/build/reports/kover/hideout-core.xml' - - coverage: - needs: - - change - - hideout-core-unit-test - runs-on: ubuntu-latest - steps: - - name: Download Coverage Report - uses: actions/download-artifact@v4 - with: - name: 'hideout-core.xml' - path: 'hideout-core/build/reports/kover/hideout-core.xml' - - name: Report Coverage - uses: madrapps/jacoco-report@v1.7.0 - with: - paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/**.xml - token: ${{ secrets.GITHUB_TOKEN }} - title: Code Coverage - update-comment: true - min-coverage-overall: 50 - min-coverage-changed-files: 80 - - lint: - needs: - - change - - hideout-core-setup - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - ref: ${{ github.head_ref }} - token: ${{ secrets.PAT }} - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - with: - cache-read-only: false - gradle-home-cache-cleanup: true - - - name: Lint - run: ./gradlew :hideout-core:detektMain :hideout-mastodon:detektMain - - - name: Auto Commit - if: ${{ always() }} - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: "style: fix lint (CI)" \ No newline at end of file diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index c100e253..b3ecb96e 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -1,31 +1,53 @@ -name: PullRequest Merge Check - +name: pull-request-merge-check.yml on: pull_request: - paths-ignore: - - 'owl/**' branches: - "develop" types: - - opened # default - - reopened # default - - synchronize # default - - ready_for_review # 必要 + - opened + - reopened + - synchronize + - ready_for_review + concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true -permissions: - contents: read - checks: write - id-token: write - pull-requests: write - jobs: - setup: - name: Setup + change: if: github.event.pull_request.draft == false runs-on: ubuntu-latest + outputs: + core: ${{ steps.filter.outputs.core }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Check Changes + uses: dorny/paths-filter@v2 + id: filter + with: + filters: | + core: + - 'hideout-core/**' + - 'libs.versions.toml' + ap: + - 'hideout-activitypub/**' + - 'libs.versions.toml' + mastodon: + - 'hideout-mastodon/**' + - 'libs.versions.toml' + owl: + - 'owl/**' + - 'libs.versions.toml' + + hideout-core-setup: + needs: + - change + if: github.event.pull_request.draft == false && needs.change.outputs.core == 'true' + runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 @@ -50,9 +72,11 @@ jobs: - name: Build run: ./gradlew classes --no-daemon - unit-test: - name: Unit Test - needs: [ setup ] + hideout-core-unit-test: + needs: + - hideout-core-setup + - change + if: github.event.pull_request.draft == false && needs.change.outputs.core == 'true' runs-on: ubuntu-latest steps: - name: Checkout @@ -75,30 +99,44 @@ jobs: - name: Unit Test run: ./hideout-core/gradlew :hideout-core:koverXmlReport - - name: Add coverage report to PR - if: always() - id: kover + - name: JUnit Test Report + uses: mikepenz/action-junit-report@v4 + with: + report_paths: '**/TEST-*.xml' + check_name: 'hideout-core JUnit Test Report' + + - name: Upload Coverage Report + uses: actions/upload-artifact@v4 + with: + name: 'hideout-core.xml' + path: 'hideout-core/build/reports/kover/hideout-core.xml' + + coverage: + needs: + - change + - hideout-core-unit-test + runs-on: ubuntu-latest + steps: + - name: Download Coverage Report + uses: actions/download-artifact@v4 + with: + name: 'hideout-core.xml' + path: 'hideout-core/build/reports/kover/hideout-core.xml' + - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/report.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage update-comment: true min-coverage-overall: 50 min-coverage-changed-files: 80 - - name: JUnit Test Report - uses: mikepenz/action-junit-report@v4 - with: - report_paths: '**/TEST-*.xml' - - - name: Verify Coverage - run: ./hideout-core/gradlew :hideout-core:koverVerify - lint: - name: Lint - needs: [ setup ] + needs: + - change + - hideout-core-setup runs-on: ubuntu-latest permissions: contents: write @@ -107,7 +145,7 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} - token: '${{ secrets.PAT }}' + token: ${{ secrets.PAT }} - name: Set up JDK 21 uses: actions/setup-java@v4 @@ -121,7 +159,7 @@ jobs: cache-read-only: false gradle-home-cache-cleanup: true - - name: Build with Gradle + - name: Lint run: ./gradlew :hideout-core:detektMain :hideout-mastodon:detektMain - name: Auto Commit From bd74ca1e0fc09d0997e2a4bd756db3f4b9558b01 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 23:02:18 +0900 Subject: [PATCH 09/30] =?UTF-8?q?chore:=20=E3=82=AB=E3=83=90=E3=83=AC?= =?UTF-8?q?=E3=83=83=E3=82=B8=E3=83=AC=E3=83=9D=E3=83=BC=E3=83=88=E3=81=AE?= =?UTF-8?q?=E9=9B=86=E8=A8=88=E5=A0=B4=E6=89=80=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index b3ecb96e..27190b24 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -122,6 +122,7 @@ jobs: with: name: 'hideout-core.xml' path: 'hideout-core/build/reports/kover/hideout-core.xml' + - run: echo ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: From e6573ccbb31e4540e58e1f6a740d45e4295043c4 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 23:12:50 +0900 Subject: [PATCH 10/30] =?UTF-8?q?chore:=20=E3=82=AB=E3=83=90=E3=83=AC?= =?UTF-8?q?=E3=83=83=E3=82=B8=E3=83=AC=E3=83=9D=E3=83=BC=E3=83=88=E3=81=AE?= =?UTF-8?q?=E9=9B=86=E8=A8=88=E5=A0=B4=E6=89=80=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 27190b24..c834735e 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -121,8 +121,7 @@ jobs: uses: actions/download-artifact@v4 with: name: 'hideout-core.xml' - path: 'hideout-core/build/reports/kover/hideout-core.xml' - - run: echo ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml + path: 'hideout-core/build/reports/kover/' - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: From 375113f384e40470a64b1176446af461d2b80b06 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 23:17:56 +0900 Subject: [PATCH 11/30] =?UTF-8?q?chore:=20=E6=A8=A9=E9=99=90=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index c834735e..f751ea1c 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -13,6 +13,12 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + checks: write + id-token: write + pull-requests: write + jobs: change: if: github.event.pull_request.draft == false From 5456413e42c5c5aa6d02ef23e4fd208c58949f67 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 23:39:12 +0900 Subject: [PATCH 12/30] =?UTF-8?q?chore:=20mastodon=E3=81=A7=E3=82=82?= =?UTF-8?q?=E3=82=AB=E3=83=90=E3=83=AC=E3=83=83=E3=82=B8=E7=8E=87=E3=82=92?= =?UTF-8?q?=E8=A8=88=E6=B8=AC=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflows/pull-request-merge-check.yml | 76 ++++++++++++++++++- hideout-mastodon/build.gradle.kts | 48 ++++++++++++ 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index f751ea1c..701df932 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -76,7 +76,36 @@ jobs: gradle-home-cache-cleanup: true - name: Build - run: ./gradlew classes --no-daemon + run: ./gradlew :hideout-core:classes --no-daemon + + hideout-mastodon-setup: + needs: + - change + if: github.event.pull_request.draft == false && needs.change.outputs.mastodon == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Gradle Wrapper Validation + uses: gradle/actions/wrapper-validation@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Build + run: ./gradlew :hideout-mastodon:classes --no-daemon hideout-core-unit-test: needs: @@ -117,22 +146,62 @@ jobs: name: 'hideout-core.xml' path: 'hideout-core/build/reports/kover/hideout-core.xml' + + hideout-mastodon-unit-test: + needs: + - hideout-mastodon-setup + - change + if: github.event.pull_request.draft == false && needs.change.outputs.mastodon == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Unit Test + run: ./hideout-mastodon/gradlew :hideout-mastodon:koverXmlReport + + - name: JUnit Test Report + uses: mikepenz/action-junit-report@v4 + with: + report_paths: '**/TEST-*.xml' + check_name: 'hideout-core JUnit Test Report' + + - name: Upload Coverage Report + uses: actions/upload-artifact@v4 + with: + name: 'hideout-core.xml' + path: 'hideout-core/build/reports/kover/hideout-mastodon.xml' + coverage: needs: - change - hideout-core-unit-test + - hideout-mastodon-unit-test runs-on: ubuntu-latest steps: - name: Download Coverage Report uses: actions/download-artifact@v4 with: - name: 'hideout-core.xml' path: 'hideout-core/build/reports/kover/' - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/**.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage update-comment: true @@ -143,6 +212,7 @@ jobs: needs: - change - hideout-core-setup + - hideout-mastodon-setup runs-on: ubuntu-latest permissions: contents: write diff --git a/hideout-mastodon/build.gradle.kts b/hideout-mastodon/build.gradle.kts index 12ad6ee8..38cd2c58 100644 --- a/hideout-mastodon/build.gradle.kts +++ b/hideout-mastodon/build.gradle.kts @@ -1,3 +1,4 @@ +import kotlinx.kover.gradle.plugin.dsl.CoverageUnit import org.openapitools.generator.gradle.plugin.tasks.GenerateTask plugins { @@ -6,6 +7,7 @@ plugins { alias(libs.plugins.spring.boot) alias(libs.plugins.kotlin.spring) alias(libs.plugins.detekt) + alias(libs.plugins.kover) } @@ -131,6 +133,52 @@ configurations.matching { it.name == "detekt" }.all { } } +project.gradle.taskGraph.whenReady { + if (this.hasTask(":koverGenerateArtifact")) { + val task = this.allTasks.find { it.name == "test" } + val verificationTask = task as VerificationTask + verificationTask.ignoreFailures = true + } +} + +kover { + currentProject { + sources { + + + } + } + + reports { + verify { + rule { + bound { + minValue = 50 + coverageUnits = CoverageUnit.INSTRUCTION + } + } + } + total { + xml { + xmlFile = file("$buildDir/reports/kover/hideout-core.xml") + } + } + filters { + excludes { + annotatedBy("org.springframework.context.annotation.Configuration") + annotatedBy("org.springframework.boot.context.properties.ConfigurationProperties") + packages( + "dev.usbharu.hideout.controller.mastodon.generated", + "dev.usbharu.hideout.domain.mastodon.model.generated" + ) + packages("org.springframework") + packages("org.jetbrains") + } + } + + } +} + tasks.withType { exclude("**/generated/**") doFirst { From af70c18b7ae687afd2c10920d9d3a33f9e0c793d Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 23:42:34 +0900 Subject: [PATCH 13/30] =?UTF-8?q?chore:=20output=E3=81=AE=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=82=92=E9=96=93=E9=81=95=E3=81=88=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=9F=E3=81=AE=E3=81=A7=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 701df932..1c1f54da 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -25,6 +25,7 @@ jobs: runs-on: ubuntu-latest outputs: core: ${{ steps.filter.outputs.core }} + mastodon: ${{ steps.filter.outputs.mastodon }} steps: - name: Checkout uses: actions/checkout@v4 From 6ffd675f35f2752fa394bbfb6d2908ee532b5ef0 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 23:46:39 +0900 Subject: [PATCH 14/30] =?UTF-8?q?chore:=20gradlew=E3=81=AE=E3=83=91?= =?UTF-8?q?=E3=83=BC=E3=83=9F=E3=83=83=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92?= =?UTF-8?q?=E8=A8=AD=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hideout-mastodon/gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 hideout-mastodon/gradlew diff --git a/hideout-mastodon/gradlew b/hideout-mastodon/gradlew old mode 100644 new mode 100755 From ee665eddb3927b2d797dae0fe8e58be173d1be36 Mon Sep 17 00:00:00 2001 From: usbharu Date: Mon, 16 Sep 2024 23:56:38 +0900 Subject: [PATCH 15/30] =?UTF-8?q?chore:=20=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=89=E5=90=8D=E3=82=92=E9=96=93=E9=81=95?= =?UTF-8?q?=E3=81=88=E3=81=A6=E3=81=84=E3=81=9F=E3=81=AE=E3=81=A7=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 1c1f54da..d56e6e29 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -179,12 +179,12 @@ jobs: uses: mikepenz/action-junit-report@v4 with: report_paths: '**/TEST-*.xml' - check_name: 'hideout-core JUnit Test Report' + check_name: 'hideout-mastodon JUnit Test Report' - name: Upload Coverage Report uses: actions/upload-artifact@v4 with: - name: 'hideout-core.xml' + name: 'hideout-mastodon.xml' path: 'hideout-core/build/reports/kover/hideout-mastodon.xml' coverage: From e36c7d6fb945ba537884d5919d5d03d22187bb28 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 00:04:14 +0900 Subject: [PATCH 16/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 3 ++- hideout-mastodon/build.gradle.kts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index d56e6e29..c83c9a5a 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -202,7 +202,8 @@ jobs: uses: madrapps/jacoco-report@v1.7.0 with: paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/**.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage update-comment: true diff --git a/hideout-mastodon/build.gradle.kts b/hideout-mastodon/build.gradle.kts index 38cd2c58..593eac69 100644 --- a/hideout-mastodon/build.gradle.kts +++ b/hideout-mastodon/build.gradle.kts @@ -160,7 +160,7 @@ kover { } total { xml { - xmlFile = file("$buildDir/reports/kover/hideout-core.xml") + xmlFile = file("$buildDir/reports/kover/hideout-mastodon.xml") } } filters { From 95ac60bfec3f6a4e91834baacf35d2a1d50b9e06 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 00:12:37 +0900 Subject: [PATCH 17/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index c83c9a5a..860df1ff 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -185,7 +185,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: 'hideout-mastodon.xml' - path: 'hideout-core/build/reports/kover/hideout-mastodon.xml' + path: 'hideout-mastodon/build/reports/kover/hideout-mastodon.xml' coverage: needs: From 031ba79450fb07ba4c4d976b2f9596e0a42f72b6 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 00:16:52 +0900 Subject: [PATCH 18/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 860df1ff..1be1b0ce 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -202,7 +202,7 @@ jobs: uses: madrapps/jacoco-report@v1.7.0 with: paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml, ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage From 4eb81271051e93f13b1de76888b88e39faaecef0 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 00:26:33 +0900 Subject: [PATCH 19/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 1be1b0ce..31b9c75e 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -181,6 +181,8 @@ jobs: report_paths: '**/TEST-*.xml' check_name: 'hideout-mastodon JUnit Test Report' + - run: cd ./hideout-core/build/reports/kover || ls -lah + - name: Upload Coverage Report uses: actions/upload-artifact@v4 with: From 579ac443722fe27eb8fcb6b86edc4acdf99104d0 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 00:33:36 +0900 Subject: [PATCH 20/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 31b9c75e..3bf9ab15 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -181,8 +181,6 @@ jobs: report_paths: '**/TEST-*.xml' check_name: 'hideout-mastodon JUnit Test Report' - - run: cd ./hideout-core/build/reports/kover || ls -lah - - name: Upload Coverage Report uses: actions/upload-artifact@v4 with: @@ -200,6 +198,10 @@ jobs: uses: actions/download-artifact@v4 with: path: 'hideout-core/build/reports/kover/' + + + - run: cd ./hideout-core/build/reports/kover || ls -lah + - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: From bb6e03461ad9a1331ae5cd844ec124435a8e1e30 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 00:49:27 +0900 Subject: [PATCH 21/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 3bf9ab15..96134aad 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -197,10 +197,10 @@ jobs: - name: Download Coverage Report uses: actions/download-artifact@v4 with: - path: 'hideout-core/build/reports/kover/' + path: 'hideout-core/build/reports/kover' - - run: cd ./hideout-core/build/reports/kover || ls -lah + - run: ls -R hideout-core/build/reports/kover - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 From 23fb7f9f2a7c954d1170e3249360a65ef741090b Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 01:16:07 +0900 Subject: [PATCH 22/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 96134aad..28ad9803 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -206,8 +206,7 @@ jobs: uses: madrapps/jacoco-report@v1.7.0 with: paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml, - ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/**/**.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage update-comment: true From f622d23a7b000cf3fc4202e431d657d4bde0e9c2 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 01:24:04 +0900 Subject: [PATCH 23/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 28ad9803..477995c6 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -206,7 +206,8 @@ jobs: uses: madrapps/jacoco-report@v1.7.0 with: paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/**/**.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core/hideout-core.xml, + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon/hideout-mastodon.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage update-comment: true From 4a9b192e84ebd8c8f37a298681e17c1484c98d7d Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 01:32:46 +0900 Subject: [PATCH 24/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 477995c6..e01b1658 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -202,6 +202,9 @@ jobs: - run: ls -R hideout-core/build/reports/kover + - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core/hideout-core.xml + - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon/hideout-mastodon.xml + - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: From 455c7aea3fed47079bbc91ef589c8891eb932d59 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 01:37:19 +0900 Subject: [PATCH 25/30] =?UTF-8?q?chore:=E3=80=80=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index e01b1658..f9860945 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -202,15 +202,15 @@ jobs: - run: ls -R hideout-core/build/reports/kover - - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core/hideout-core.xml - - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon/hideout-mastodon.xml + - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml/hideout-core.xml + - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml/hideout-mastodon.xml - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: paths: | - ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core/hideout-core.xml, - ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon/hideout-mastodon.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml/hideout-core.xml, + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml/hideout-mastodon.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage update-comment: true From ee7bdf66eb358689ca909848548432a977174328 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 01:47:34 +0900 Subject: [PATCH 26/30] =?UTF-8?q?chore:=E3=80=80=E3=82=AB=E3=83=90?= =?UTF-8?q?=E3=83=AC=E3=83=83=E3=82=B8=E3=83=AC=E3=83=9D=E3=83=BC=E3=83=88?= =?UTF-8?q?=E5=90=8D=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hideout-core/build.gradle.kts | 1 + hideout-mastodon/build.gradle.kts | 1 + 2 files changed, 2 insertions(+) diff --git a/hideout-core/build.gradle.kts b/hideout-core/build.gradle.kts index 9be112b5..b488437b 100644 --- a/hideout-core/build.gradle.kts +++ b/hideout-core/build.gradle.kts @@ -219,6 +219,7 @@ kover { } total { xml { + title = "Hideout Core" xmlFile = file("$buildDir/reports/kover/hideout-core.xml") } } diff --git a/hideout-mastodon/build.gradle.kts b/hideout-mastodon/build.gradle.kts index 593eac69..37094786 100644 --- a/hideout-mastodon/build.gradle.kts +++ b/hideout-mastodon/build.gradle.kts @@ -160,6 +160,7 @@ kover { } total { xml { + title = "Hideout Mastodon" xmlFile = file("$buildDir/reports/kover/hideout-mastodon.xml") } } From 3890659a7d277763be6e36e630a6fbdb207d939a Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 13:10:14 +0900 Subject: [PATCH 27/30] =?UTF-8?q?chore:=E3=80=80=E4=B8=8D=E8=A6=81?= =?UTF-8?q?=E3=81=AA=E3=82=B9=E3=83=86=E3=83=83=E3=83=97=E3=82=92=E5=89=8A?= =?UTF-8?q?=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index f9860945..7326f383 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -199,12 +199,6 @@ jobs: with: path: 'hideout-core/build/reports/kover' - - - run: ls -R hideout-core/build/reports/kover - - - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml/hideout-core.xml - - run: cat ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml/hideout-mastodon.xml - - name: Report Coverage uses: madrapps/jacoco-report@v1.7.0 with: From 3faf6b9c34b1f41b5481c96377ba4941b3323b0e Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 13:56:24 +0900 Subject: [PATCH 28/30] =?UTF-8?q?chore:=E3=80=80owl=E3=81=A8activitypub?= =?UTF-8?q?=E3=81=AB=E3=82=82lint=E3=81=A8=E3=82=B3=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=82=AB=E3=83=90=E3=83=AC=E3=83=83=E3=82=B8=E3=81=AE=E8=A8=88?= =?UTF-8?q?=E6=B8=AC=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../workflows/pull-request-merge-check.yml | 151 +++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 7326f383..1fa54bf5 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -26,6 +26,8 @@ jobs: outputs: core: ${{ steps.filter.outputs.core }} mastodon: ${{ steps.filter.outputs.mastodon }} + activitypub: ${{ steps.filter.outputs.ap }} + owl: $${{ steps.filter.outputs.owl }} steps: - name: Checkout uses: actions/checkout@v4 @@ -108,6 +110,64 @@ jobs: - name: Build run: ./gradlew :hideout-mastodon:classes --no-daemon + hideout-activitypub-setup: + needs: + - change + if: github.event.pull_request.draft == false && needs.change.outputs.activitypub == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Gradle Wrapper Validation + uses: gradle/actions/wrapper-validation@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Build + run: ./gradlew :hideout-activitypub:classes --no-daemon + + owl-setup: + needs: + - change + if: github.event.pull_request.draft == false && needs.change.outputs.owl == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Gradle Wrapper Validation + uses: gradle/actions/wrapper-validation@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Build + run: ./owl/gradlew :owl:classes --no-daemon + hideout-core-unit-test: needs: - hideout-core-setup @@ -187,11 +247,90 @@ jobs: name: 'hideout-mastodon.xml' path: 'hideout-mastodon/build/reports/kover/hideout-mastodon.xml' + hideout-activitypub-unit-test: + needs: + - hideout-activitypub-setup + - change + if: github.event.pull_request.draft == false && needs.change.outputs.activitypub == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Unit Test + run: ./hideout-activitypub/gradlew :hideout-activitypub:koverXmlReport + + - name: JUnit Test Report + uses: mikepenz/action-junit-report@v4 + with: + report_paths: '**/TEST-*.xml' + check_name: 'hideout-activitypub JUnit Test Report' + + - name: Upload Coverage Report + uses: actions/upload-artifact@v4 + with: + name: 'hideout-activitypub.xml' + path: 'hideout-activitypub/build/reports/kover/hideout-activitypub.xml' + + owl-unit-test: + needs: + - owl-setup + - change + if: github.event.pull_request.draft == false && needs.change.outputs.owl == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + token: ${{ secrets.PAT }} + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + with: + cache-read-only: false + gradle-home-cache-cleanup: true + + - name: Unit Test + run: ./owl/gradlew :owl:koverXmlReport + + - name: JUnit Test Report + uses: mikepenz/action-junit-report@v4 + with: + report_paths: '**/TEST-*.xml' + check_name: 'owl JUnit Test Report' + + - name: Upload Coverage Report + uses: actions/upload-artifact@v4 + with: + name: 'owl.xml' + path: 'owl/build/reports/kover/owl.xml' + coverage: needs: - change - hideout-core-unit-test - hideout-mastodon-unit-test + - hideout-activitypub-unit-test runs-on: ubuntu-latest steps: - name: Download Coverage Report @@ -204,7 +343,9 @@ jobs: with: paths: | ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-core.xml/hideout-core.xml, - ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml/hideout-mastodon.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-mastodon.xml/hideout-mastodon.xml, + ${{ github.workspace }}/hideout-core/build/reports/kover/hideout-activitypub.xml/hideout-activitypub.xml + ${{ github.workspace }}/hideout-core/build/reports/kover/owl.xml/owl.xml token: ${{ secrets.GITHUB_TOKEN }} title: Code Coverage update-comment: true @@ -216,6 +357,8 @@ jobs: - change - hideout-core-setup - hideout-mastodon-setup + - hideout-activitypub-setup + - owl-setup runs-on: ubuntu-latest permissions: contents: write @@ -239,7 +382,11 @@ jobs: gradle-home-cache-cleanup: true - name: Lint - run: ./gradlew :hideout-core:detektMain :hideout-mastodon:detektMain + run: ./gradlew :hideout-core:detektMain :hideout-mastodon:detektMain :hideout-activitypub:detektMain + + - name: owl Lint + if: always() + run: ./owl/gradlew :owl:detektMain - name: Auto Commit if: ${{ always() }} From 80a8a5dceec46f04c2e24fc5ebaa1235d3803a4a Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 14:01:26 +0900 Subject: [PATCH 29/30] =?UTF-8?q?chore:=E3=80=80=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=96=E3=81=AE=E4=BE=9D=E5=AD=98=E9=96=A2=E4=BF=82=E3=81=A8?= =?UTF-8?q?=E5=AE=9F=E8=A1=8C=E6=9D=A1=E4=BB=B6=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index 1fa54bf5..df219854 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -326,11 +326,13 @@ jobs: path: 'owl/build/reports/kover/owl.xml' coverage: + if: needs.change.outputs.core == 'true' || needs.change.outputs.activitypub == 'true' || needs.change.outputs.mastodon == 'true' || needs.change.outputs.owl == 'true' needs: - change - hideout-core-unit-test - hideout-mastodon-unit-test - hideout-activitypub-unit-test + - owl-unit-test runs-on: ubuntu-latest steps: - name: Download Coverage Report @@ -353,6 +355,7 @@ jobs: min-coverage-changed-files: 80 lint: + if: needs.change.outputs.core == 'true' || needs.change.outputs.activitypub == 'true' || needs.change.outputs.mastodon == 'true' || needs.change.outputs.owl == 'true' needs: - change - hideout-core-setup From acb9efdfef622e79288b56458603190e79e03bb3 Mon Sep 17 00:00:00 2001 From: usbharu Date: Tue, 17 Sep 2024 14:07:21 +0900 Subject: [PATCH 30/30] =?UTF-8?q?chore:=E3=80=80=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=96=E3=81=AE=E5=AE=9F=E8=A1=8C=E6=9D=A1=E4=BB=B6=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/pull-request-merge-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request-merge-check.yml b/.github/workflows/pull-request-merge-check.yml index df219854..aa68bd97 100644 --- a/.github/workflows/pull-request-merge-check.yml +++ b/.github/workflows/pull-request-merge-check.yml @@ -326,7 +326,7 @@ jobs: path: 'owl/build/reports/kover/owl.xml' coverage: - if: needs.change.outputs.core == 'true' || needs.change.outputs.activitypub == 'true' || needs.change.outputs.mastodon == 'true' || needs.change.outputs.owl == 'true' + if: always() && (needs.change.outputs.core == 'true' || needs.change.outputs.activitypub == 'true' || needs.change.outputs.mastodon == 'true' || needs.change.outputs.owl == 'true') needs: - change - hideout-core-unit-test @@ -355,7 +355,7 @@ jobs: min-coverage-changed-files: 80 lint: - if: needs.change.outputs.core == 'true' || needs.change.outputs.activitypub == 'true' || needs.change.outputs.mastodon == 'true' || needs.change.outputs.owl == 'true' + if: always() && (needs.change.outputs.core == 'true' || needs.change.outputs.activitypub == 'true' || needs.change.outputs.mastodon == 'true' || needs.change.outputs.owl == 'true') needs: - change - hideout-core-setup