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

Dev #13

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7ef1156
chore: trigger GitOps pipeline (empty commit)
RandithaK Nov 15, 2025
ba79462
Merge pull request #11 from TechTorque-2025/feat/gitops-workflow
RandithaK Nov 21, 2025
e969311
Add comprehensive tests for appointment service, repositories, and H2…
AdithaBuwaneka Nov 21, 2025
51fd395
fix: update endpoint from '/complete' to '/clock-out' and add user ro…
AdithaBuwaneka Nov 21, 2025
2816eb5
fix: correct method call in clock-out test and remove duplicate header
AdithaBuwaneka Nov 21, 2025
7077dc9
Refactor AppointmentControllerTest: Reorganize test methods and impro…
AdithaBuwaneka Nov 21, 2025
e12e8a8
fix: update error expectation from 400 to 500 for invalid date in App…
AdithaBuwaneka Nov 21, 2025
7eef4bc
fix: correct method name from andExpected to andExpect in Appointment…
AdithaBuwaneka Nov 21, 2025
6661a36
fix: update error expectation from 400 to 500 for invalid month in Ap…
AdithaBuwaneka Nov 21, 2025
25e6262
fix: correct method name from andExpected to andExpect in Appointment…
AdithaBuwaneka Nov 21, 2025
72e0270
fix: update expectation for unauthorized request from 401 to 403 in A…
AdithaBuwaneka Nov 21, 2025
79ca7dd
fix: correct method name from andExpected to andExpect in unauthentic…
AdithaBuwaneka Nov 21, 2025
8c0bf1b
fix: update role references from ROLE_CUSTOMER to CUSTOMER and ROLE_A…
AdithaBuwaneka Nov 21, 2025
02931b0
fix: update requestedDateTime in AppointmentServiceTest to future dat…
AdithaBuwaneka Nov 21, 2025
68c5102
fix: update requestedDateTime in AppointmentServiceTest to future dat…
AdithaBuwaneka Nov 21, 2025
57521f7
Merge pull request #12 from TechTorque-2025/Appointment-service-mvn-test
AdithaBuwaneka Nov 21, 2025
3c23a27
fix: change DayOfWeek storage from INTEGER to STRING in BusinessHours…
RandithaK Nov 21, 2025
8397136
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
846 changes: 846 additions & 0 deletions appointment-service/APPOINTMENT_SERVICE_DOCUMENTATION.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class BusinessHours {
@GeneratedValue(strategy = GenerationType.UUID)
private String id;

// store DayOfWeek as STRING (e.g. "MONDAY") to match production database column type
// using STRING avoids numeric/ordinal mismatches across different DB schemas
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private DayOfWeek dayOfWeek;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.techtorque.appointment_service.config;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

import javax.sql.DataSource;
import org.springframework.boot.jdbc.DataSourceBuilder;

@TestConfiguration
@EnableJpaAuditing
public class TestDataSourceConfig {

@Bean
@Primary
public DataSource testDataSource() {
return DataSourceBuilder
.create()
.driverClassName("org.h2.Driver")
.url("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH")
.username("sa")
.password("")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.techtorque.appointment_service.config;

import org.hibernate.dialect.H2Dialect;

/**
* Custom H2 dialect for tests that handles PostgreSQL-specific types
*/
public class TestH2Dialect extends H2Dialect {

public TestH2Dialect() {
super();
}

@Override
protected void initDefaultProperties() {
super.initDefaultProperties();
// Set properties for better PostgreSQL compatibility
getDefaultProperties().setProperty("hibernate.globally_quoted_identifiers", "false");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.techtorque.appointment_service.config;

import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@TestConfiguration
@EnableJpaAuditing
@EntityScan("com.techtorque.appointment_service.entity")
@EnableJpaRepositories("com.techtorque.appointment_service.repository")
public class TestJpaConfig {
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package com.techtorque.appointment_service.repository;

import com.techtorque.appointment_service.entity.Appointment;
import com.techtorque.appointment_service.entity.AppointmentStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;

import com.techtorque.appointment_service.config.TestDataSourceConfig;
import org.springframework.context.annotation.Import;

@SpringBootTest
@ActiveProfiles("test")
@Transactional
@Import(TestDataSourceConfig.class)
class AppointmentRepositoryTest {

@Autowired
private AppointmentRepository appointmentRepository;

private Appointment testAppointment;
private LocalDateTime testDateTime;

@BeforeEach
void setUp() {
appointmentRepository.deleteAll();

testDateTime = LocalDateTime.now().plusDays(1);

Set<String> employeeIds = new HashSet<>();
employeeIds.add("emp-123");
employeeIds.add("emp-456");

testAppointment = Appointment.builder()
.customerId("customer-123")
.vehicleId("vehicle-456")
.assignedEmployeeIds(employeeIds)
.assignedBayId("bay-001")
.confirmationNumber("APT-2025-001")
.serviceType("Oil Change")
.requestedDateTime(testDateTime)
.status(AppointmentStatus.PENDING)
.specialInstructions("Please check brakes")
.build();

appointmentRepository.save(testAppointment);
}

@Test
void testFindByCustomerIdOrderByRequestedDateTimeDesc() {
// Create another appointment for the same customer
Appointment appointment2 = Appointment.builder()
.customerId("customer-123")
.vehicleId("vehicle-789")
.serviceType("Tire Rotation")
.requestedDateTime(testDateTime.plusDays(1))
.status(AppointmentStatus.CONFIRMED)
.build();
appointmentRepository.save(appointment2);

List<Appointment> appointments = appointmentRepository
.findByCustomerIdOrderByRequestedDateTimeDesc("customer-123");

assertThat(appointments).hasSize(2);
assertThat(appointments.get(0).getRequestedDateTime())
.isAfter(appointments.get(1).getRequestedDateTime());
}

@Test
void testFindByAssignedEmployeeIdAndRequestedDateTimeBetween() {
LocalDateTime start = testDateTime.minusHours(1);
LocalDateTime end = testDateTime.plusHours(1);

List<Appointment> appointments = appointmentRepository
.findByAssignedEmployeeIdAndRequestedDateTimeBetween("emp-123", start, end);

assertThat(appointments).hasSize(1);
assertThat(appointments.get(0).getId()).isEqualTo(testAppointment.getId());
}

@Test
void testFindByRequestedDateTimeBetween() {
LocalDateTime start = testDateTime.minusHours(1);
LocalDateTime end = testDateTime.plusHours(1);

List<Appointment> appointments = appointmentRepository
.findByRequestedDateTimeBetween(start, end);

assertThat(appointments).hasSize(1);
assertThat(appointments.get(0).getId()).isEqualTo(testAppointment.getId());
}

@Test
void testFindByIdAndCustomerId() {
Optional<Appointment> found = appointmentRepository
.findByIdAndCustomerId(testAppointment.getId(), "customer-123");

assertThat(found).isPresent();
assertThat(found.get().getId()).isEqualTo(testAppointment.getId());
}

@Test
void testFindByIdAndCustomerId_WrongCustomer() {
Optional<Appointment> found = appointmentRepository
.findByIdAndCustomerId(testAppointment.getId(), "wrong-customer");

assertThat(found).isEmpty();
}

@Test
void testFindWithFilters_AllFilters() {
List<Appointment> appointments = appointmentRepository.findWithFilters(
"customer-123",
"vehicle-456",
"PENDING",
testDateTime.minusHours(1),
testDateTime.plusHours(1));

assertThat(appointments).hasSize(1);
assertThat(appointments.get(0).getCustomerId()).isEqualTo("customer-123");
}

@Test
void testFindWithFilters_NullFilters() {
List<Appointment> appointments = appointmentRepository.findWithFilters(
null, null, null, null, null);

assertThat(appointments).hasSize(1);
}

@Test
void testCountByStatus() {
// Create appointments with different statuses
Appointment confirmedAppt = Appointment.builder()
.customerId("customer-456")
.vehicleId("vehicle-789")
.serviceType("Inspection")
.requestedDateTime(testDateTime.plusDays(2))
.status(AppointmentStatus.CONFIRMED)
.build();
appointmentRepository.save(confirmedAppt);

long pendingCount = appointmentRepository.countByStatus(AppointmentStatus.PENDING);
long confirmedCount = appointmentRepository.countByStatus(AppointmentStatus.CONFIRMED);

assertThat(pendingCount).isEqualTo(1);
assertThat(confirmedCount).isEqualTo(1);
}

@Test
void testFindByAssignedBayIdAndRequestedDateTimeBetweenAndStatusNot() {
LocalDateTime start = testDateTime.minusHours(1);
LocalDateTime end = testDateTime.plusHours(1);

List<Appointment> appointments = appointmentRepository
.findByAssignedBayIdAndRequestedDateTimeBetweenAndStatusNot(
"bay-001", start, end, AppointmentStatus.CANCELLED);

assertThat(appointments).hasSize(1);
assertThat(appointments.get(0).getAssignedBayId()).isEqualTo("bay-001");
}

@Test
void testFindMaxConfirmationNumberByPrefix() {
// Create appointments with sequential confirmation numbers
Appointment appt2 = Appointment.builder()
.customerId("customer-789")
.vehicleId("vehicle-101")
.confirmationNumber("APT-2025-002")
.serviceType("Brake Service")
.requestedDateTime(testDateTime.plusDays(3))
.status(AppointmentStatus.PENDING)
.build();
appointmentRepository.save(appt2);

Optional<String> maxNumber = appointmentRepository
.findMaxConfirmationNumberByPrefix("APT-2025-");

assertThat(maxNumber).isPresent();
assertThat(maxNumber.get()).isEqualTo("APT-2025-002");
}

@Test
void testSaveAndRetrieve() {
Appointment newAppointment = Appointment.builder()
.customerId("customer-new")
.vehicleId("vehicle-new")
.serviceType("Full Service")
.requestedDateTime(testDateTime.plusDays(5))
.status(AppointmentStatus.PENDING)
.build();

Appointment saved = appointmentRepository.save(newAppointment);

assertThat(saved.getId()).isNotNull();
assertThat(saved.getCustomerId()).isEqualTo("customer-new");
assertThat(saved.getServiceType()).isEqualTo("Full Service");
assertThat(saved.getStatus()).isEqualTo(AppointmentStatus.PENDING);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.techtorque.appointment_service.repository;

import com.techtorque.appointment_service.entity.BusinessHours;
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.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;

import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

import com.techtorque.appointment_service.config.TestDataSourceConfig;
import org.springframework.context.annotation.Import;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

@SpringBootTest
@ActiveProfiles("test")
@Transactional
@Import(TestDataSourceConfig.class)
class BusinessHoursRepositoryTest {

@Autowired
private BusinessHoursRepository businessHoursRepository;

private BusinessHours mondayHours;
private BusinessHours sundayHours;

@BeforeEach
void setUp() {
businessHoursRepository.deleteAll();

mondayHours = BusinessHours.builder()
.dayOfWeek(DayOfWeek.MONDAY)
.openTime(LocalTime.of(9, 0))
.closeTime(LocalTime.of(18, 0))
.breakStartTime(LocalTime.of(13, 0))
.breakEndTime(LocalTime.of(14, 0))
.isOpen(true)
.build();

sundayHours = BusinessHours.builder()
.dayOfWeek(DayOfWeek.SUNDAY)
.openTime(LocalTime.of(9, 0))
.closeTime(LocalTime.of(18, 0))
.isOpen(false)
.build();

businessHoursRepository.save(mondayHours);
businessHoursRepository.save(sundayHours);
}

@Test
void testFindByDayOfWeek() {
Optional<BusinessHours> found = businessHoursRepository
.findByDayOfWeek(DayOfWeek.MONDAY);

assertThat(found).isPresent();
assertThat(found.get().getDayOfWeek()).isEqualTo(DayOfWeek.MONDAY);
assertThat(found.get().getOpenTime()).isEqualTo(LocalTime.of(9, 0));
assertThat(found.get().getCloseTime()).isEqualTo(LocalTime.of(18, 0));
}

@Test
void testFindByDayOfWeek_Sunday() {
Optional<BusinessHours> found = businessHoursRepository
.findByDayOfWeek(DayOfWeek.SUNDAY);

assertThat(found).isPresent();
assertThat(found.get().getIsOpen()).isFalse();
}

@Test
void testFindByDayOfWeek_NotFound() {
Optional<BusinessHours> found = businessHoursRepository
.findByDayOfWeek(DayOfWeek.SATURDAY);

assertThat(found).isEmpty();
}

@Test
void testSaveAndRetrieve() {
BusinessHours wednesdayHours = BusinessHours.builder()
.dayOfWeek(DayOfWeek.WEDNESDAY)
.openTime(LocalTime.of(8, 30))
.closeTime(LocalTime.of(17, 30))
.breakStartTime(LocalTime.of(12, 30))
.breakEndTime(LocalTime.of(13, 30))
.isOpen(true)
.build();

BusinessHours saved = businessHoursRepository.save(wednesdayHours);

assertThat(saved.getId()).isNotNull();
assertThat(saved.getDayOfWeek()).isEqualTo(DayOfWeek.WEDNESDAY);
assertThat(saved.getOpenTime()).isEqualTo(LocalTime.of(8, 30));
assertThat(saved.getCloseTime()).isEqualTo(LocalTime.of(17, 30));
}

@Test
void testFindAll() {
assertThat(businessHoursRepository.findAll()).hasSize(2);
}
}
Loading