Skip to content
This repository was archived by the owner on Nov 23, 2025. It is now read-only.
Merged

Dev #12

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f7bbf51
chore: trigger GitOps pipeline (empty commit)
RandithaK Nov 15, 2025
3dff8ae
Merge pull request #10 from TechTorque-2025/feat/gitops-workflow
RandithaK Nov 21, 2025
cf20f65
Add unit tests for VehiclePhoto and Vehicle repositories, and impleme…
AdithaBuwaneka Nov 21, 2025
c611586
test: Add unit tests for PhotoStorageServiceImpl methods
AdithaBuwaneka Nov 21, 2025
3ca6438
test: Add integration tests for VehicleController to validate vehicle…
AdithaBuwaneka Nov 21, 2025
1eae636
Remove unit tests for VehicleRepository, PhotoStorageServiceImpl, and…
AdithaBuwaneka Nov 21, 2025
3208343
test: Add comprehensive unit and integration tests for VehicleControl…
AdithaBuwaneka Nov 21, 2025
1879218
test: Refactor updateVehicle test to use builder pattern for updatedV…
AdithaBuwaneka Nov 21, 2025
ea8d5b5
fix: Remove unused import for EntityNotFoundException in VehicleServi…
AdithaBuwaneka Nov 21, 2025
ab410c9
test: Update VehiclePhoto creation in VehiclePhotoRepositoryTest to u…
AdithaBuwaneka Nov 21, 2025
99a7ce3
test: Update VehiclePhoto creation in VehiclePhotoRepositoryTest to u…
AdithaBuwaneka Nov 21, 2025
6b3d33f
test: Update assertions in VehiclePhotoRepositoryTest to reflect chan…
AdithaBuwaneka Nov 21, 2025
642b041
test: Update ServiceHistoryDto fields in VehicleControllerTest for im…
AdithaBuwaneka Nov 21, 2025
dfc0a90
test: Refactor Vehicle update test to use builder pattern for improve…
AdithaBuwaneka Nov 21, 2025
9c15304
test: Update VehiclePhoto creation in VehicleControllerTest to use ve…
AdithaBuwaneka Nov 21, 2025
b1d1573
test: Update deleteByIdAndCustomerId test to verify vehicle existence…
AdithaBuwaneka Nov 21, 2025
329132d
test: Refactor VehicleServiceTest for improved readability and mainta…
AdithaBuwaneka Nov 21, 2025
71574d7
test: Update VehiclePhoto creation in VehiclePhotoRepositoryTest to u…
AdithaBuwaneka Nov 21, 2025
66b6d1e
fix: Update Vehicle model_year column annotation and clean up ID gene…
AdithaBuwaneka Nov 21, 2025
7406236
test: Add verification for generated ID in VehiclePhoto save test
AdithaBuwaneka Nov 21, 2025
50f2b7d
test: Update VehicleControllerTest and VehicleEntityTest for improved…
AdithaBuwaneka Nov 21, 2025
1844f2a
test: Update VehicleControllerTest to use vehicleId instead of id in …
AdithaBuwaneka Nov 21, 2025
fc15358
Merge pull request #11 from TechTorque-2025/Vehicle-service-mvn-test
AdithaBuwaneka Nov 21, 2025
c7ce65b
fix: Remove name attribute from model_year column annotation in Vehic…
RandithaK Nov 21, 2025
3430677
fix: Update model_year column annotation in Vehicle entity for clarity
RandithaK Nov 21, 2025
812d334
fix: Remove name attribute from model_year column annotation in Vehic…
RandithaK Nov 21, 2025
11343d1
Merge branch 'main' into dev
RandithaK Nov 23, 2025
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
Expand Up @@ -62,16 +62,16 @@ public void generateId() {
if (this.id == null || this.id.isEmpty()) {
// Generate a sequential number (using UUID last 4 chars as pseudo-random)
String randomSuffix = UUID.randomUUID().toString().substring(0, 4).toUpperCase();

// Clean make and model (remove spaces, convert to uppercase)
String cleanMake = this.make.replaceAll("[^A-Za-z0-9]", "").toUpperCase();
String cleanModel = this.model.replaceAll("[^A-Za-z0-9]", "").toUpperCase();

// Format: VEH-YYYY-MAKE-MODEL-####
this.id = String.format("VEH-%d-%s-%s-%s",
this.year,
cleanMake,
cleanModel,
this.id = String.format("VEH-%d-%s-%s-%s",
this.year,
cleanMake,
cleanModel,
randomSuffix);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
package com.techtorque.vehicle_service.controller;

import com.techtorque.vehicle_service.dto.*;
import com.techtorque.vehicle_service.entity.Vehicle;
import com.techtorque.vehicle_service.entity.VehiclePhoto;
import com.techtorque.vehicle_service.exception.VehicleNotFoundException;
import com.techtorque.vehicle_service.mapper.VehicleMapper;
import com.techtorque.vehicle_service.service.PhotoStorageService;
import com.techtorque.vehicle_service.service.ServiceHistoryService;
import com.techtorque.vehicle_service.service.VehicleService;
import com.fasterxml.jackson.databind.ObjectMapper;
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.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(VehicleController.class)
class VehicleControllerTest {

@Autowired
private MockMvc mockMvc;

@Autowired
private ObjectMapper objectMapper;

@MockBean
private VehicleService vehicleService;

@MockBean
private PhotoStorageService photoStorageService;

@MockBean
private ServiceHistoryService serviceHistoryService;

private Vehicle testVehicle;
private VehicleRequestDto validRequest;
private VehicleUpdateDto validUpdate;

@BeforeEach
void setUp() {
testVehicle = Vehicle.builder()
.id("VEH-123")
.customerId("CUST-123")
.make("Toyota")
.model("Camry")
.year(2022)
.vin("1HGBH41JXMN109186")
.licensePlate("ABC123")
.color("Silver")
.mileage(15000)
.build();

validRequest = VehicleRequestDto.builder()
.make("Toyota")
.model("Camry")
.year(2022)
.vin("1HGBH41JXMN109186")
.licensePlate("ABC123")
.color("Silver")
.mileage(15000)
.build();

validUpdate = VehicleUpdateDto.builder()
.mileage(20000)
.color("Blue")
.build();
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testRegisterNewVehicle_Success() throws Exception {
when(vehicleService.registerVehicle(any(VehicleRequestDto.class), eq("CUST-123")))
.thenReturn(testVehicle);

mockMvc.perform(post("/vehicles")
.with(csrf())
.header("X-User-Subject", "CUST-123")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(validRequest)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.message").value("Vehicle added"))
.andExpect(jsonPath("$.vehicleId").value("VEH-123"));

verify(vehicleService).registerVehicle(any(VehicleRequestDto.class), eq("CUST-123"));
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testListCustomerVehicles_Customer() throws Exception {
List<Vehicle> vehicles = Arrays.asList(testVehicle);
when(vehicleService.getVehiclesForCustomer("CUST-123")).thenReturn(vehicles);

mockMvc.perform(get("/vehicles")
.header("X-User-Subject", "CUST-123")
.header("X-User-Roles", "CUSTOMER"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.length()").value(1))
.andExpect(jsonPath("$[0].vehicleId").value("VEH-123"));

verify(vehicleService).getVehiclesForCustomer("CUST-123");
}

@Test
@WithMockUser(roles = { "ADMIN" })
void testListCustomerVehicles_Admin() throws Exception {
List<Vehicle> vehicles = Arrays.asList(testVehicle);
when(vehicleService.getAllVehicles()).thenReturn(vehicles);

mockMvc.perform(get("/vehicles")
.header("X-User-Subject", "ADMIN-123")
.header("X-User-Roles", "ADMIN"))
.andExpect(status().isOk());

verify(vehicleService).getAllVehicles();
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testGetVehicleDetails_Success() throws Exception {
when(vehicleService.getVehicleByIdAndCustomer("VEH-123", "CUST-123"))
.thenReturn(Optional.of(testVehicle));

mockMvc.perform(get("/vehicles/VEH-123")
.header("X-User-Subject", "CUST-123")
.header("X-User-Roles", "CUSTOMER"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.vehicleId").value("VEH-123"))
.andExpect(jsonPath("$.make").value("Toyota"));

verify(vehicleService).getVehicleByIdAndCustomer("VEH-123", "CUST-123");
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testGetVehicleDetails_NotFound() throws Exception {
when(vehicleService.getVehicleByIdAndCustomer("VEH-123", "CUST-123"))
.thenReturn(Optional.empty());

mockMvc.perform(get("/vehicles/VEH-123")
.header("X-User-Subject", "CUST-123")
.header("X-User-Roles", "CUSTOMER"))
.andExpect(status().isNotFound());

verify(vehicleService).getVehicleByIdAndCustomer("VEH-123", "CUST-123");
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testUpdateVehicleInfo_Success() throws Exception {
Vehicle updatedVehicle = Vehicle.builder()
.id(testVehicle.getId())
.customerId(testVehicle.getCustomerId())
.make(testVehicle.getMake())
.model(testVehicle.getModel())
.year(testVehicle.getYear())
.vin(testVehicle.getVin())
.licensePlate(testVehicle.getLicensePlate())
.mileage(20000)
.color("Blue")
.build();

when(vehicleService.updateVehicle(eq("VEH-123"), any(VehicleUpdateDto.class), eq("CUST-123")))
.thenReturn(updatedVehicle);

mockMvc.perform(put("/vehicles/VEH-123")
.with(csrf())
.header("X-User-Subject", "CUST-123")
.header("X-User-Roles", "CUSTOMER")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(validUpdate)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Vehicle updated"))
.andExpect(jsonPath("$.vehicleId").value("VEH-123"));

verify(vehicleService).updateVehicle(eq("VEH-123"), any(VehicleUpdateDto.class), eq("CUST-123"));
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testRemoveVehicle_Success() throws Exception {
doNothing().when(vehicleService).deleteVehicle("VEH-123", "CUST-123");
doNothing().when(photoStorageService).deleteVehiclePhotos("VEH-123");

mockMvc.perform(delete("/vehicles/VEH-123")
.with(csrf())
.header("X-User-Subject", "CUST-123")
.header("X-User-Roles", "CUSTOMER"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Vehicle removed"))
.andExpect(jsonPath("$.vehicleId").value("VEH-123"));

verify(vehicleService).deleteVehicle("VEH-123", "CUST-123");
verify(photoStorageService).deleteVehiclePhotos("VEH-123");
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testGetVehiclePhotoList_Success() throws Exception {
VehiclePhoto photo = VehiclePhoto.builder()
.id("PHOTO-123")
.vehicleId("VEH-123")
.fileName("front.jpg")
.filePath("/uploads/VEH-123/front.jpg")
.fileUrl("http://localhost/uploads/VEH-123/front.jpg")
.contentType("image/jpeg")
.fileSize(1024L)
.build();

List<VehiclePhoto> photos = Arrays.asList(photo);
when(photoStorageService.getVehiclePhotos("VEH-123", "CUST-123"))
.thenReturn(photos);

mockMvc.perform(get("/vehicles/VEH-123/photos")
.header("X-User-Subject", "CUST-123"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.length()").value(1))
.andExpect(jsonPath("$[0].fileName").value("front.jpg"));

verify(photoStorageService).getVehiclePhotos("VEH-123", "CUST-123");
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testGetServiceHistory_Success() throws Exception {
ServiceHistoryDto historyItem = ServiceHistoryDto.builder()
.type("Oil Change")
.cost(new java.math.BigDecimal("50.00"))
.date(java.time.LocalDateTime.now())
.description("Regular oil change service")
.build();

List<ServiceHistoryDto> history = Arrays.asList(historyItem);
when(serviceHistoryService.getServiceHistory("VEH-123", "CUST-123"))
.thenReturn(history);

mockMvc.perform(get("/vehicles/VEH-123/history")
.header("X-User-Subject", "CUST-123")
.header("X-User-Roles", "CUSTOMER"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.length()").value(1))
.andExpect(jsonPath("$[0].type").value("Oil Change"));

verify(serviceHistoryService).getServiceHistory("VEH-123", "CUST-123");
}

@Test
@WithMockUser(roles = { "CUSTOMER" })
void testDeleteSinglePhoto_Success() throws Exception {
doNothing().when(photoStorageService).deleteSinglePhoto("PHOTO-123", "CUST-123");

mockMvc.perform(delete("/vehicles/photos/PHOTO-123")
.with(csrf())
.header("X-User-Subject", "CUST-123"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message").value("Photo deleted successfully"));

verify(photoStorageService).deleteSinglePhoto("PHOTO-123", "CUST-123");
}

@Test
void testUnauthorizedAccess() throws Exception {
mockMvc.perform(get("/vehicles"))
.andExpect(status().isUnauthorized());
}

@Test
@WithMockUser(roles = { "ADMIN" })
void testGetVehicleDetails_AdminAccess() throws Exception {
when(vehicleService.getVehicleById("VEH-123"))
.thenReturn(Optional.of(testVehicle));

mockMvc.perform(get("/vehicles/VEH-123")
.header("X-User-Subject", "ADMIN-123")
.header("X-User-Roles", "ADMIN"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.vehicleId").value("VEH-123"));

verify(vehicleService).getVehicleById("VEH-123");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.techtorque.vehicle_service.dto;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class VehicleRequestDtoTest {

@Test
void testBuilder() {
VehicleRequestDto dto = VehicleRequestDto.builder()
.make("Toyota")
.model("Camry")
.year(2022)
.vin("1HGBH41JXMN109186")
.licensePlate("ABC123")
.color("Silver")
.mileage(15000)
.build();

assertEquals("Toyota", dto.getMake());
assertEquals("Camry", dto.getModel());
assertEquals(2022, dto.getYear());
assertEquals("1HGBH41JXMN109186", dto.getVin());
assertEquals("ABC123", dto.getLicensePlate());
assertEquals("Silver", dto.getColor());
assertEquals(15000, dto.getMileage());
}

@Test
void testEqualsAndHashCode() {
VehicleRequestDto dto1 = VehicleRequestDto.builder()
.make("Toyota")
.model("Camry")
.year(2022)
.vin("1HGBH41JXMN109186")
.build();

VehicleRequestDto dto2 = VehicleRequestDto.builder()
.make("Toyota")
.model("Camry")
.year(2022)
.vin("1HGBH41JXMN109186")
.build();

VehicleRequestDto dto3 = VehicleRequestDto.builder()
.make("Honda")
.model("Civic")
.year(2021)
.vin("2HGFC2F59MH123456")
.build();

assertEquals(dto1, dto2);
assertEquals(dto1.hashCode(), dto2.hashCode());
assertNotEquals(dto1, dto3);
}

@Test
void testToString() {
VehicleRequestDto dto = VehicleRequestDto.builder()
.make("BMW")
.model("X5")
.year(2023)
.build();

String toString = dto.toString();
assertTrue(toString.contains("BMW"));
assertTrue(toString.contains("X5"));
assertTrue(toString.contains("2023"));
}
}
Loading