diff --git a/src/docs/asciidoc/api-guide.adoc b/src/docs/asciidoc/api-guide.adoc index 15473328..7aaf4302 100644 --- a/src/docs/asciidoc/api-guide.adoc +++ b/src/docs/asciidoc/api-guide.adoc @@ -9,8 +9,8 @@ endif::[] :sectlinks: :operation-http-request-title: Example Request :operation-http-response-title: Example Response -:author: dokkisan -:revdate: 2024-08-07 +:author: dokkisan, lvalentine6 +:revdate: 2024-11-22 :revnumber: 1.0.0 = Issuefy API 명세서 @@ -47,39 +47,47 @@ include::{snippets}/issuefy/oauth/logout/http-response.adoc[] == 2. 리포지토리 -=== 2.1 리포지토리 구독 +=== 2.1 구독중인 리포지토리 목록 조회 ==== HTTP 요청 -include::{snippets}/issuefy/subscriptions/post/http-request.adoc[] +include::{snippets}/issuefy/subscriptions/get/http-request.adoc[] -===== 요청 본문 +===== 쿼리 매개변수 -include::{snippets}/issuefy/subscriptions/post/request-fields.adoc[] +include::{snippets}/issuefy/subscriptions/get/query-parameters.adoc[] ==== HTTP 응답 -include::{snippets}/issuefy/subscriptions/post/http-response.adoc[] +include::{snippets}/issuefy/subscriptions/get/http-response.adoc[] -=== 2.2 리포지토리 구독 취소 +=== 2.2 리포지토리 구독 ==== HTTP 요청 -// TODO: 스니펫 host 수정 -include::{snippets}/issuefy/subscriptions/delete/http-request.adoc[] + +include::{snippets}/issuefy/subscriptions/post/http-request.adoc[] + +===== 요청 본문 + +include::{snippets}/issuefy/subscriptions/post/request-fields.adoc[] ==== HTTP 응답 -include::{snippets}/issuefy/subscriptions/delete/http-response.adoc[] +include::{snippets}/issuefy/subscriptions/post/http-response.adoc[] -=== 2.3 구독중인 리포지토리 목록 조회 +=== 2.3 리포지토리 구독 취소 ==== HTTP 요청 -include::{snippets}/issuefy/subscriptions/get/http-request.adoc[] +include::{snippets}/issuefy/subscriptions/delete/http-request.adoc[] + +===== 경로 매개변수 + +include::{snippets}/issuefy/subscriptions/delete/path-parameters.adoc[] ==== HTTP 응답 -include::{snippets}/issuefy/subscriptions/get/http-response.adoc[] +include::{snippets}/issuefy/subscriptions/delete/http-response.adoc[] === 2.4 리포지토리 즐겨찾기 @@ -107,8 +115,12 @@ include::{snippets}/issuefy/issues/get/http-request.adoc[] include::{snippets}/issuefy/issues/get/path-parameters.adoc[] +===== 쿼리 매개변수 + +include::{snippets}/issuefy/issues/get/query-parameters.adoc[] + ==== HTTP 응답 -// TODO: 이슈 응답 수정 + include::{snippets}/issuefy/issues/get/http-response.adoc[] ===== 응답 본문 @@ -117,7 +129,7 @@ include::{snippets}/issuefy/issues/get/response-body.adoc[] == 4. Server-Sent Events (SSE) -=== 4.1 SSE 연결 +=== 4.1 SSE 연결 및 수신 ==== HTTP 요청 @@ -125,21 +137,18 @@ include::{snippets}/issuefy/sse/connect/http-request.adoc[] ==== HTTP 응답 -include::{snippets}/issuefy/sse/connect/http-response.adoc[] +[source,text] +---- +event:initial +data:"connected successfully." +id:123456 -=== 4.2 SSE 수신 +event:info +data:{"unreadCount":0} -==== HTTP 요청 - -include::{snippets}/issuefy/sse/receive/http-request.adoc[] - -===== 요청 필드 - -include::{snippets}/issuefy/sse/receive/request-fields.adoc[] - -==== HTTP 응답 - -include::{snippets}/issuefy/sse/receive/http-response.adoc[] +event:info +data:{"unreadCount":1} +---- == 5. 알림 @@ -214,3 +223,29 @@ include::{snippets}/issuefy/user/update-email/request-fields.adoc[] ==== HTTP 응답 include::{snippets}/issuefy/user/update-email/http-response.adoc[] + +== 7. 대시보드 + +=== 7.1 대시보드 정보 조회 + +==== HTTP 요청 + +include::{snippets}/dashboard/http-request.adoc[] + +==== HTTP 응답 + +include::{snippets}/dashboard/http-response.adoc[] + +===== 응답 필드 + +include::{snippets}/dashboard/response-fields.adoc[] + +== 8. 서버 상태 확인 + +=== HTTP 요청 + +include::{snippets}/health-check/http-request.adoc[] + +=== HTTP 응답 + +include::{snippets}/health-check/http-response.adoc[] \ No newline at end of file diff --git a/src/main/java/site/iris/issuefy/response/PagedRepositoryIssuesResponse.java b/src/main/java/site/iris/issuefy/response/PagedRepositoryIssuesResponse.java index 42024eb0..9a1e5db3 100644 --- a/src/main/java/site/iris/issuefy/response/PagedRepositoryIssuesResponse.java +++ b/src/main/java/site/iris/issuefy/response/PagedRepositoryIssuesResponse.java @@ -4,8 +4,10 @@ import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@NoArgsConstructor @AllArgsConstructor public class PagedRepositoryIssuesResponse { private int currentPage; diff --git a/src/main/resources/static/docs/api-guide.html b/src/main/resources/static/docs/api-guide.html index 743ac83d..014ca62d 100644 --- a/src/main/resources/static/docs/api-guide.html +++ b/src/main/resources/static/docs/api-guide.html @@ -1,2786 +1,1238 @@ - - - - - - Issuefy API 명세서 - - - - + + + + + +Issuefy API 명세서 + + + +
-
-

1. 사용자 인증/인가

-
-
-

1.1 OAuth 로그인

-
-

HTTP 요청

-
-
+
+

1. 사용자 인증/인가

+
+
+

1.1 OAuth 로그인

+
+

HTTP 요청

+
+
GET /api/login?code=test-auth-code HTTP/1.1
 Accept: application/json
-Host: localhost:8080
-
-
-
-
-

HTTP 응답

-
-
+Host: issuefy.site +
+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
 Content-Type: application/json
-Content-Length: 205
+Content-Length: 257
 
-{"userName":"testUser","userEmail":"test@gmail.com","avatarURL":"https://avatars.githubusercontent.com/12345","alertStatus":false,"jwt":{"accessToken":"test-jwt-token","refreshToken":"test-refresh-token"}}
-
-
-
-
응답 필드
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

- userName

String -

사용자 로그인 이름

- userEmail

String -

사용자 이메일 주소

- avatarURL

String -

사용자 아바타 URL

- alertStatus

Boolean -

알림 상태

jwt.accessToken -

String -

JWT 액세스 토큰

jwt.refreshToken -

String -

JWT 리프레시 토큰

-
-
-
-
-

1.2 OAuth 로그아웃

-
-

HTTP 요청

-
-
+{ + "userName" : "testUser", + "userEmail" : "test@gmail.com", + "avatarURL" : "https://avatars.githubusercontent.com/12345", + "alertStatus" : false, + "jwt" : { + "accessToken" : "test-jwt-token", + "refreshToken" : "test-refresh-token" + } +} +
+
+
+
응답 필드
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathTypeDescription

userName

String

사용자 로그인 이름

userEmail

String

사용자 이메일 주소

avatarURL

String

사용자 아바타 URL

alertStatus

Boolean

알림 상태

jwt.accessToken

String

JWT 액세스 토큰

jwt.refreshToken

String

JWT 리프레시 토큰

+
+
+
+
+

1.2 OAuth 로그아웃

+
+

HTTP 요청

+
+
POST /api/logout HTTP/1.1
 Authorization: Bearer test-jwt-token
-Host: localhost:8080
+Host: issuefy.site
 Content-Type: application/x-www-form-urlencoded
-
-
-
-
요청 헤더
- - - - - - - - - - - - - - - - - -
NameDescription

- Authorization

JWT 토큰

-
-
-
-

HTTP 응답

-
-
+
+
+
+
요청 헤더
+ ++++ + + + + + + + + + + + + +
NameDescription

Authorization

JWT 토큰

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
-
-
- +
+

2. 리포지토리

+
+
+

2.1 구독중인 리포지토리 목록 조회

+
+

HTTP 요청

+
+
+
GET /api/subscriptions?page=0&sort=latestUpdateAt&order=desc&starred=false HTTP/1.1
+Authorization: Bearer testToken
+Host: issuefy.site
+
+
+
+
쿼리 매개변수
+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription

page

페이지 번호

sort

정렬 기준

order

정렬 순서 (asc/desc)

starred

즐겨찾기 여부

+
+
+
+

HTTP 응답

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+Content-Length: 349
+
+{
+  "currentPage" : 0,
+  "pageSize" : 15,
+  "totalElements" : 29,
+  "totalPages" : 2,
+  "subscriptionListDtos" : [ {
+    "orgId" : 6764390,
+    "orgName" : "elastic",
+    "githubRepositoryId" : 507775,
+    "repositoryName" : "elasticsearch",
+    "repositoryLatestUpdateAt" : "2024-10-23T21:26:34",
+    "repositoryStarred" : true
+  } ]
+}
+
+
+
+
+
+

2.2 리포지토리 구독

+
+

HTTP 요청

+
+
POST /api/subscriptions HTTP/1.1
 Content-Type: application/json;charset=UTF-8
-Content-Length: 73
+Content-Length: 61
 Host: issuefy.site
 
 {
-  "repositoryUrl" : "https://issuefy.site/2024-Iris/issuefy-spring"
+  "repositoryUrl" : "https://github.com/org/repository"
 }
-
-
-
-
요청 본문
- - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

- repositoryUrl

String -

GitHub 리포지토리 URL

-
-
-
-
-

HTTP 응답

-
-
+
+
+
+
요청 본문
+ +++++ + + + + + + + + + + + + + + +
PathTypeDescription

repositoryUrl

String

GitHub 리포지토리 URL

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 201 Created
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
 Location: https://github.com/2024-Iris/issuefy-spring
-
-
-
-
- +
+

2.3 리포지토리 구독 취소

+
+

HTTP 요청

+
+
DELETE /api/subscriptions/1 HTTP/1.1
-Host: localhost:8080
-
-
-
-
-

HTTP 응답

-
-
-
HTTP/1.1 204 No Content
-Vary: Origin
-Vary: Access-Control-Request-Method
-Vary: Access-Control-Request-Headers
-
-
-
-
-
-

2.3 구독중인 리포지토리 목록 조회 -

-
-

HTTP 요청

-
-
-
GET /api/subscriptions HTTP/1.1
-Authorization: Bearer testToken
 Host: issuefy.site
-
-
-
-
-

HTTP 응답

-
-
-
HTTP/1.1 200 OK
+
+
+
+
경로 매개변수
+ + ++++ + + + + + + + + + + + + +
Table 1. /api/subscriptions/{gh_repo_id}
ParameterDescription

gh_repo_id

GitHub 리포지토리 ID

+
+
+
+

HTTP 응답

+
+
+
HTTP/1.1 204 No Content
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
- +
+

2.4 리포지토리 즐겨찾기

+
+

HTTP 요청

+
+
PUT /api/subscriptions/star/1 HTTP/1.1
 Host: issuefy.site
 Content-Type: application/x-www-form-urlencoded
-
-
-
-
경로 매개변수
- - - - - - - - - - - - - - - - - - -
Table 1. /api/subscriptions/star/{gh_repo_id}
ParameterDescription

- gh_repo_id

GitHub 리포지토리 ID

-
-
-
-
-

HTTP 응답

-
-
+
+
+
+
경로 매개변수
+ + ++++ + + + + + + + + + + + + +
Table 2. /api/subscriptions/star/{gh_repo_id}
ParameterDescription

gh_repo_id

GitHub 리포지토리 ID

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 204 No Content
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
-
-
-
-

3. 이슈

-
-
-

3.1 이슈 목록 조회

-
-

HTTP 요청

-
-
-
GET /api/subscriptions/iris/issuefy/issues?page=0&size=10&sort=createdAt&order=desc HTTP/1.1
+
+
+
+
+
+
+
+

3. 이슈

+
+
+

3.1 이슈 목록 조회

+
+

HTTP 요청

+
+
+
GET /api/subscriptions/iris/issuefy/issues?page=0&size=15&sort=createdAt&order=desc HTTP/1.1
+Accept: application/json
 Host: issuefy.site
-
-
-
-
경로 매개변수
- - - - - - - - - - - - - - - - - - - - - - -
Table 2. /api/subscriptions/{org_name}/{repo_name}/issues
ParameterDescription

- org_name

조직 이름

- repo_name

리포지토리 이름

-
-
-
-

HTTP 응답

-
-
+
+
+
+
경로 매개변수
+ + ++++ + + + + + + + + + + + + + + + + +
Table 3. /api/subscriptions/{org_name}/{repo_name}/issues
ParameterDescription

org_name

조직 이름

repo_name

리포지토리 이름

+
+
+
쿼리 매개변수
+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription

page

페이지 번호

size

페이지 크기

sort

정렬 기준

order

정렬 순서

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
-Vary: Access-Control-Request-Headers
-
-
-
-
응답 본문
-
-
-
-
-
-
-
-
-
-
-
-

4. Server-Sent Events - (SSE)

-
-
-

4.1 SSE 연결

-
-

HTTP 요청

-
-
+Vary: Access-Control-Request-Headers +Content-Type: application/json +Content-Length: 492 + +{ + "currentPage" : 0, + "pageSize" : 15, + "totalElements" : 100, + "totalPages" : 10, + "repositoryName" : "issuefy", + "issues" : [ { + "id" : 1, + "githubIssueNumber" : 123, + "state" : "OPEN", + "title" : "Sample Issue", + "labels" : [ { + "name" : null, + "color" : null + } ], + "read" : true, + "createdAt" : "2024-11-23T22:30:43.353437", + "updatedAt" : "2024-11-23T22:30:43.353437", + "closedAt" : null, + "starred" : false + } ] +} +
+
+
+
응답 본문
+
+
+
{
+  "currentPage" : 0,
+  "pageSize" : 15,
+  "totalElements" : 100,
+  "totalPages" : 10,
+  "repositoryName" : "issuefy",
+  "issues" : [ {
+    "id" : 1,
+    "githubIssueNumber" : 123,
+    "state" : "OPEN",
+    "title" : "Sample Issue",
+    "labels" : [ {
+      "name" : null,
+      "color" : null
+    } ],
+    "read" : true,
+    "createdAt" : "2024-11-23T22:30:43.353437",
+    "updatedAt" : "2024-11-23T22:30:43.353437",
+    "closedAt" : null,
+    "starred" : false
+  } ]
+}
+
+
+
+
+
+
+
+
+

4. Server-Sent Events (SSE)

+
+
+

4.1 SSE 연결

+
+

HTTP 요청

+
+
GET /api/connect HTTP/1.1
 Accept: text/event-stream
-Host: localhost:8080
-
-
-
-
-

HTTP 응답

-
-
+Host: issuefy.site +
+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
-
-

4.2 SSE 수신

-
-

HTTP 요청

-
-
+
+
+
+
+
+

4.2 SSE 수신

+
+

HTTP 요청

+
+
POST /api/receive HTTP/1.1
 Content-Type: application/json;charset=UTF-8
 Content-Length: 34
-Host: localhost:8080
+Host: issuefy.site
 
 {"updatedRepositoryIds":["1","2"]}
-
-
-
-
요청 필드
- - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

updatedRepositoryIds -

Array -

업데이트 된 리포지토리 ID - 목록

-
-
-
-

HTTP 응답

-
-
+
+
+
+
요청 필드
+ +++++ + + + + + + + + + + + + + + +
PathTypeDescription

updatedRepositoryIds

Array

업데이트 된 리포지토리 ID 목록

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
-
-
-
-

5. 알림

-
-
-

5.1 알림 조회

-
-

HTTP 요청

-
-
+
+
+
+
+
+
+
+

5. 알림

+
+
+

5.1 알림 조회

+
+

HTTP 요청

+
+
GET /api/notifications HTTP/1.1
-Host: localhost:8080
-
-
-
-
-

HTTP 응답

-
-
+Host: issuefy.site +
+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
 Content-Type: application/json
-Content-Length: 350
+Content-Length: 352
 
 [ {
   "userNotificationId" : 1,
   "orgName" : "testOrg1",
   "repositoryName" : "testRepo1",
-  "notificationCreatedAt" : "2024-09-02T22:50:57.295435",
+  "notificationCreatedAt" : "2024-11-23T22:30:43.9301388",
   "read" : false
 }, {
   "userNotificationId" : 2,
   "orgName" : "testOrg2",
   "repositoryName" : "testRepo2",
-  "notificationCreatedAt" : "2024-09-02T22:50:57.295435",
+  "notificationCreatedAt" : "2024-11-23T22:30:43.9311381",
   "read" : false
 } ]
-
-
-
-
응답 필드
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

[].userNotificationId -

Number -

알림 ID

- [].orgName

String -

조직 이름

[].repositoryName -

String -

저장소 이름

[].notificationCreatedAt -

String -

생성 시간

[].read -

Boolean -

읽음 여부

-
-
-
-
-

5.2 알림 읽음 여부 업데이트

-
-

HTTP 요청

-
-
+
+
+
+
응답 필드
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathTypeDescription

[].userNotificationId

Number

알림 ID

[].orgName

String

조직 이름

[].repositoryName

String

저장소 이름

[].notificationCreatedAt

String

생성 시간

[].read

Boolean

읽음 여부

+
+
+
+
+

5.2 알림 읽음 여부 업데이트

+
+

HTTP 요청

+
+
PATCH /api/notifications HTTP/1.1
 Content-Type: application/json;charset=UTF-8
 Content-Length: 29
-Host: localhost:8080
+Host: issuefy.site
 
 {"userNotificationIds":[1,2]}
-
-
-
-
요청 필드
- - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

userNotificationIds -

Array -

업데이트할 알림 ID 목록

-
-
-
-
-

HTTP 응답

-
-
+
+
+
+
요청 필드
+ +++++ + + + + + + + + + + + + + + +
PathTypeDescription

userNotificationIds

Array

업데이트할 알림 ID 목록

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
-
-
- +
+

6. 마이페이지

+
+
+

6.1 사용자 정보 조회

+
+

HTTP 요청

+
+
GET /api/user/info HTTP/1.1
 Accept: application/json
-Host: localhost:8080
-
-
-
-
-

HTTP 응답

-
-
+Host: issuefy.site +
+
+
+
+

HTTP 응답

+
+
HTTP/1.1 200 OK
 Vary: Origin
 Vary: Access-Control-Request-Method
@@ -2789,182 +1241,166 @@ 

HTTP 응답 Content-Length: 111 {"email":"test@gmail.com","alertStatus":false,"login":"testUser","avatar_url":"https://example.com/avatar.jpg"}

-
-
-
-
응답 필드
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

login -

String -

사용자의 GitHub ID

-

- avatar_url

String -

사용자의 GitHub 프로필 이미지 - URL

email -

String -

사용자의 이메일 주소

- alertStatus

Boolean -

알림 상태

-
-
-
-
-

6.2 알림 수신 여부 업데이트

-
-

HTTP 요청

-
-
+
+
+
+
응답 필드
+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PathTypeDescription

login

String

사용자의 GitHub ID

avatar_url

String

사용자의 GitHub 프로필 이미지 URL

email

String

사용자의 이메일 주소

alertStatus

Boolean

알림 상태

+
+
+
+
+

6.2 알림 수신 여부 업데이트

+
+

HTTP 요청

+
+
PATCH /api/user/alert HTTP/1.1
 Content-Type: application/json;charset=UTF-8
 Content-Length: 20
-Host: localhost:8080
+Host: issuefy.site
 
 {"alertStatus":true}
-
-
-
-
요청 필드
- - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

- alertStatus

Boolean -

알림 받기 / 안받기

-
-
-
-

HTTP 응답

-
-
+
+
+
+
요청 필드
+ +++++ + + + + + + + + + + + + + + +
PathTypeDescription

alertStatus

Boolean

알림 받기 / 안받기

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 204 No Content
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
- +
+

6.3 이메일 업데이트

+
+

HTTP 요청

+
+
PATCH /api/user/email HTTP/1.1
 Content-Type: application/json;charset=UTF-8
 Content-Length: 30
-Host: localhost:8080
+Host: issuefy.site
 
 {"email":"newemail@gmail.com"}
-
-
-
-
요청 필드
- - - - - - - - - - - - - - - - - - - - -
PathTypeDescription

email -

String -

새로운 이메일 주소

-
-
-
-

HTTP 응답

-
-
+
+
+
+
요청 필드
+ +++++ + + + + + + + + + + + + + + +
PathTypeDescription

email

String

새로운 이메일 주소

+
+
+
+

HTTP 응답

+
+
HTTP/1.1 204 No Content
 Vary: Origin
 Vary: Access-Control-Request-Method
 Vary: Access-Control-Request-Headers
-
-
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/test/java/site/iris/issuefy/controller/AuthenticationControllerTest.java b/src/test/java/site/iris/issuefy/controller/AuthenticationControllerTest.java index d1de8732..9b8ae93f 100644 --- a/src/test/java/site/iris/issuefy/controller/AuthenticationControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/AuthenticationControllerTest.java @@ -7,6 +7,7 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static site.iris.issuefy.ApiDocumentUtils.*; import java.util.HashMap; import java.util.Map; @@ -28,7 +29,7 @@ import site.iris.issuefy.service.UserService; @WebMvcTest(AuthenticationController.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class AuthenticationControllerTest { @Autowired @@ -75,6 +76,8 @@ void login_after_return_userInfoAndJWT() throws Exception { .andExpect(jsonPath("$.jwt.accessToken", is(accessToken))) .andExpect(jsonPath("$.jwt.refreshToken", is(refreshToken))) .andDo(document("issuefy/oauth/login", + getDocumentRequest(), + getDocumentResponse(), responseFields( fieldWithPath("userName").description("사용자 로그인 이름"), fieldWithPath("userEmail").description("사용자 이메일 주소"), @@ -90,7 +93,8 @@ void login_after_return_userInfoAndJWT() throws Exception { void logout() throws Exception { // given String githubId = "testUser"; - String token = "Bearer test-jwt-token"; + String token = "Bearer testToken"; + String tokenWithoutBearer = "testToken"; when(tokenProvider.isValidToken(anyString())).thenReturn(true); // when @@ -101,10 +105,12 @@ void logout() throws Exception { // then result.andExpect(status().isOk()) .andDo(document("issuefy/oauth/logout", + getDocumentRequest(), + getDocumentResponse(), requestHeaders( headerWithName("Authorization").description("JWT 토큰") ))); - verify(tokenProvider).invalidateToken("test-jwt-token"); + verify(tokenProvider).invalidateToken(tokenWithoutBearer); } } \ No newline at end of file diff --git a/src/test/java/site/iris/issuefy/controller/DashBoardControllerTest.java b/src/test/java/site/iris/issuefy/controller/DashBoardControllerTest.java index e75ccb46..504e5b5a 100644 --- a/src/test/java/site/iris/issuefy/controller/DashBoardControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/DashBoardControllerTest.java @@ -31,7 +31,7 @@ @ExtendWith(RestDocumentationExtension.class) @WebFluxTest(controllers = DashBoardController.class) @Import(DashBoardControllerTest.TestSecurityConfig.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class DashBoardControllerTest { @Autowired @@ -43,6 +43,7 @@ class DashBoardControllerTest { @Test @DisplayName("대시보드에 필요한 랭크, 주간방문수, 리포지토리 추가 횟수를 반환한다.") void dashboard() { + String token = "Bearer testToken"; LocalDate endDate = LocalDate.now(); LocalDate startDate = endDate.minusDays(6); DashBoardResponse mockResponse = DashBoardResponse.of(startDate, endDate, "A", "10", "5"); @@ -50,7 +51,7 @@ void dashboard() { when(dashBoardService.getDashBoardFromLoki(anyString())).thenReturn(Mono.just(mockResponse)); webTestClient.get().uri("/api/dashboard") - .header("Authorization", "Bearer mockJwtToken") + .header("Authorization", token) .exchange() .expectStatus().isOk() .expectBody() diff --git a/src/test/java/site/iris/issuefy/controller/HealthCheckControllerTest.java b/src/test/java/site/iris/issuefy/controller/HealthCheckControllerTest.java index 806b0c5b..cb359087 100644 --- a/src/test/java/site/iris/issuefy/controller/HealthCheckControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/HealthCheckControllerTest.java @@ -13,7 +13,7 @@ import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(HealthCheckController.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class HealthCheckControllerTest { @Autowired diff --git a/src/test/java/site/iris/issuefy/controller/IssueControllerTest.java b/src/test/java/site/iris/issuefy/controller/IssueControllerTest.java index 76e937d9..267ab4f5 100644 --- a/src/test/java/site/iris/issuefy/controller/IssueControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/IssueControllerTest.java @@ -3,11 +3,14 @@ import static org.mockito.Mockito.*; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.*; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; import static org.springframework.restdocs.request.RequestDocumentation.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static site.iris.issuefy.ApiDocumentUtils.*; +import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -15,15 +18,18 @@ import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; +import site.iris.issuefy.response.IssueResponse; +import site.iris.issuefy.response.LabelResponse; import site.iris.issuefy.response.PagedRepositoryIssuesResponse; import site.iris.issuefy.response.StarRepositoryIssuesResponse; import site.iris.issuefy.service.IssueService; @WebMvcTest(IssueController.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class IssueControllerTest { @Autowired @@ -36,15 +42,32 @@ class IssueControllerTest { @Test void getIssuesByRepoName() throws Exception { // given + String token = "Bearer testToken"; String orgName = "iris"; String repoName = "issuefy"; String githubId = "dokkisan"; int page = 0; - int pageSize = 10; + int pageSize = 15; String sort = "createdAt"; String order = "desc"; - PagedRepositoryIssuesResponse response = new PagedRepositoryIssuesResponse(0, 10, 100, 10, repoName, - new ArrayList<>()); + + IssueResponse sampleIssue = new IssueResponse( + 1L, + 123L, + "OPEN", + "Sample Issue", + List.of(new LabelResponse()), + true, + LocalDateTime.now(), + LocalDateTime.now(), + null, + false + ); + + PagedRepositoryIssuesResponse response = new PagedRepositoryIssuesResponse( + 0, 15, 100, 10, repoName, + List.of(sampleIssue) + ); // when when(issueService.getRepositoryIssues(orgName, repoName, githubId, page, pageSize, sort, order)) @@ -52,10 +75,12 @@ void getIssuesByRepoName() throws Exception { ResultActions result = mockMvc.perform( get("/api/subscriptions/{org_name}/{repo_name}/issues", orgName, repoName) .requestAttr("githubId", githubId) + .header("Authorization", token) .param("page", String.valueOf(page)) .param("size", String.valueOf(pageSize)) .param("sort", sort) - .param("order", order)); + .param("order", order) + .accept(MediaType.APPLICATION_JSON)); // then result.andExpect(status().isOk()) @@ -71,6 +96,26 @@ void getIssuesByRepoName() throws Exception { parameterWithName("size").description("페이지 크기").optional(), parameterWithName("sort").description("정렬 기준").optional(), parameterWithName("order").description("정렬 순서").optional() + ), + responseFields( + fieldWithPath("currentPage").description("현재 페이지 번호"), + fieldWithPath("pageSize").description("페이지 크기"), + fieldWithPath("totalElements").description("전체 이슈 수"), + fieldWithPath("totalPages").description("전체 페이지 수"), + fieldWithPath("repositoryName").description("리포지토리 이름"), + fieldWithPath("issues").description("이슈 목록"), + fieldWithPath("issues[].id").description("이슈 ID"), + fieldWithPath("issues[].githubIssueNumber").description("GitHub 이슈 번호"), + fieldWithPath("issues[].state").description("이슈 상태"), + fieldWithPath("issues[].title").description("이슈 제목"), + fieldWithPath("issues[].labels").description("라벨 목록"), + fieldWithPath("issues[].labels[].name").description("라벨 이름"), + fieldWithPath("issues[].labels[].color").description("라벨 색상"), + fieldWithPath("issues[].read").description("읽음 여부"), + fieldWithPath("issues[].createdAt").description("생성일시"), + fieldWithPath("issues[].updatedAt").description("수정일시"), + fieldWithPath("issues[].closedAt").description("종료일시"), + fieldWithPath("issues[].starred").description("스타 여부") ) )); } @@ -79,6 +124,7 @@ void getIssuesByRepoName() throws Exception { @Test void getIssueStar() throws Exception { // given + String token = "Bearer testToken"; String githubId = "dokkisan"; StarRepositoryIssuesResponse response = new StarRepositoryIssuesResponse(new ArrayList<>()); @@ -86,7 +132,8 @@ void getIssueStar() throws Exception { when(issueService.getStarredRepositoryIssuesResponse(githubId)).thenReturn(response); ResultActions result = mockMvc.perform( get("/api/subscriptions/issue-star") - .requestAttr("githubId", githubId)); + .requestAttr("githubId", githubId) + .header("Authorization", token)); // then result.andExpect(status().isOk()) @@ -100,6 +147,7 @@ void getIssueStar() throws Exception { @Test void updateIssueStar() throws Exception { // given + String token = "Bearer testToken"; String githubId = "dokkisan"; Long issueId = 123L; @@ -107,7 +155,8 @@ void updateIssueStar() throws Exception { doNothing().when(issueService).toggleIssueStar(githubId, issueId); ResultActions result = mockMvc.perform( put("/api/subscriptions/issue-star/{gh_issue_id}", issueId) - .requestAttr("githubId", githubId)); + .requestAttr("githubId", githubId) + .header("Authorization", token)); // then result.andExpect(status().isNoContent()) diff --git a/src/test/java/site/iris/issuefy/controller/NotificationControllerTest.java b/src/test/java/site/iris/issuefy/controller/NotificationControllerTest.java index 7c3b88b7..0a54cdef 100644 --- a/src/test/java/site/iris/issuefy/controller/NotificationControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/NotificationControllerTest.java @@ -32,7 +32,7 @@ @ExtendWith(RestDocumentationExtension.class) @WebMvcTest(NotificationController.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class NotificationControllerTest { @Autowired @@ -47,6 +47,7 @@ class NotificationControllerTest { @Test @DisplayName("사용자의 알림 목록을 조회하여 반환한다.") void getNotifications() throws Exception { + String token = "Bearer testToken"; String githubId = "testUser"; List notificationDtos = Arrays.asList( NotificationDto.of(1L, "testOrg1", "testRepo1", LocalDateTime.now(), false), @@ -56,7 +57,8 @@ void getNotifications() throws Exception { given(notificationService.findNotifications(githubId)).willReturn(notificationDtos); mockMvc.perform(get("/api/notifications") - .requestAttr("githubId", githubId)) + .requestAttr("githubId", githubId) + .header("Authorization", token)) .andExpect(status().isOk()) .andExpect(jsonPath("$", hasSize(2))) .andDo(document("issuefy/notifications/get", @@ -75,12 +77,14 @@ void getNotifications() throws Exception { @Test @DisplayName("각 알림을 읽음으로 업데이트 한다.") void updateNotification() throws Exception { + String token = "Bearer testToken"; List ids = Arrays.asList(1L, 2L); NotificationReadDto notificationReadDto = new NotificationReadDto(ids); mockMvc.perform(patch("/api/notifications") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(notificationReadDto))) + .content(objectMapper.writeValueAsString(notificationReadDto)) + .header("Authorization", token)) .andExpect(status().isOk()) .andDo(document("issuefy/notifications/update", requestFields( diff --git a/src/test/java/site/iris/issuefy/controller/SseControllerTest.java b/src/test/java/site/iris/issuefy/controller/SseControllerTest.java index 01304565..7a9adf4d 100644 --- a/src/test/java/site/iris/issuefy/controller/SseControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/SseControllerTest.java @@ -8,6 +8,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static site.iris.issuefy.ApiDocumentUtils.*; import java.util.Arrays; @@ -29,7 +30,7 @@ import site.iris.issuefy.service.SseService; @WebMvcTest(SseController.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class SseControllerTest { @Autowired @@ -47,6 +48,7 @@ class SseControllerTest { @Test @DisplayName("SSE 커넥션을 생성하고 연결한다.") void connect() throws Exception { + String token = "Bearer testToken"; String githubId = "testUser"; UnreadNotificationDto unreadNotificationDto = new UnreadNotificationDto(5); @@ -55,10 +57,14 @@ void connect() throws Exception { mockMvc.perform(get("/api/connect") .requestAttr("githubId", githubId) + .header("Authorization", token) .accept(MediaType.TEXT_EVENT_STREAM_VALUE)) .andExpect(status().isOk()) .andExpect(request().asyncStarted()) - .andDo(document("issuefy/sse/connect")); + .andDo(document("issuefy/sse/connect", + getDocumentRequest(), + getDocumentResponse() + )); verify(sseService).connect(githubId); verify(notificationService).getNotification(githubId); diff --git a/src/test/java/site/iris/issuefy/controller/SubscriptionControllerTest.java b/src/test/java/site/iris/issuefy/controller/SubscriptionControllerTest.java index f33124df..ac1a7cb4 100644 --- a/src/test/java/site/iris/issuefy/controller/SubscriptionControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/SubscriptionControllerTest.java @@ -2,14 +2,16 @@ import static org.mockito.Mockito.*; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*; +import static org.springframework.restdocs.operation.preprocess.Preprocessors.*; import static org.springframework.restdocs.payload.PayloadDocumentation.*; import static org.springframework.restdocs.request.RequestDocumentation.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import static site.iris.issuefy.ApiDocumentUtils.*; -import java.util.ArrayList; +import java.time.LocalDateTime; import java.util.List; +import java.util.regex.Pattern; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -32,7 +34,7 @@ import site.iris.issuefy.service.SubscriptionService; @WebMvcTest(SubscriptionController.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class SubscriptionControllerTest { @Autowired @@ -50,15 +52,40 @@ class SubscriptionControllerTest { @DisplayName("구독 중인 repository 목록을 조회한다.") @Test void getSubscribedRepositories() throws Exception { - // given + //given String token = "Bearer testToken"; String githubId = "testGithubId"; - List subscriptionResponses = new ArrayList<>(); - when(subscriptionService.getSubscribedRepositories("testToken", 1, 15, "sort", "order", false)).thenReturn( - PagedSubscriptionResponse.of(1, 15, 1, 1, subscriptionResponses)); + + List subscriptionResponses = List.of( + new SubscriptionListDto( + 6764390L, + "elastic", + 507775L, + "elasticsearch", + LocalDateTime.of(2024, 10, 23, 21, 26, 34), + true + ) + ); + + PagedSubscriptionResponse response = PagedSubscriptionResponse.of( + 0, 15, 29, 2, subscriptionResponses + ); + + when(subscriptionService.getSubscribedRepositories( + eq(githubId), + eq(0), + eq(15), + eq("latestUpdateAt"), + eq("desc"), + eq(false) + )).thenReturn(response); // when ResultActions result = mockMvc.perform(get("/api/subscriptions") + .param("page", "0") + .param("sort", "latestUpdateAt") + .param("order", "desc") + .param("starred", "false") .header("Authorization", token) .requestAttr("githubId", githubId)); @@ -66,7 +93,37 @@ void getSubscribedRepositories() throws Exception { result.andExpect(status().isOk()) .andDo(document("issuefy/subscriptions/get", getDocumentRequest(), - getDocumentResponse() + getDocumentResponse(), + queryParameters( + parameterWithName("page").description("페이지 번호").optional(), + parameterWithName("sort").description("정렬 기준").optional(), + parameterWithName("order").description("정렬 순서 (asc/desc)").optional(), + parameterWithName("starred").description("즐겨찾기 여부").optional() + ), + responseFields( + fieldWithPath("currentPage").type(JsonFieldType.NUMBER) + .description("현재 페이지 번호"), + fieldWithPath("pageSize").type(JsonFieldType.NUMBER) + .description("페이지 크기"), + fieldWithPath("totalElements").type(JsonFieldType.NUMBER) + .description("전체 항목 수"), + fieldWithPath("totalPages").type(JsonFieldType.NUMBER) + .description("전체 페이지 수"), + fieldWithPath("subscriptionListDtos").type(JsonFieldType.ARRAY) + .description("구독 리포지토리 목록"), + fieldWithPath("subscriptionListDtos[].orgId").type(JsonFieldType.NUMBER) + .description("조직 ID"), + fieldWithPath("subscriptionListDtos[].orgName").type(JsonFieldType.STRING) + .description("조직 이름"), + fieldWithPath("subscriptionListDtos[].githubRepositoryId").type(JsonFieldType.NUMBER) + .description("GitHub 리포지토리 ID"), + fieldWithPath("subscriptionListDtos[].repositoryName").type(JsonFieldType.STRING) + .description("리포지토리 이름"), + fieldWithPath("subscriptionListDtos[].repositoryLatestUpdateAt").type(JsonFieldType.STRING) + .description("리포지토리 최근 업데이트 시간"), + fieldWithPath("subscriptionListDtos[].repositoryStarred").type(JsonFieldType.BOOLEAN) + .description("즐겨찾기 여부") + ) )); } @@ -74,6 +131,7 @@ void getSubscribedRepositories() throws Exception { @Test void addRepository() throws Exception { // given + String token = "Bearer testToken"; String githubId = "testUser"; String repositoryUrl = "https://github.com/2024-Iris/issuefy-spring"; RepositoryRecord repositoryUrlVo = new RepositoryRecord(repositoryUrl); @@ -81,16 +139,22 @@ void addRepository() throws Exception { // when ResultActions result = mockMvc.perform(post("/api/subscriptions") .requestAttr("githubId", githubId) + .header("Authorization", token) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(repositoryUrlVo))); // then result.andExpect(status().isCreated()) .andDo(document("issuefy/subscriptions/post", - getDocumentRequest(), + preprocessRequest(prettyPrint(), + replacePattern( + Pattern.compile("\"repositoryUrl\"\\s*:\\s*\"[^\"]*\""), + "\"repositoryUrl\" : \"https://github.com/org/repository\"" + )), getDocumentResponse(), requestFields( - fieldWithPath("repositoryUrl").type(JsonFieldType.STRING).description("GitHub 리포지토리 URL") + fieldWithPath("repositoryUrl").type(JsonFieldType.STRING) + .description("GitHub 리포지토리 URL") ) )); } @@ -99,15 +163,19 @@ void addRepository() throws Exception { @DisplayName("구독하고 있는 리포지토리를 삭제한다.") void unsubscribeRepository() throws Exception { // given + String token = "Bearer testToken"; String githubId = "testUser"; Long ghRepoId = 1L; doNothing().when(subscriptionService).unsubscribeRepository(ghRepoId); mockMvc.perform(RestDocumentationRequestBuilders.delete("/api/subscriptions/{gh_repo_id}", ghRepoId) - .requestAttr("githubId", githubId)) + .requestAttr("githubId", githubId) + .header("Authorization", token)) .andExpect(status().isNoContent()) .andDo(document("issuefy/subscriptions/delete", + getDocumentRequest(), + getDocumentResponse(), pathParameters( parameterWithName("gh_repo_id").description("GitHub 리포지토리 ID") ) @@ -120,6 +188,7 @@ void unsubscribeRepository() throws Exception { @DisplayName("리포지토리 즐겨찾기를 토글한다.") void toggleStarRepository() throws Exception { // given + String token = "Bearer testToken"; String githubId = "testUser"; Long ghRepoId = 1L; @@ -128,7 +197,8 @@ void toggleStarRepository() throws Exception { // when ResultActions result = mockMvc.perform( RestDocumentationRequestBuilders.put("/api/subscriptions/star/{gh_repo_id}", ghRepoId) - .requestAttr("githubId", githubId)); + .requestAttr("githubId", githubId) + .header("Authorization", token)); // then result.andExpect(status().isNoContent()) diff --git a/src/test/java/site/iris/issuefy/controller/UserControllerTest.java b/src/test/java/site/iris/issuefy/controller/UserControllerTest.java index 64105407..18c8e4d6 100644 --- a/src/test/java/site/iris/issuefy/controller/UserControllerTest.java +++ b/src/test/java/site/iris/issuefy/controller/UserControllerTest.java @@ -20,7 +20,7 @@ import site.iris.issuefy.service.UserService; @WebMvcTest(UserController.class) -@AutoConfigureRestDocs +@AutoConfigureRestDocs(uriScheme = "https", uriHost = "issuefy.site", uriPort = -1) class UserControllerTest { @Autowired @@ -33,6 +33,7 @@ class UserControllerTest { @Test void getUserInfo() throws Exception { // given + String token = "Bearer testToken"; String githubId = "testUser"; UserDto userDto = UserDto.of(githubId, "https://example.com/avatar.jpg", "test@gmail.com", false); when(userService.getUserInfo(githubId)).thenReturn(userDto); @@ -40,6 +41,7 @@ void getUserInfo() throws Exception { // when ResultActions result = mockMvc.perform(get("/api/user/info") .requestAttr("githubId", githubId) + .header("Authorization", token) .accept(MediaType.APPLICATION_JSON)); // then @@ -63,6 +65,7 @@ void getUserInfo() throws Exception { @Test void updateEmail() throws Exception { // given + String token = "Bearer testToken"; String githubId = "testUser"; String newEmail = "newemail@gmail.com"; String requestBody = "{\"email\":\"" + newEmail + "\"}"; @@ -70,6 +73,7 @@ void updateEmail() throws Exception { // when ResultActions result = mockMvc.perform(patch("/api/user/email") .requestAttr("githubId", githubId) + .header("Authorization", token) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)); @@ -87,6 +91,7 @@ void updateEmail() throws Exception { @Test void updateAlert() throws Exception { // given + String token = "Bearer testToken"; String githubId = "testUser"; boolean newAlertStatus = true; String requestBody = "{\"alertStatus\":" + newAlertStatus + "}"; @@ -94,6 +99,7 @@ void updateAlert() throws Exception { // when ResultActions result = mockMvc.perform(patch("/api/user/alert") .requestAttr("githubId", githubId) + .header("Authorization", token) .contentType(MediaType.APPLICATION_JSON) .content(requestBody)); @@ -110,12 +116,14 @@ void updateAlert() throws Exception { @DisplayName("사용자의 탈퇴가 정상적으로 이루어진다.") @Test void testWithdraw() throws Exception { + String token = "Bearer testToken"; String githubId = "testUser"; doNothing().when(userService).withdraw(githubId); mockMvc.perform(delete("/api/user/withdraw") - .requestAttr("githubId", githubId)) + .requestAttr("githubId", githubId) + .header("Authorization", token)) .andExpect(status().isOk()); verify(userService).withdraw(githubId); diff --git a/src/test/java/site/iris/issuefy/service/DashBoardServiceTest.java b/src/test/java/site/iris/issuefy/service/DashBoardServiceTest.java index af93cad5..85f753b5 100644 --- a/src/test/java/site/iris/issuefy/service/DashBoardServiceTest.java +++ b/src/test/java/site/iris/issuefy/service/DashBoardServiceTest.java @@ -24,114 +24,114 @@ class DashBoardServiceTest { - private static MockWebServer mockWebServer; - private DashBoardService dashBoardService; - private ObjectMapper objectMapper; - - @BeforeAll - static void setUp() throws IOException { - mockWebServer = new MockWebServer(); - mockWebServer.start(); - } - - @AfterAll - static void tearDown() throws IOException { - mockWebServer.shutdown(); - } - - @BeforeEach - void initialize() { - String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort()); - WebClient webClient = WebClient.create(baseUrl); - dashBoardService = new DashBoardService(webClient); - objectMapper = new ObjectMapper(); - } - - @Test - @DisplayName("Loki에서 대시보드 정보를 정상적으로 가져오는지 테스트한다.") - void getDashBoardFromLoki_ShouldReturnCorrectResponse() throws Exception { - // Given - LokiQueryVisitDto visitDto = new LokiQueryVisitDto(); - visitDto.setVisitCount("10"); - String visitJson = objectMapper.writeValueAsString(visitDto); - - LokiQueryAddRepositoryDto repoDto = new LokiQueryAddRepositoryDto(); - repoDto.setAddRepositoryCount("5"); - String repoJson = objectMapper.writeValueAsString(repoDto); - - mockWebServer.enqueue(new MockResponse() - .setBody(visitJson) - .addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse() - .setBody(repoJson) - .addHeader("Content-Type", "application/json")); - - // When - Mono result = dashBoardService.getDashBoardFromLoki("testUser"); - - // Then - StepVerifier.create(result) - .expectNextMatches(response -> { - assertEquals("10", response.getVisitCount()); - assertEquals("5", response.getAddRepositoryCount()); - assertNotNull(response.getRank()); - LocalDate today = LocalDate.now(); - assertEquals(today.minusDays(6), response.getStartDate()); - assertEquals(today, response.getEndDate()); - return true; - }) - .verifyComplete(); - } - - @Test - @DisplayName("Loki에서 빈 응답을 받았을 때 올바르게 처리하는지 테스트한다.") - void getDashBoardFromLoki_ShouldHandleEmptyResponses() { - // Given - mockWebServer.enqueue(new MockResponse() - .setBody("{}") - .addHeader("Content-Type", "application/json")); - mockWebServer.enqueue(new MockResponse() - .setBody("{}") - .addHeader("Content-Type", "application/json")); - - // When - Mono result = dashBoardService.getDashBoardFromLoki("testUser"); - - // Then - StepVerifier.create(result) - .expectNextMatches(response -> { - assertEquals("0", response.getVisitCount()); - assertEquals("0", response.getAddRepositoryCount()); - assertNotNull(response.getRank()); - LocalDate today = LocalDate.now(); - assertEquals(today.minusDays(6), response.getStartDate()); - assertEquals(today, response.getEndDate()); - return true; - }) - .verifyComplete(); - } - - @Test - @DisplayName("Loki에서 오류 응답을 받았을 때 올바르게 처리하는지 테스트한다.") - void getDashBoardFromLoki_ShouldHandleErrorResponses() { - // Given - mockWebServer.enqueue(new MockResponse().setResponseCode(500)); - mockWebServer.enqueue(new MockResponse().setResponseCode(500)); - - // When - Mono result = dashBoardService.getDashBoardFromLoki("testUser"); - - // Then - StepVerifier.create(result) - .expectNextMatches(response -> { - assertEquals("0", response.getVisitCount()); - assertEquals("0", response.getAddRepositoryCount()); - assertNotNull(response.getRank()); - LocalDate today = LocalDate.now(); - assertEquals(today.minusDays(6), response.getStartDate()); - assertEquals(today, response.getEndDate()); - return true; - }) - .verifyComplete(); - } + private static MockWebServer mockWebServer; + private DashBoardService dashBoardService; + private ObjectMapper objectMapper; + + @BeforeAll + static void setUp() throws IOException { + mockWebServer = new MockWebServer(); + mockWebServer.start(); + } + + @AfterAll + static void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @BeforeEach + void initialize() { + String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort()); + WebClient webClient = WebClient.create(baseUrl); + dashBoardService = new DashBoardService(webClient); + objectMapper = new ObjectMapper(); + } + + @Test + @DisplayName("Loki에서 대시보드 정보를 정상적으로 가져오는지 테스트한다.") + void getDashBoardFromLoki_ShouldReturnCorrectResponse() throws Exception { + // Given + LokiQueryVisitDto visitDto = new LokiQueryVisitDto(); + visitDto.setVisitCount("0"); + String visitJson = objectMapper.writeValueAsString(visitDto); + + LokiQueryAddRepositoryDto repoDto = new LokiQueryAddRepositoryDto(); + repoDto.setAddRepositoryCount("0"); + String repoJson = objectMapper.writeValueAsString(repoDto); + + mockWebServer.enqueue(new MockResponse() + .setBody(visitJson) + .addHeader("Content-Type", "application/json")); + mockWebServer.enqueue(new MockResponse() + .setBody(repoJson) + .addHeader("Content-Type", "application/json")); + + // When + Mono result = dashBoardService.getDashBoardFromLoki("testUser"); + + // Then + StepVerifier.create(result) + .expectNextMatches(response -> { + assertEquals("0", response.getVisitCount()); + assertEquals("0", response.getAddRepositoryCount()); + assertNotNull(response.getRank()); + LocalDate today = LocalDate.now(); + assertEquals(today.minusDays(6), response.getStartDate()); + assertEquals(today, response.getEndDate()); + return true; + }) + .verifyComplete(); + } + + @Test + @DisplayName("Loki에서 빈 응답을 받았을 때 올바르게 처리하는지 테스트한다.") + void getDashBoardFromLoki_ShouldHandleEmptyResponses() { + // Given + mockWebServer.enqueue(new MockResponse() + .setBody("{}") + .addHeader("Content-Type", "application/json")); + mockWebServer.enqueue(new MockResponse() + .setBody("{}") + .addHeader("Content-Type", "application/json")); + + // When + Mono result = dashBoardService.getDashBoardFromLoki("testUser"); + + // Then + StepVerifier.create(result) + .expectNextMatches(response -> { + assertEquals("0", response.getVisitCount()); + assertEquals("0", response.getAddRepositoryCount()); + assertNotNull(response.getRank()); + LocalDate today = LocalDate.now(); + assertEquals(today.minusDays(6), response.getStartDate()); + assertEquals(today, response.getEndDate()); + return true; + }) + .verifyComplete(); + } + + @Test + @DisplayName("Loki에서 오류 응답을 받았을 때 올바르게 처리하는지 테스트한다.") + void getDashBoardFromLoki_ShouldHandleErrorResponses() { + // Given + mockWebServer.enqueue(new MockResponse().setResponseCode(500)); + mockWebServer.enqueue(new MockResponse().setResponseCode(500)); + + // When + Mono result = dashBoardService.getDashBoardFromLoki("testUser"); + + // Then + StepVerifier.create(result) + .expectNextMatches(response -> { + assertEquals("0", response.getVisitCount()); + assertEquals("0", response.getAddRepositoryCount()); + assertNotNull(response.getRank()); + LocalDate today = LocalDate.now(); + assertEquals(today.minusDays(6), response.getStartDate()); + assertEquals(today, response.getEndDate()); + return true; + }) + .verifyComplete(); + } } \ No newline at end of file