Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 도서관 남은 좌석 API 구현 #387

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.ku_stacks.ku_ring.domain

data class LibraryRoom(
val name: String,
val totalSeats: Int,
val occupiedSeats: Int,
val availableSeats: Int,
)
1 change: 1 addition & 0 deletions data/library/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
26 changes: 26 additions & 0 deletions data/library/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.ku_stacks.ku_ring.buildlogic.dsl.setNameSpace

plugins {
kuring("feature")
kuringPrimitive("retrofit")
kuringPrimitive("test")
}
Comment on lines +3 to +7
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 이해하기 어렵지 않았나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 아직 제대로 이해하진 못했어요,,
저 플러그인들에 필요한 라이브러리들이 있겠거니 해서 일단 넣었습니다😅

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋ이것도 강의 해줄게요


android {
setNameSpace("library")
l2hyunwoo marked this conversation as resolved.
Show resolved Hide resolved
compileSdk = 34

testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}

dependencies {
implementation(projects.core.util)
implementation(projects.data.domain)
implementation(projects.data.remote)

testImplementation(libs.kotlinx.coroutines.test)
}
Empty file added data/library/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions data/library/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
4 changes: 4 additions & 0 deletions data/library/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.ku_stacks.ku_ring.library.di

import com.ku_stacks.ku_ring.library.repository.LibraryRepository
import com.ku_stacks.ku_ring.library.repository.LibraryRepositoryImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
@Module
abstract class RepositoryModule {
@Binds
@Singleton
abstract fun provideLibraryRepository(repositoryImpl: LibraryRepositoryImpl): LibraryRepository

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.ku_stacks.ku_ring.library.mapper

import com.ku_stacks.ku_ring.domain.LibraryRoom
import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse

fun LibrarySeatResponse.toLibraryAreaList(): List<LibraryRoom> {
return data.libraryRooms.map {
LibraryRoom(
name = it.roomName,
totalSeats = it.seats.total,
availableSeats = it.seats.available,
occupiedSeats = it.seats.occupied
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ku_stacks.ku_ring.library.repository

import com.ku_stacks.ku_ring.domain.LibraryRoom

interface LibraryRepository {
suspend fun getRemainingSeats(): Result<List<LibraryRoom>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.library.repository

import com.ku_stacks.ku_ring.domain.LibraryRoom
import com.ku_stacks.ku_ring.library.mapper.toLibraryAreaList
import com.ku_stacks.ku_ring.remote.library.LibraryClient
import javax.inject.Inject

class LibraryRepositoryImpl @Inject constructor(
private val libraryClient: LibraryClient
) : LibraryRepository {
override suspend fun getRemainingSeats(): Result<List<LibraryRoom>> = runCatching {
libraryClient.fetchRoomSeatStatus().toLibraryAreaList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.ku_stacks.ku_ring.library

import com.ku_stacks.ku_ring.library.repository.LibraryRepository
import com.ku_stacks.ku_ring.library.repository.LibraryRepositoryImpl
import com.ku_stacks.ku_ring.remote.library.LibraryClient
import junit.framework.TestCase.assertEquals
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito
import org.mockito.kotlin.times

class LibraryRepositoryTest {
private lateinit var libraryRepository: LibraryRepository
private val client: LibraryClient = Mockito.mock(LibraryClient::class.java)

@Before
fun setup() {
libraryRepository = LibraryRepositoryImpl(client)
}

@Test
fun `get Library Seat Status From Remote Test`() = runTest {
val mockLibraryStatus = LibraryTestUtil.mockLibrarySeatResponse()

Mockito.`when`(client.fetchRoomSeatStatus()).thenReturn(mockLibraryStatus)
Comment on lines +15 to +26
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굳이 Mock을 사용할 필요가 있을까요? 인터페이스 다형성을 활용해보면 좋을 것 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 테스트 코드 작성이 아직 미흡해서 기존 테스트 코드를 좀 차용했습니다..
추후에 좀 더 괜찮은 방법으로 테스트 코드를 작성해보도록 할게요!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 좋습니다.


libraryRepository.getRemainingSeats().onSuccess { mockResult ->
val expectedResult = LibraryTestUtil.mockLibraryRoomList()

Mockito.verify(
client,
times(1)
).fetchRoomSeatStatus()

assertEquals(mockResult, expectedResult)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.ku_stacks.ku_ring.library

import com.ku_stacks.ku_ring.domain.LibraryRoom
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomBranchResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomListResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomSeatResponse
import com.ku_stacks.ku_ring.remote.library.response.LibraryRoomTypeResponse
import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse

object LibraryTestUtil {
fun mockLibrarySeatResponse() = LibrarySeatResponse(
success = true,
code = "success.retrieved",
message = "조회되었습니다.",
data = LibraryRoomListResponse(
resultCount = 1,
libraryRooms = listOf(
LibraryRoomResponse(
id = 102,
roomName = "제 1 열람실 (A구역)",
roomType = LibraryRoomTypeResponse(
id = 1,
roomName = "열람실",
sortOrder = 1
),
awaitable = true,
isChargeable = true,
branch = LibraryRoomBranchResponse(
id = 1,
roomBranchName = "상허기념도서관",
alias = "상허",
libraryCode = "211004",
sortOrder = 1
),
unableMessage = null,
seats = LibraryRoomSeatResponse(
total = 219,
occupied = 82,
waiting = 0,
available = 137
)
)
)
)
)


fun mockLibraryRoomList() = listOf(
LibraryRoom(
name = "제 1 열람실 (A구역)",
totalSeats = 219,
occupiedSeats = 82,
availableSeats = 137
)
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library

import com.ku_stacks.ku_ring.remote.library.request.LibrarySeatRequest
import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse
import javax.inject.Inject

class LibraryClient @Inject constructor(private val libraryService: LibraryService) {

suspend fun fetchRoomSeatStatus(): LibrarySeatResponse = libraryService.fetchLibrarySeatStatus(
methodCode = LibrarySeatRequest.METHOD_CODE,
roomTypeId = LibrarySeatRequest.ROOM_TYPE_ID,
branchTypeId = LibrarySeatRequest.BRANCH_TYPE_ID,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library

import com.ku_stacks.ku_ring.remote.library.response.LibrarySeatResponse
import retrofit2.http.GET
import retrofit2.http.Query

interface LibraryService {
@GET("1/seat-rooms")
suspend fun fetchLibrarySeatStatus(
@Query("smufMethodCode") methodCode: String,
@Query("roomTypeId") roomTypeId: Int,
@Query("branchTypeId") branchTypeId: Int,
): LibrarySeatResponse
mwy3055 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.ku_stacks.ku_ring.remote.library.di

import com.ku_stacks.ku_ring.remote.library.LibraryClient
import com.ku_stacks.ku_ring.remote.library.LibraryService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import retrofit2.Retrofit
import javax.inject.Named
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object LibraryModule {
@Provides
@Singleton
fun provideLibraryService(@Named("Library") retrofit: Retrofit): LibraryService
= retrofit.create(LibraryService::class.java)

@Provides
@Singleton
fun provideLibraryClient(libraryService: LibraryService): LibraryClient
= LibraryClient(libraryService)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ku_stacks.ku_ring.remote.library.request

object LibrarySeatRequest {
const val METHOD_CODE: String = "PC"
const val ROOM_TYPE_ID = 4
const val BRANCH_TYPE_ID: Int = 1
}
mwy3055 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomBranchResponse (
@SerializedName("id")
val id: Int,
@SerializedName("name")
val roomBranchName: String,
@SerializedName("alias")
val alias: String,
@SerializedName("libraryCode")
val libraryCode: String,
@SerializedName("sortOrder")
val sortOrder: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomListResponse(
@SerializedName(value = "totalCount")
val resultCount: Int,
@SerializedName(value = "list")
val libraryRooms: List<LibraryRoomResponse>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomResponse(
@SerializedName("id")
val id: Int,
@SerializedName("name")
val roomName: String,
@SerializedName("roomType")
val roomType: LibraryRoomTypeResponse,
@SerializedName("awaitable")
val awaitable: Boolean,
@SerializedName("isChargeable")
val isChargeable: Boolean,
@SerializedName("branch")
val branch: LibraryRoomBranchResponse,
@SerializedName("unableMessage")
val unableMessage: String?,
@SerializedName("seats")
val seats: LibraryRoomSeatResponse,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomSeatResponse(
@SerializedName("total")
val total: Int,
@SerializedName("occupied")
val occupied: Int,
@SerializedName("waiting")
val waiting: Int,
@SerializedName("available")
val available: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibraryRoomTypeResponse(
@SerializedName("id")
val id: Int,
@SerializedName("name")
val roomName: String,
@SerializedName("sortOrder")
val sortOrder: Int,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ku_stacks.ku_ring.remote.library.response

import com.google.gson.annotations.SerializedName

data class LibrarySeatResponse(
@SerializedName("success")
val success: Boolean,
@SerializedName("code")
val code: String,
@SerializedName("message")
val message: String,
@SerializedName("data")
val data: LibraryRoomListResponse,
)
Loading