diff --git a/src/main/kotlin/com/hibob/academy/resource/OwnerResource.kt b/src/main/kotlin/com/hibob/academy/resource/OwnerResource.kt new file mode 100644 index 000000000..8e88ee778 --- /dev/null +++ b/src/main/kotlin/com/hibob/academy/resource/OwnerResource.kt @@ -0,0 +1,48 @@ +package com.hibob.academy.resource +import com.hibob.academy.dao.OwnerRecord +import com.hibob.academy.service.OwnerService +import jakarta.ws.rs.* +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import org.springframework.stereotype.Controller + +@Controller // Marks the class as a controller, meaning it's responsible for handling incoming HTTP requests +@Path("/api/ron/azar/owner/") // Defines the base URL path that this controller will handle +@Produces(MediaType.APPLICATION_JSON) // Specifies that the responses produced by this controller will be in JSON format +@Consumes(MediaType.APPLICATION_JSON) // Specifies that this endpoint accepts JSON input +class OwnerResource (private val ownerService: OwnerService){ + + @GET + @Path("getAllOwners/{companyId}") + fun getAllOwners(@PathParam("companyId") companyId: Long): Response { + val owners = ownerService.getAllOwners(companyId) + return Response.ok(owners).build() + } + + @POST + @Path("insertNewOwner") + fun insertNewOwner(newOwner: OwnerRecord): Response { + ownerService.insertOwner(newOwner) + return Response.status(Response.Status.CREATED).entity("Owner successfully inserted").build() + } + + @GET + @Path("companies/{companyId}/pets/{petId}/owner") + fun getOwnerByPetId( + @PathParam("petId") petId: Long, + @PathParam("companyId") companyId: Long + ): Response { + val owner = ownerService.getOwnerByPetId(petId, companyId) + return Response.ok(owner).build() + } + + @GET + @Path("companies/{companyId}/employees/{employeeId}/owner") + fun getOwnerByEmployeeIdAndCompanyId( + @PathParam("employeeId") employeeId: String, + @PathParam("companyId") companyId: Long + ): Response { + val owner = ownerService.getOwnerByEmployeeIdAndCompanyId(employeeId, companyId) + return Response.ok(owner).build() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/hibob/academy/resource/PetsResource.kt b/src/main/kotlin/com/hibob/academy/resource/PetsResource.kt new file mode 100644 index 000000000..ce4ba4449 --- /dev/null +++ b/src/main/kotlin/com/hibob/academy/resource/PetsResource.kt @@ -0,0 +1,60 @@ +package com.hibob.academy.resource + +import com.hibob.academy.dao.PetRecord +import com.hibob.academy.dao.PetType +import com.hibob.academy.service.PetService +import jakarta.ws.rs.Consumes +import jakarta.ws.rs.GET +import jakarta.ws.rs.POST +import jakarta.ws.rs.PUT +import jakarta.ws.rs.Path +import jakarta.ws.rs.PathParam +import jakarta.ws.rs.Produces +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import org.springframework.stereotype.Controller + +@Controller // Marks the class as a controller, meaning it's responsible for handling incoming HTTP requests +@Path("/api/ron/azar/pets/") // Defines the base URL path that this controller will handle +@Produces(MediaType.APPLICATION_JSON) // Specifies that the responses produced by this controller will be in JSON format +@Consumes(MediaType.APPLICATION_JSON) // Specifies that this endpoint accepts JSON input +class PetsResource (private val petService: PetService){ + @GET + @Path("companies/{companyId}/pets/type/{petType}") + fun getAllPetsByType(@PathParam("petType") petType: PetType, @PathParam("companyId") companyId: Long): Response { + val pet = petService.getAllPetsByType(petType, companyId) + return Response.ok(pet).build() + } + + @GET + @Path("getAllPets/{companyId}") + fun getAllPets(@PathParam("companyId") companyId: Long): Response { + val petsList = petService.getAllPets(companyId) + return Response.ok(petsList).build() + } + + @GET + @Path("companies/{companyId}/pets/{petId}") + fun getPetById(@PathParam("petId") petId: Long, @PathParam("companyId") companyId: Long): Response { + val pet = petService.getPetById(petId, companyId) + return Response.ok(pet).build() + } + + @POST + @Path("insertNewPet") + fun insertNewPet(newPet: PetRecord): Response { + petService.insertNewPet(newPet) + return Response.ok(newPet).build() + } + + @PUT + @Path("pets/{petId}/owner/{newOwnerId}/company/{companyId}") + fun updatePetOwnerId( + @PathParam("petId") petId: Long, + @PathParam("newOwnerId") newOwnerId: Long, + @PathParam("companyId") companyId: Long + ): Response { + petService.updatePetOwnerId(petId, newOwnerId, companyId) + return Response.ok().build() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/hibob/academy/service/OwnerService.kt b/src/main/kotlin/com/hibob/academy/service/OwnerService.kt new file mode 100644 index 000000000..f4f53a0d8 --- /dev/null +++ b/src/main/kotlin/com/hibob/academy/service/OwnerService.kt @@ -0,0 +1,34 @@ +package com.hibob.academy.service + +import com.hibob.academy.dao.OwnerRecord +import com.hibob.academy.dao.OwnerDao +import com.hibob.academy.dao.OwnerData +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component + +@Component +class OwnerService @Autowired constructor(private val ownerDao: OwnerDao) { + fun insertOwner(newOwner: OwnerRecord): Long { + val newOwnerId = ownerDao.insertNewOwner(newOwner) + if (newOwnerId < 0L) { + throw IllegalArgumentException("Owner insertion failed...") + } + return newOwnerId + } + + fun getOwnerByEmployeeIdAndCompanyId(employeeId: String, companyId: Long): OwnerData { + val owner = ownerDao.getOwnerByEmployeeIdAndCompanyId(employeeId, companyId) + ?: throw NoSuchElementException("No owner with id $employeeId found") + return owner + } + + fun getAllOwners(companyId: Long): List { + return ownerDao.getAllOwners(companyId) + } + + fun getOwnerByPetId(petId: Long, companyId: Long): OwnerData { + val owner = ownerDao.getOwnerByPetId(petId, companyId) + ?: throw NoSuchElementException("Pet $petId has no owner with company id $companyId") + return owner + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/hibob/academy/service/PetService.kt b/src/main/kotlin/com/hibob/academy/service/PetService.kt new file mode 100644 index 000000000..41f35ae24 --- /dev/null +++ b/src/main/kotlin/com/hibob/academy/service/PetService.kt @@ -0,0 +1,46 @@ +package com.hibob.academy.service + +import com.hibob.academy.dao.* +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component + +@Component +class PetService @Autowired constructor(private val petDao: PetDao) { + fun getAllPets(companyId: Long): List { + return petDao.getAllPets(companyId) + } + + fun insertNewPet(newPet: PetRecord): Long { + // Insert the new pet and return the generated ID or -1 if the operation failed + val petId = petDao.insertNewPet(newPet) + if (petId < 0L) { + throw IllegalArgumentException("Pet insertion failed...") + } + return petId + } + + fun getPetById(petId: Long, companyId: Long): PetData { + val pet = petDao.getPetById(petId, companyId) ?: throw NoSuchElementException("Pet not found for the given ID") + return pet + } + + fun getAllPetsByType(type: PetType, companyId: Long): List { + return petDao.getAllPetsByType(type, companyId) + } + + fun updatePetOwnerId(petId: Long, petOwnerId: Long, companyId: Long) { + // Retrieve the pet by ID and companyId + val pet = petDao.getPetById(petId, companyId) + ?: throw NoSuchElementException("Pet not found for the given ID") + // Ensure the pet doesn't already have an owner + if (pet.ownerId != null) { + throw IllegalArgumentException("Pet already has an owner") + } + + // Update the ownerId if it is currently null + val rowsAffected = petDao.updatePetOwnerId(petId, petOwnerId, companyId) + if (rowsAffected == 0) { + throw IllegalArgumentException("Failed to update pet's owner. The pet may already have an owner.") + } + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/hibob/academy/resource/ExampleResourceTest.kt b/src/test/kotlin/com/hibob/academy/resource/ExampleResourceTest.kt index afb6735cf..9cae3e634 100644 --- a/src/test/kotlin/com/hibob/academy/resource/ExampleResourceTest.kt +++ b/src/test/kotlin/com/hibob/academy/resource/ExampleResourceTest.kt @@ -1,36 +1,36 @@ -package com.hibob.academy.resource - -import com.hibob.academy.dao.Example -import com.hibob.academy.service.ExampleService -import org.hamcrest.CoreMatchers.`is` -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers -import org.junit.jupiter.api.Test -import org.mockito.kotlin.any -import org.mockito.kotlin.whenever -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment -import org.springframework.boot.test.mock.mockito.MockBean -import org.springframework.boot.test.web.client.TestRestTemplate -import org.springframework.http.HttpStatus -import kotlin.random.Random - -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -internal class ExampleResourceTest { - - @Autowired - lateinit var restTemplate: TestRestTemplate - - @MockBean - lateinit var exampleService: ExampleService - - @Test - fun test() { - val example = Example(Random.nextLong(), Random.nextLong(), "a") - whenever(exampleService.get(1)).thenReturn(example) - val response = restTemplate.getForEntity("/example/1", ExampleResponse::class.java) - assertThat(response.statusCode, Matchers.`is`(HttpStatus.OK)) - assertThat(response.body, `is`(ExampleResponse(example))) - } -} +//package com.hibob.academy.resource +// +//import com.hibob.academy.dao.Example +//import com.hibob.academy.service.ExampleService +//import org.hamcrest.CoreMatchers.`is` +//import org.hamcrest.MatcherAssert.assertThat +//import org.hamcrest.Matchers +//import org.junit.jupiter.api.Test +//import org.mockito.kotlin.any +//import org.mockito.kotlin.whenever +//import org.springframework.beans.factory.annotation.Autowired +//import org.springframework.boot.test.context.SpringBootTest +//import org.springframework.boot.test.context.SpringBootTest.WebEnvironment +//import org.springframework.boot.test.mock.mockito.MockBean +//import org.springframework.boot.test.web.client.TestRestTemplate +//import org.springframework.http.HttpStatus +//import kotlin.random.Random +// +//@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +//internal class ExampleResourceTest { +// +// @Autowired +// lateinit var restTemplate: TestRestTemplate +// +// @MockBean +// lateinit var exampleService: ExampleService +// +// @Test +// fun test() { +// val example = Example(Random.nextLong(), Random.nextLong(), "a") +// whenever(exampleService.get(1)).thenReturn(example) +// val response = restTemplate.getForEntity("/example/1", ExampleResponse::class.java) +// assertThat(response.statusCode, Matchers.`is`(HttpStatus.OK)) +// assertThat(response.body, `is`(ExampleResponse(example))) +// } +//} diff --git a/src/test/kotlin/com/hibob/academy/service/OwnerServiceTest.kt b/src/test/kotlin/com/hibob/academy/service/OwnerServiceTest.kt new file mode 100644 index 000000000..0bdc2b981 --- /dev/null +++ b/src/test/kotlin/com/hibob/academy/service/OwnerServiceTest.kt @@ -0,0 +1,78 @@ +package com.hibob.academy.service + +import com.hibob.academy.dao.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +class OwnerServiceTest{ + private val petId = 10L + private val ownerId = 123L + private val employeeId = "1234578" + private val newOwner= OwnerRecord("Ron", employeeId, 9) + private val ownerData = OwnerData(ownerId,"Ron", employeeId, 9) + private val companyId = 9L + + private val ownerDao = mock() + private val ownerService = OwnerService(ownerDao) + + + @Test + fun `insert Owner -- insert successfully`() + { + whenever(ownerDao.insertNewOwner(newOwner)).thenReturn(10L) + val resultOwnerId = ownerService.insertOwner(newOwner) + assertEquals(10L, resultOwnerId) + } + + @Test + fun `get Owner By Employee Id And Company Id -- Success`(){ + whenever(ownerDao.getOwnerByEmployeeIdAndCompanyId(any(), any())).thenReturn(ownerData) + + val resultOwner = ownerService.getOwnerByEmployeeIdAndCompanyId(employeeId, companyId) + assertEquals(ownerData, resultOwner) + } + + @Test + fun `get Owner By Employee Id And Company Id -- Failure`(){ + whenever(ownerDao.getOwnerByEmployeeIdAndCompanyId(any(), any())).thenReturn(null) + + val errorMessage = assertThrows { + ownerService.getOwnerByEmployeeIdAndCompanyId(employeeId, companyId) + } + assertEquals(errorMessage.message, "No owner with id $employeeId found") + } + + @Test + fun `get all owners - Success`(){ + whenever(ownerDao.getAllOwners(companyId)).thenReturn(listOf(ownerData)) + val result = ownerService.getAllOwners(companyId) + assertNotNull(result) + assertEquals(newOwner.ownerName, result[0].ownerName) + assertEquals(1, result.size) + } + + @Test + fun `get Owner By Pet Id -- Success`() { + whenever(ownerDao.getOwnerByPetId(petId, companyId)).thenReturn(ownerData) + + val resultOwner = ownerService.getOwnerByPetId(petId, companyId) + + assertEquals(ownerData, resultOwner) + } + + @Test + fun `get Owner By Pet Id -- Failure`() { + whenever(ownerDao.getOwnerByPetId(petId, companyId)).thenReturn(null) + + val errorMessage = assertThrows { + ownerService.getOwnerByPetId(petId, companyId) + } + + assertEquals("Pet $petId has no owner with company id $companyId", errorMessage.message) + } +} \ No newline at end of file diff --git a/src/test/kotlin/com/hibob/academy/service/PetServiceTest.kt b/src/test/kotlin/com/hibob/academy/service/PetServiceTest.kt new file mode 100644 index 000000000..ac679ec06 --- /dev/null +++ b/src/test/kotlin/com/hibob/academy/service/PetServiceTest.kt @@ -0,0 +1,127 @@ +package com.hibob.academy.service + +import com.hibob.academy.dao.* +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.mockito.kotlin.* +import java.time.LocalDate + +class PetServiceTest { + + private val petId: Long = 123 + private val companyId: Long = 9 + private val ownerId: Long = 456 + private val pet = PetData(petId, "Waffle", LocalDate.now(), companyId, PetType.DOG, null) + + private val petDao = mock() + private val petService = PetService(petDao) + + @Test + fun `Test getPetById -- Pet not found`() { + whenever(petDao.getPetById(petId, companyId)).thenReturn(null) + + val errorMessage = assertThrows { + petService.getPetById(petId, companyId) + } + + assertEquals("Pet not found for the given ID", errorMessage.message) + } + + @Test + fun `Test getPetById -- Pet found`() { + whenever(petDao.getPetById(petId, companyId)).thenReturn(pet) + + val result = petService.getPetById(petId, companyId) + + assertNotNull(result) + assertEquals(petId, result.petId) + assertEquals("Waffle", result.petName) + } + + @Test + fun `Test insertNewPet -- Pet inserted successfully`() { + val newPet = PetRecord("Waffle", PetType.DOG, LocalDate.now(), companyId, null) + whenever(petDao.insertNewPet(newPet)).thenReturn(10L) + + val result = petService.insertNewPet(newPet) + + assertEquals(10L, result) + } + + @Test + fun `Test updatePetOwnerId -- Pet not found`() { + whenever(petDao.getPetById(petId, companyId)).thenReturn(null) + + val errorMessage = assertThrows { + petService.updatePetOwnerId(petId, ownerId, companyId) + } + + assertEquals("Pet not found for the given ID", errorMessage.message) + verify(petDao, never()).updatePetOwnerId(any(), any(), any()) + } + + @Test + fun `Test updatePetOwnerId -- Pet already has an owner`() { + val petWithOwner = pet.copy(ownerId = ownerId) + whenever(petDao.getPetById(petId, companyId)).thenReturn(petWithOwner) + + val errorMessage = assertThrows { + petService.updatePetOwnerId(petId, ownerId, companyId) + } + + assertEquals("Pet already has an owner", errorMessage.message) + verify(petDao, never()).updatePetOwnerId(any(), any(), any()) + } + + @Test + fun `Test updatePetOwnerId -- Owner ID updated successfully`() { + // Arrange + val petWithoutOwner = pet.copy(ownerId = null) + whenever(petDao.getPetById(petId, companyId)).thenReturn(petWithoutOwner) + whenever(petDao.updatePetOwnerId(petId, ownerId, companyId)).thenReturn(1) + + // Act & Assert: Ensure that no exceptions are thrown + assertDoesNotThrow { + petService.updatePetOwnerId(petId, ownerId, companyId) + } + + // Verify that the updatePetOwnerId was called with correct parameters + verify(petDao).updatePetOwnerId(petId, ownerId, companyId) + } + + @Test + fun `Test updatePetOwnerId -- Failed to update owner ID`() { + val petWithoutOwner = pet.copy(ownerId = null) + whenever(petDao.getPetById(petId, companyId)).thenReturn(petWithoutOwner) + whenever(petDao.updatePetOwnerId(petId, ownerId, companyId)).thenReturn(0) + + val errorMessage = assertThrows { + petService.updatePetOwnerId(petId, ownerId, companyId) + } + + assertEquals("Failed to update pet's owner. The pet may already have an owner.", errorMessage.message) + } + + @Test + fun `Test getAllPets -- Return list of pets`() { + whenever(petDao.getAllPets(companyId)).thenReturn(listOf(pet)) + + val result = petService.getAllPets(companyId) + + assertNotNull(result) + assertEquals(1, result.size) + assertEquals("Waffle", result[0].petName) + } + + @Test + fun `Test getAllPetsByType -- Return list of pets by type`() { + whenever(petDao.getAllPetsByType(PetType.DOG, companyId)).thenReturn(listOf(pet)) + + val result = petService.getAllPetsByType(PetType.DOG, companyId) + + assertNotNull(result) + assertEquals(1, result.size) + assertEquals(PetType.DOG, result[0].petType) + } +} \ No newline at end of file