diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/controller/GlobalExceptionHandler.java b/src/main/java/com/onboarding/camera/cameraonboarding/controller/GlobalExceptionHandler.java index 30bd025..95714c6 100644 --- a/src/main/java/com/onboarding/camera/cameraonboarding/controller/GlobalExceptionHandler.java +++ b/src/main/java/com/onboarding/camera/cameraonboarding/controller/GlobalExceptionHandler.java @@ -10,6 +10,10 @@ import com.onboarding.camera.cameraonboarding.exception.ImageNotFoundException; import com.onboarding.camera.cameraonboarding.exception.ImageNotUploadedException; import com.onboarding.camera.cameraonboarding.exception.LocationNotAddedException; +import com.onboarding.camera.cameraonboarding.exception.SensorMismatchException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -166,5 +170,53 @@ public ResponseEntity handleLocationNotAddedException(LocationNot return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); } + + @ExceptionHandler(SensorNotCreatedException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ResponseBody + public ResponseEntity handleSensorNotCreatedException(SensorNotCreatedException ex) { + ErrorResponse errorResponse = new ErrorResponse(); + + errorResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); + errorResponse.setMessage(ex.getMessage()); + + return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ExceptionHandler(SensorNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + @ResponseBody + public ResponseEntity handleSensorNotFoundException(SensorNotFoundException ex) { + ErrorResponse errorResponse = new ErrorResponse(); + + errorResponse.setStatusCode(HttpStatus.NOT_FOUND.value()); + errorResponse.setMessage(ex.getMessage()); + + return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(SensorNotUpdatedException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ResponseBody + public ResponseEntity handleSensorNotUpdatedException(SensorNotUpdatedException ex) { + ErrorResponse errorResponse = new ErrorResponse(); + + errorResponse.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); + errorResponse.setMessage(ex.getMessage()); + + return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ExceptionHandler(SensorMismatchException.class) + @ResponseStatus(HttpStatus.CONFLICT) + @ResponseBody + public ResponseEntity handleSensorMismatchException(SensorMismatchException ex) { + ErrorResponse errorResponse = new ErrorResponse(); + + errorResponse.setStatusCode(HttpStatus.CONFLICT.value()); + errorResponse.setMessage(ex.getMessage()); + + return new ResponseEntity<>(errorResponse, HttpStatus.CONFLICT); + } } diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/controller/LightSensorController.java b/src/main/java/com/onboarding/camera/cameraonboarding/controller/LightSensorController.java new file mode 100644 index 0000000..55277e8 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/controller/LightSensorController.java @@ -0,0 +1,71 @@ +package com.onboarding.camera.cameraonboarding.controller; + +import com.onboarding.camera.cameraonboarding.converter.SensorDtoConverter; +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.dto.SensorResponse; +import com.onboarding.camera.cameraonboarding.entity.LightSensor; +import com.onboarding.camera.cameraonboarding.service.impl.LightSensorService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("${api.version}/camera/{cameraId}/sensor/light") +@RequiredArgsConstructor +public class LightSensorController { + + private final LightSensorService lightSensorService; + + private final SensorDtoConverter sensorDtoConverter; + + @PostMapping + public ResponseEntity addLightSensor( + @PathVariable UUID cameraId, + @Valid @RequestBody SensorDto sensorDto) { + + LightSensor sensorMetadata = sensorDtoConverter.toLightEntity(sensorDto); + LightSensor savedSensor = lightSensorService.handleCreateSensor(cameraId, sensorMetadata); + SensorResponse sensorResponse = sensorDtoConverter.toSensorResponse(savedSensor); + + return new ResponseEntity<>(sensorResponse, HttpStatus.CREATED); + } + + @GetMapping + public ResponseEntity> getLightSensors( + @PathVariable UUID cameraId) { + + List sensors = lightSensorService.handleGetSensorsByCameraId(cameraId); + return ResponseEntity.ok(sensors); + } + + @PutMapping("/{sensorId}") + public ResponseEntity updateLightSensor( + @PathVariable UUID sensorId, + @Valid @RequestBody SensorDto sensorDto, @PathVariable UUID cameraId) { + + LightSensor sensorMetadata = sensorDtoConverter.toLightEntity(sensorDto); + LightSensor updatedSensor = lightSensorService.handleUpdateSensor(cameraId, sensorId, sensorMetadata); + SensorResponse sensorResponse = sensorDtoConverter.toSensorResponse(updatedSensor); + return ResponseEntity.ok(sensorResponse); + } + + @DeleteMapping("/{sensorId}") + public ResponseEntity deleteLightSensor( + @PathVariable UUID sensorId, @PathVariable UUID cameraId) { + + lightSensorService.handleDeleteSensor(cameraId, sensorId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/controller/MotionSensorController.java b/src/main/java/com/onboarding/camera/cameraonboarding/controller/MotionSensorController.java new file mode 100644 index 0000000..3b6b986 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/controller/MotionSensorController.java @@ -0,0 +1,71 @@ +package com.onboarding.camera.cameraonboarding.controller; + +import com.onboarding.camera.cameraonboarding.converter.SensorDtoConverter; +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.dto.SensorResponse; +import com.onboarding.camera.cameraonboarding.entity.MotionSensor; +import com.onboarding.camera.cameraonboarding.service.impl.MotionSensorService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("${api.version}/camera/{cameraId}/sensor/motion") +@RequiredArgsConstructor +public class MotionSensorController { + + private final MotionSensorService motionSensorService; + + private final SensorDtoConverter sensorDtoConverter; + + @PostMapping + public ResponseEntity addMotionSensor( + @PathVariable UUID cameraId, + @Valid @RequestBody SensorDto sensorDto) { + + MotionSensor motionSensor = sensorDtoConverter.toMotionEntity(sensorDto); + MotionSensor savedSensor = motionSensorService.handleCreateSensor(cameraId, motionSensor); + SensorResponse sensorResponse = sensorDtoConverter.toSensorResponse(savedSensor); + + return new ResponseEntity<>(sensorResponse, HttpStatus.CREATED); + } + + @GetMapping + public ResponseEntity> getMotionSensors( + @PathVariable UUID cameraId) { + + List sensors = motionSensorService.handleGetSensorsByCameraId(cameraId); + return ResponseEntity.ok(sensors); + } + + @PutMapping("/{sensorId}") + public ResponseEntity updateMotionSensor( + @PathVariable UUID sensorId, + @Valid @RequestBody SensorDto sensorDto, @PathVariable UUID cameraId) { + + MotionSensor motionSensor = sensorDtoConverter.toMotionEntity(sensorDto); + MotionSensor updatedSensor = motionSensorService.handleUpdateSensor(cameraId, sensorId, motionSensor); + SensorResponse sensorResponse = sensorDtoConverter.toSensorResponse(updatedSensor); + return ResponseEntity.ok(sensorResponse); + } + + @DeleteMapping("/{sensorId}") + public ResponseEntity deleteMotionSensor( + @PathVariable UUID sensorId, @PathVariable UUID cameraId) { + + motionSensorService.handleDeleteSensor(cameraId, sensorId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/controller/TemperatureSensorController.java b/src/main/java/com/onboarding/camera/cameraonboarding/controller/TemperatureSensorController.java new file mode 100644 index 0000000..20c5c04 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/controller/TemperatureSensorController.java @@ -0,0 +1,70 @@ +package com.onboarding.camera.cameraonboarding.controller; + +import com.onboarding.camera.cameraonboarding.converter.SensorDtoConverter; +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.dto.SensorResponse; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import com.onboarding.camera.cameraonboarding.service.impl.TemperatureSensorService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("${api.version}/camera/{cameraId}/sensor/temperature") +@RequiredArgsConstructor +public class TemperatureSensorController { + + private final TemperatureSensorService temperatureSensorService; + + private final SensorDtoConverter sensorDtoConverter; + + @PostMapping + public ResponseEntity addTemperatureSensor( + @PathVariable UUID cameraId, + @Valid @RequestBody SensorDto sensorDto) { + + TemperatureSensor sensorMetadata = sensorDtoConverter.toTemperatureEntity(sensorDto); + TemperatureSensor savedSensor = temperatureSensorService.handleCreateSensor(cameraId, sensorMetadata); + SensorResponse sensorResponse = sensorDtoConverter.toSensorResponse(savedSensor); + return new ResponseEntity<>(sensorResponse, HttpStatus.CREATED); + } + + @GetMapping + public ResponseEntity> getTemperatureSensors( + @PathVariable UUID cameraId) { + + List sensors = temperatureSensorService.handleGetSensorsByCameraId(cameraId); + return ResponseEntity.ok(sensors); + } + + @PutMapping("/{sensorId}") + public ResponseEntity updateTemperatureSensor( + @PathVariable UUID sensorId, + @Valid @RequestBody SensorDto sensorDto, @PathVariable UUID cameraId) { + + TemperatureSensor sensorMetadata = sensorDtoConverter.toTemperatureEntity(sensorDto); + TemperatureSensor updatedSensor = temperatureSensorService.handleUpdateSensor(cameraId, sensorId, sensorMetadata); + SensorResponse sensorResponse = sensorDtoConverter.toSensorResponse(updatedSensor); + return ResponseEntity.ok(sensorResponse); + } + + @DeleteMapping("/{sensorId}") + public ResponseEntity deleteTemperatureSensor( + @PathVariable UUID sensorId, @PathVariable UUID cameraId) { + + temperatureSensorService.handleDeleteSensor(cameraId, sensorId); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/converter/CameraDtoConverter.java b/src/main/java/com/onboarding/camera/cameraonboarding/converter/CameraDtoConverter.java index b8c1744..9addaec 100644 --- a/src/main/java/com/onboarding/camera/cameraonboarding/converter/CameraDtoConverter.java +++ b/src/main/java/com/onboarding/camera/cameraonboarding/converter/CameraDtoConverter.java @@ -2,9 +2,12 @@ import com.onboarding.camera.cameraonboarding.dto.CameraDto; import com.onboarding.camera.cameraonboarding.dto.CameraResponse; +import com.onboarding.camera.cameraonboarding.dto.SensorResponse; import com.onboarding.camera.cameraonboarding.entity.Camera; import org.springframework.stereotype.Component; +import java.util.stream.Collectors; + @Component public class CameraDtoConverter { @@ -20,6 +23,18 @@ public CameraResponse toCameraResponse(Camera camera) { response.setCameraId(camera.getCamId()); response.setCameraName(camera.getCameraName()); response.setFirmwareVersion(camera.getFirmwareVersion()); + response.setSensors(camera.getSensors() + .stream() + .map(sensor -> { + SensorResponse sensorResponse = new SensorResponse(); + sensorResponse.setId(sensor.getId()); + sensorResponse.setName(sensor.getName()); + sensorResponse.setVersion(sensor.getVersion()); + sensorResponse.setSensorType(sensor.getSensorType()); + sensorResponse.setData(sensor.getData()); + return sensorResponse; + }) + .collect(Collectors.toList())); return response; } } diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/converter/SensorDtoConverter.java b/src/main/java/com/onboarding/camera/cameraonboarding/converter/SensorDtoConverter.java new file mode 100644 index 0000000..db75c9d --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/converter/SensorDtoConverter.java @@ -0,0 +1,89 @@ +package com.onboarding.camera.cameraonboarding.converter; + +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.dto.SensorResponse; +import com.onboarding.camera.cameraonboarding.entity.LightSensor; +import com.onboarding.camera.cameraonboarding.entity.MotionSensor; +import com.onboarding.camera.cameraonboarding.entity.Sensor; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.SensorMismatchException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import org.springframework.stereotype.Component; + +@Component +public class SensorDtoConverter { + + public MotionSensor toMotionEntity(SensorDto sensorDto) { + + validateSensorDto(sensorDto); + if (sensorDto.getSensorType() != SensorType.MOTION) { + throw new SensorMismatchException("Invalid sensor type for MotionSensor"); + } + + MotionSensor sensorMetadata = new MotionSensor(); + sensorMetadata.setName(sensorDto.getName()); + sensorMetadata.setVersion(sensorDto.getVersion()); + sensorMetadata.setSensorType(sensorDto.getSensorType()); + sensorMetadata.setData(sensorDto.getData()); + return sensorMetadata; + } + + public LightSensor toLightEntity(SensorDto sensorDto) { + + validateSensorDto(sensorDto); + if (sensorDto.getSensorType() != SensorType.LIGHT) { + throw new SensorMismatchException("Invalid sensor type for LightSensor"); + } + + LightSensor sensorMetadata = new LightSensor(); + sensorMetadata.setName(sensorDto.getName()); + sensorMetadata.setVersion(sensorDto.getVersion()); + sensorMetadata.setSensorType(sensorDto.getSensorType()); + sensorMetadata.setData(sensorDto.getData()); + return sensorMetadata; + } + + public TemperatureSensor toTemperatureEntity(SensorDto sensorDto) { + + validateSensorDto(sensorDto); + if (sensorDto.getSensorType() != SensorType.TEMPERATURE) { + throw new SensorMismatchException("Invalid sensor type for TemperatureSensor"); + } + + TemperatureSensor sensorMetadata = new TemperatureSensor(); + sensorMetadata.setName(sensorDto.getName()); + sensorMetadata.setVersion(sensorDto.getVersion()); + sensorMetadata.setSensorType(sensorDto.getSensorType()); + sensorMetadata.setData(sensorDto.getData()); + return sensorMetadata; + } + + public SensorResponse toSensorResponse(Sensor sensor) { + SensorResponse response = new SensorResponse(); + response.setId(sensor.getId()); + response.setName(sensor.getName()); + response.setVersion(sensor.getVersion()); + response.setSensorType(sensor.getSensorType()); + response.setData(sensor.getData()); + return response; + } + + /** + * Validates if the camera has been onboarded and initialized + * + * @param sensorDto the sensor dto to check + * @throws SensorNotCreatedException if the sensor name, version or type is null + */ + private void validateSensorDto(SensorDto sensorDto) { + if (sensorDto.getName() == null || sensorDto.getName().isBlank()) { + throw new SensorNotCreatedException("Sensor name cannot be null"); + } + if (sensorDto.getVersion() == null || sensorDto.getVersion().isBlank()) { + throw new SensorNotCreatedException("Sensor version cannot be null"); + } + if (sensorDto.getSensorType() == null || sensorDto.getSensorType().toString().isBlank()) { + throw new SensorNotCreatedException("Sensor type cannot be null"); + } + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/dto/CameraResponse.java b/src/main/java/com/onboarding/camera/cameraonboarding/dto/CameraResponse.java index 6aac830..3e45431 100644 --- a/src/main/java/com/onboarding/camera/cameraonboarding/dto/CameraResponse.java +++ b/src/main/java/com/onboarding/camera/cameraonboarding/dto/CameraResponse.java @@ -1,6 +1,8 @@ package com.onboarding.camera.cameraonboarding.dto; import lombok.Data; + +import java.util.List; import java.util.UUID; @Data @@ -8,4 +10,5 @@ public class CameraResponse { private UUID cameraId; private String cameraName; private String firmwareVersion; + private List sensors; } diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/dto/SensorDto.java b/src/main/java/com/onboarding/camera/cameraonboarding/dto/SensorDto.java new file mode 100644 index 0000000..842513c --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/dto/SensorDto.java @@ -0,0 +1,30 @@ +package com.onboarding.camera.cameraonboarding.dto; + +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Data +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class SensorDto { + + @NotBlank(message = "Sensor name cannot be blank") + @Size(min = 2, max = 100, message = "Sensor name should be between 2 and 100 characters") + private String name; + + @NotBlank(message = "Version cannot be blank") + @Size(min = 2, max = 50, message = "Version should be between 2 and 50 characters") + private String version; + + @NotNull(message = "Sensor type cannot be null") + private SensorType sensorType; + + private String data; +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/dto/SensorResponse.java b/src/main/java/com/onboarding/camera/cameraonboarding/dto/SensorResponse.java new file mode 100644 index 0000000..51cdb55 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/dto/SensorResponse.java @@ -0,0 +1,15 @@ +package com.onboarding.camera.cameraonboarding.dto; + +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import lombok.Data; + +import java.util.UUID; + +@Data +public class SensorResponse { + private UUID id; + private String name; + private String version; + private SensorType sensorType; + private String data; +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/entity/Camera.java b/src/main/java/com/onboarding/camera/cameraonboarding/entity/Camera.java index 389f5df..3e4e325 100644 --- a/src/main/java/com/onboarding/camera/cameraonboarding/entity/Camera.java +++ b/src/main/java/com/onboarding/camera/cameraonboarding/entity/Camera.java @@ -6,6 +6,7 @@ import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; import lombok.Data; @@ -13,6 +14,8 @@ import org.hibernate.annotations.UuidGenerator; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; @Data @@ -54,4 +57,8 @@ public class Camera { @OneToOne(mappedBy = "camera", cascade = CascadeType.ALL, orphanRemoval = true) @JsonManagedReference private Location location; + + @OneToMany(mappedBy = "camera", cascade = CascadeType.ALL, orphanRemoval = true) + @JsonManagedReference + private List sensors = new ArrayList<>(); } diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/entity/LightSensor.java b/src/main/java/com/onboarding/camera/cameraonboarding/entity/LightSensor.java new file mode 100644 index 0000000..013a39a --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/entity/LightSensor.java @@ -0,0 +1,12 @@ +package com.onboarding.camera.cameraonboarding.entity; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import lombok.ToString; + +@Entity +@ToString +@DiscriminatorValue("LIGHT") +public class LightSensor extends Sensor { + +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/entity/MotionSensor.java b/src/main/java/com/onboarding/camera/cameraonboarding/entity/MotionSensor.java new file mode 100644 index 0000000..a120e52 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/entity/MotionSensor.java @@ -0,0 +1,12 @@ +package com.onboarding.camera.cameraonboarding.entity; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import lombok.ToString; + +@Entity +@ToString +@DiscriminatorValue("MOTION") +public class MotionSensor extends Sensor { + +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/entity/Sensor.java b/src/main/java/com/onboarding/camera/cameraonboarding/entity/Sensor.java new file mode 100644 index 0000000..6f95d96 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/entity/Sensor.java @@ -0,0 +1,56 @@ +package com.onboarding.camera.cameraonboarding.entity; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.DiscriminatorType; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.ToString; +import org.hibernate.annotations.UuidGenerator; + +import java.util.UUID; + +@Data +@Entity +@ToString(exclude = "camera") +@Table(name = "sensor_metadata", indexes = @Index(name = "idx_camera_id", columnList = "camera_id")) +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "sensor_type", discriminatorType = DiscriminatorType.STRING) +public abstract class Sensor { + + @Id + @GeneratedValue + @UuidGenerator + @Column(name = "id") + private UUID id; + + @ManyToOne + @JoinColumn(name = "camera_id", nullable = false) + @JsonBackReference + private Camera camera; + + @Column(name = "name", nullable = false) + private String name; + + @Column(name = "version") + private String version; + + @Column(name = "data") + private String data; + + @Column(name = "sensor_type", nullable = false, updatable = false, insertable = false) + @Enumerated(EnumType.STRING) + private SensorType sensorType; +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/entity/TemperatureSensor.java b/src/main/java/com/onboarding/camera/cameraonboarding/entity/TemperatureSensor.java new file mode 100644 index 0000000..b6e9cb0 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/entity/TemperatureSensor.java @@ -0,0 +1,12 @@ +package com.onboarding.camera.cameraonboarding.entity; + +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import lombok.ToString; + +@Entity +@ToString +@DiscriminatorValue("TEMPERATURE") +public class TemperatureSensor extends Sensor { + +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/enums/SensorType.java b/src/main/java/com/onboarding/camera/cameraonboarding/enums/SensorType.java new file mode 100644 index 0000000..3deff35 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/enums/SensorType.java @@ -0,0 +1,24 @@ +package com.onboarding.camera.cameraonboarding.enums; + +public enum SensorType { + /** + * MOTION: Used to detect movement in the vicinity of the camera. + * This sensor is typically utilized in security systems to trigger alerts + * or initiate recordings when motion is detected. + */ + MOTION, + + /** + * TEMPERATURE: Used to monitor the environmental temperature around the camera. + * This sensor can be used in smart home systems, industrial setups, or outdoor + * environments where temperature variations need to be tracked for safety or efficiency. + */ + TEMPERATURE, + + /** + * LIGHT: Used to measure the intensity of light around the camera. + * This sensor can assist in adjusting the camera's exposure settings + * or determining the need for additional lighting in low-light conditions. + */ + LIGHT +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorMismatchException.java b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorMismatchException.java new file mode 100644 index 0000000..6985419 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorMismatchException.java @@ -0,0 +1,7 @@ +package com.onboarding.camera.cameraonboarding.exception; + +public class SensorMismatchException extends RuntimeException { + public SensorMismatchException(String message) { + super(message); + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotCreatedException.java b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotCreatedException.java new file mode 100644 index 0000000..64e626f --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotCreatedException.java @@ -0,0 +1,7 @@ +package com.onboarding.camera.cameraonboarding.exception; + +public class SensorNotCreatedException extends RuntimeException { + public SensorNotCreatedException(String message) { + super(message); + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotFoundException.java b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotFoundException.java new file mode 100644 index 0000000..4e42903 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotFoundException.java @@ -0,0 +1,7 @@ +package com.onboarding.camera.cameraonboarding.exception; + +public class SensorNotFoundException extends RuntimeException { + public SensorNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotUpdatedException.java b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotUpdatedException.java new file mode 100644 index 0000000..92231a6 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/exception/SensorNotUpdatedException.java @@ -0,0 +1,7 @@ +package com.onboarding.camera.cameraonboarding.exception; + +public class SensorNotUpdatedException extends RuntimeException { + public SensorNotUpdatedException(String message) { + super(message); + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/repository/LightSensorRepository.java b/src/main/java/com/onboarding/camera/cameraonboarding/repository/LightSensorRepository.java new file mode 100644 index 0000000..09868ea --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/repository/LightSensorRepository.java @@ -0,0 +1,13 @@ +package com.onboarding.camera.cameraonboarding.repository; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.LightSensor; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.UUID; + +public interface LightSensorRepository extends JpaRepository { + + List findLightSensorByCamera(Camera camera); +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/repository/MotionSensorRepository.java b/src/main/java/com/onboarding/camera/cameraonboarding/repository/MotionSensorRepository.java new file mode 100644 index 0000000..b6a7b5e --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/repository/MotionSensorRepository.java @@ -0,0 +1,13 @@ +package com.onboarding.camera.cameraonboarding.repository; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.MotionSensor; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.UUID; + +public interface MotionSensorRepository extends JpaRepository { + + List findMotionSensorByCamera(Camera camera); +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/repository/TemperatureSensorRepository.java b/src/main/java/com/onboarding/camera/cameraonboarding/repository/TemperatureSensorRepository.java new file mode 100644 index 0000000..ffd93f3 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/repository/TemperatureSensorRepository.java @@ -0,0 +1,13 @@ +package com.onboarding.camera.cameraonboarding.repository; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.UUID; + +public interface TemperatureSensorRepository extends JpaRepository { + + List findTemperatureSensorByCamera(Camera camera); +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/service/SensorService.java b/src/main/java/com/onboarding/camera/cameraonboarding/service/SensorService.java new file mode 100644 index 0000000..fc470d2 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/service/SensorService.java @@ -0,0 +1,61 @@ +package com.onboarding.camera.cameraonboarding.service; + +import com.onboarding.camera.cameraonboarding.entity.Sensor; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; + +import java.util.List; +import java.util.UUID; + +public interface SensorService { + + /** + * this method is used for create sensor to specified camera + * + * @param cameraId camera id + * @param sensor sensor + * @return Sensor created sensor + * @throws IllegalArgumentException if sensor type does not match + * @throws SensorNotCreatedException if unexpected error occurs while creating sensor + */ + T handleCreateSensor(UUID cameraId, T sensor); + + /** + * this method is used for get all sensors with related camera by camera ID + * + * @param cameraId camera id + * @return List sensors with specified camera + * @throws SensorNotFoundException if sensors not found + */ + List handleGetSensorsByCameraId(UUID cameraId); + + /** + * this method is used for update sensor by sensor ID + * + * @param cameraId camera id + * @param sensorId sensor id + * @param sensor sensor + * @return Sensor updated sensor + * @throws SensorNotUpdatedException if unexpected error occurs while updating sensor + */ + T handleUpdateSensor(UUID cameraId, UUID sensorId, T sensor); + + /** + * this method is used for get sensor by sensor ID + * + * @param sensorId sensor id + * @return Sensor retrieved sensor + * @throws SensorNotFoundException if sensor not found + */ + T getSensorById(UUID sensorId); + + /** + * this method is used for deleting sensor by sensor ID + * + * @param cameraId sensor id + * @param sensorId sensor id + * @throws SensorNotUpdatedException if unexpected error occurs while deleting sensor + */ + void handleDeleteSensor(UUID cameraId, UUID sensorId); +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/CameraServiceImpl.java b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/CameraServiceImpl.java index 2da41a4..efce22b 100644 --- a/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/CameraServiceImpl.java +++ b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/CameraServiceImpl.java @@ -70,10 +70,6 @@ public void handleInitializeCamera(UUID cameraId) { public Camera getCameraById(UUID cameraId) { - if (cameraId == null) { - throw new IllegalArgumentException("Camera ID cannot be null"); - } - return cameraRepository.findById(cameraId) .orElseThrow(() -> new CameraNotFoundException(String.format("Camera not found with id: %s", cameraId))); } diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/LightSensorService.java b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/LightSensorService.java new file mode 100644 index 0000000..3926a2d --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/LightSensorService.java @@ -0,0 +1,121 @@ +package com.onboarding.camera.cameraonboarding.service.impl; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.LightSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.CameraNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.repository.LightSensorRepository; +import com.onboarding.camera.cameraonboarding.service.CameraService; +import com.onboarding.camera.cameraonboarding.service.SensorService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Slf4j +@RequiredArgsConstructor +@Service +public class LightSensorService implements SensorService { + + private final LightSensorRepository lightSensorRepository; + + private final CameraService cameraService; + + @Override + @Transactional + public LightSensor handleCreateSensor(UUID cameraId, LightSensor sensor) { + try { + sensor.setCamera(cameraService.getCameraById(cameraId)); + LightSensor createdSensor = lightSensorRepository.save(sensor); + log.info("Creating sensor: {}", createdSensor); + return createdSensor; + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (Exception ex) { + log.error("Failed to create sensor, camera:{}:ex:{}", cameraId, ex.getMessage()); + throw new SensorNotCreatedException(String.format("Failed to create sensor: %s", ex.getMessage())); + } + } + + @Override + public List handleGetSensorsByCameraId(UUID cameraId) { + try { + Camera camera = cameraService.getCameraById(cameraId); + log.info("Getting sensors by camera id: {}", cameraId); + return lightSensorRepository.findLightSensorByCamera(camera); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while getting sensors, cameraId:{}", cameraId); + throw new SensorNotFoundException(String.format("Error occurred while getting sensors: %s", ex.getMessage())); + } + } + + @Override + @Transactional + public LightSensor handleUpdateSensor(UUID cameraId, UUID sensorId, LightSensor sensor) { + try { + Camera camera = cameraService.getCameraById(cameraId); + LightSensor existingSensor = camera.getSensors().stream() + .filter(s -> s.getId().equals(sensorId) && s.getSensorType().equals(SensorType.LIGHT)) + .map(s -> (LightSensor) s) + .findFirst() + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + + existingSensor.setName(sensor.getName()); + existingSensor.setVersion(sensor.getVersion()); + existingSensor.setData(sensor.getData()); + log.info("Updating sensor: {}", existingSensor); + return lightSensorRepository.save(existingSensor); + } catch (SensorNotFoundException ex) { + log.error("Sensor not found while updating, sensorId: {}", sensorId); + throw ex; + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while updating sensor, sensorId:{}", sensorId); + throw new SensorNotUpdatedException(String.format("Error occurred while updating sensors: %s", ex.getMessage())); + } + } + + @Override + public LightSensor getSensorById(UUID sensorId) { + + return lightSensorRepository.findById(sensorId) + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + } + + @Override + public void handleDeleteSensor(UUID cameraId, UUID sensorId) { + try { + Camera camera = cameraService.getCameraById(cameraId); + LightSensor sensor = camera.getSensors().stream() + .filter(s -> s.getId().equals(sensorId) && s.getSensorType().equals(SensorType.LIGHT)) + .map(s -> (LightSensor) s) + .findFirst() + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + + camera.getSensors().remove(sensor); + lightSensorRepository.delete(sensor); + log.info("Deleted sensor: {}", sensorId); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (SensorNotFoundException ex) { + log.error("Sensor not found while deleting, sensorId: {}", sensorId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while deleting sensor, sensorId:{}", sensorId); + throw new SensorNotUpdatedException(String.format("Error occurred while deleting sensor: %s", ex.getMessage())); + } + } +} diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/MotionSensorService.java b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/MotionSensorService.java new file mode 100644 index 0000000..c7be36f --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/MotionSensorService.java @@ -0,0 +1,121 @@ +package com.onboarding.camera.cameraonboarding.service.impl; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.MotionSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.CameraNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.repository.MotionSensorRepository; +import com.onboarding.camera.cameraonboarding.service.CameraService; +import com.onboarding.camera.cameraonboarding.service.SensorService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Slf4j +@RequiredArgsConstructor +@Service +public class MotionSensorService implements SensorService { + + private final MotionSensorRepository motionSensorRepository; + + private final CameraService cameraService; + + @Override + @Transactional + public MotionSensor handleCreateSensor(UUID cameraId, MotionSensor sensor) { + try { + sensor.setCamera(cameraService.getCameraById(cameraId)); + MotionSensor createdSensor = motionSensorRepository.save(sensor); + log.info("Creating sensor: {}", createdSensor); + return createdSensor; + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (Exception ex) { + log.error("Failed to create sensor, camera:{}:ex:{}", cameraId, ex.getMessage()); + throw new SensorNotCreatedException(String.format("Failed to create sensor: %s", ex.getMessage())); + } + } + + @Override + public List handleGetSensorsByCameraId(UUID cameraId) { + try { + Camera camera = cameraService.getCameraById(cameraId); + log.info("Getting sensors by camera id: {}", cameraId); + return motionSensorRepository.findMotionSensorByCamera(camera); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while getting sensors, cameraId:{}", cameraId); + throw new SensorNotFoundException(String.format("Error occurred while getting sensors: %s", ex.getMessage())); + } + } + + @Override + @Transactional + public MotionSensor handleUpdateSensor(UUID cameraId, UUID sensorId, MotionSensor sensor) { + try { + Camera camera = cameraService.getCameraById(cameraId); + MotionSensor existingSensor = camera.getSensors().stream() + .filter(s -> s.getId().equals(sensorId) && s.getSensorType().equals(SensorType.MOTION)) + .map(s -> (MotionSensor) s) + .findFirst() + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + + existingSensor.setName(sensor.getName()); + existingSensor.setVersion(sensor.getVersion()); + existingSensor.setData(sensor.getData()); + log.info("Updating sensor: {}", existingSensor); + return motionSensorRepository.save(existingSensor); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (SensorNotFoundException ex) { + log.error("Sensor not found while updating, sensorId: {}", sensorId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while updating sensor, sensorId:{}", sensorId); + throw new SensorNotUpdatedException(String.format("Error occurred while updating sensors: %s", ex.getMessage())); + } + } + + @Override + public MotionSensor getSensorById(UUID sensorId) { + + return motionSensorRepository.findById(sensorId) + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + } + + @Override + public void handleDeleteSensor(UUID cameraId, UUID sensorId) { + try { + Camera camera = cameraService.getCameraById(cameraId); + MotionSensor sensor = camera.getSensors().stream() + .filter(s -> s.getId().equals(sensorId) && s.getSensorType().equals(SensorType.MOTION)) + .map(s -> (MotionSensor) s) + .findFirst() + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + + camera.getSensors().remove(sensor); + motionSensorRepository.delete(sensor); + log.info("Deleted sensor: {}", sensorId); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (SensorNotFoundException ex) { + log.error("Sensor not found while deleting, sensorId: {}", sensorId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while deleting sensor, sensorId:{}", sensorId); + throw new SensorNotUpdatedException(String.format("Error occurred while deleting sensor: %s", ex.getMessage())); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/TemperatureSensorService.java b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/TemperatureSensorService.java new file mode 100644 index 0000000..f1a0835 --- /dev/null +++ b/src/main/java/com/onboarding/camera/cameraonboarding/service/impl/TemperatureSensorService.java @@ -0,0 +1,121 @@ +package com.onboarding.camera.cameraonboarding.service.impl; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.CameraNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.repository.TemperatureSensorRepository; +import com.onboarding.camera.cameraonboarding.service.CameraService; +import com.onboarding.camera.cameraonboarding.service.SensorService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Slf4j +@RequiredArgsConstructor +@Service +public class TemperatureSensorService implements SensorService { + + private final TemperatureSensorRepository temperatureSensorRepository; + + private final CameraService cameraService; + + @Override + @Transactional + public TemperatureSensor handleCreateSensor(UUID cameraId, TemperatureSensor sensor) { + try { + sensor.setCamera(cameraService.getCameraById(cameraId)); + TemperatureSensor createdSensor = temperatureSensorRepository.save(sensor); + log.info("Creating sensor: {}", createdSensor); + return createdSensor; + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (Exception ex) { + log.error("Failed to create sensor, camera:{}:ex:{}", cameraId, ex.getMessage()); + throw new SensorNotCreatedException(String.format("Failed to create sensor: %s", ex.getMessage())); + } + } + + @Override + public List handleGetSensorsByCameraId(UUID cameraId) { + try { + Camera camera = cameraService.getCameraById(cameraId); + log.info("Getting sensors by camera id: {}", cameraId); + return temperatureSensorRepository.findTemperatureSensorByCamera(camera); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while getting sensors, cameraId:{}", cameraId); + throw new SensorNotFoundException(String.format("Error occurred while getting sensors: %s", ex.getMessage())); + } + } + + @Override + @Transactional + public TemperatureSensor handleUpdateSensor(UUID cameraId, UUID sensorId, TemperatureSensor sensor) { + try { + Camera camera = cameraService.getCameraById(cameraId); + TemperatureSensor existingSensor = camera.getSensors().stream() + .filter(s -> s.getId().equals(sensorId) && s.getSensorType().equals(SensorType.TEMPERATURE)) + .map(s -> (TemperatureSensor) s) + .findFirst() + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + + existingSensor.setName(sensor.getName()); + existingSensor.setVersion(sensor.getVersion()); + existingSensor.setData(sensor.getData()); + log.info("Updating sensor: {}", existingSensor); + return temperatureSensorRepository.save(existingSensor); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (SensorNotFoundException ex) { + log.error("Sensor not found while updating, sensorId: {}", sensorId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while updating sensor, sensorId:{}", sensorId); + throw new SensorNotUpdatedException(String.format("Error occurred while updating sensors: %s", ex.getMessage())); + } + } + + @Override + public TemperatureSensor getSensorById(UUID sensorId) { + + return temperatureSensorRepository.findById(sensorId) + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + } + + @Override + public void handleDeleteSensor(UUID cameraId, UUID sensorId) { + try { + Camera camera = cameraService.getCameraById(cameraId); + TemperatureSensor sensor = camera.getSensors().stream() + .filter(s -> s.getId().equals(sensorId) && s.getSensorType().equals(SensorType.TEMPERATURE)) + .map(s -> (TemperatureSensor) s) + .findFirst() + .orElseThrow(() -> new SensorNotFoundException(String.format("Sensor not found with id: %s", sensorId))); + + camera.getSensors().remove(sensor); + temperatureSensorRepository.delete(sensor); + log.info("Deleted sensor: {}", sensorId); + } catch (CameraNotFoundException ex) { + log.error("Camera not found, cameraId:{}", cameraId); + throw ex; + } catch (SensorNotFoundException ex) { + log.error("Sensor not found while deleting, sensorId: {}", sensorId); + throw ex; + } catch (Exception ex) { + log.error("Exception occurred while deleting sensor, sensorId:{}", sensorId); + throw new SensorNotUpdatedException(String.format("Error occurred while deleting sensor: %s", ex.getMessage())); + } + } +} diff --git a/src/main/resources/db/changelog/changelog-master.xml b/src/main/resources/db/changelog/changelog-master.xml index fa0bdc8..7d48782 100644 --- a/src/main/resources/db/changelog/changelog-master.xml +++ b/src/main/resources/db/changelog/changelog-master.xml @@ -7,5 +7,6 @@ + \ No newline at end of file diff --git a/src/main/resources/db/changelog/changelog-v3.xml b/src/main/resources/db/changelog/changelog-v3.xml new file mode 100644 index 0000000..7979d4c --- /dev/null +++ b/src/main/resources/db/changelog/changelog-v3.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/controller/LightSensorControllerTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/controller/LightSensorControllerTest.java new file mode 100644 index 0000000..5c3ce2d --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/controller/LightSensorControllerTest.java @@ -0,0 +1,327 @@ +package com.onboarding.camera.cameraonboarding.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onboarding.camera.cameraonboarding.converter.SensorDtoConverter; +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.LightSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.service.impl.LightSensorService; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.Collections; +import java.util.UUID; + +@WebMvcTest(controllers = LightSensorController.class) +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +@Import(SensorDtoConverter.class) +class LightSensorControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private LightSensorService lightSensorService; + + @Autowired + private ObjectMapper objectMapper; + + private SensorDto sensorDto; + + private LightSensor sensor; + + private Camera camera; + + private final UUID SENSOR_ID = UUID.randomUUID(); + private final String SENSOR_NAME = "Light Sensor 1"; + private final SensorType SENSOR_TYPE = SensorType.LIGHT; + private final String SENSOR_VERSION = "v1.0"; + private final UUID CAMERA_ID = UUID.randomUUID(); + private final String CAMERA_NAME = "Camera 1"; + private final String FIRMWARE_VERSION = "v1.0.0"; + + @BeforeEach + void setUp() { + sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setSensorType(SENSOR_TYPE); + sensorDto.setVersion(SENSOR_VERSION); + sensor = new LightSensor(); + camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + } + + @Test + public void expect_handleCreateSensor_withValidSensorDto_returnCreated() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(lightSensorService.handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(LightSensor.class))).thenReturn(sensor); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/light", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isCreated()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", CoreMatchers.is(SENSOR_NAME))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(lightSensorService).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + public void expect_handleCreateSensor_withNullSensorName_returnBadRequest() throws Exception { + + // arrange + sensorDto.setName(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/light", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isBadRequest()); + + Mockito.verify(lightSensorService, Mockito.never()).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + public void expect_handleCreateSensor_withNullSensorType_returnBadRequest() throws Exception { + + // arrange + sensorDto.setSensorType(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/light", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isBadRequest()); + + Mockito.verify(lightSensorService, Mockito.never()).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + void expect_handleCreateLightSensor_withSensorNotCreatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotCreatedException("Failed to create sensor")) + .when(lightSensorService).handleCreateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.any(LightSensor.class)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/light", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(lightSensorService).handleCreateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + void expect_getLightSensors_withValidCameraId_returnOk() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(lightSensorService.handleGetSensorsByCameraId(CAMERA_ID)) + .thenReturn(Collections.singletonList(sensor)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/camera/{cameraId}/sensor/light", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON)); + + // assert + response.andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].name", CoreMatchers.is(SENSOR_NAME))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(lightSensorService).handleGetSensorsByCameraId(CAMERA_ID); + } + + @Test + void expect_getLightSensors_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/camera/{cameraId}/sensor/light", camera.getCamId()) + .contentType(MediaType.APPLICATION_JSON)); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + void expect_handleUpdateLightSensor_withValidRequest_returnOk() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + String updatedName = "Updated Name"; + sensor.setName(updatedName); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(lightSensorService.handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(LightSensor.class))) + .thenReturn(sensor); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", CoreMatchers.is(updatedName))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(lightSensorService).handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + void expect_handleUpdateLightSensor_withNullSensorId_returnNotFound() throws Exception { + + // arrange + sensor.setId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", CAMERA_ID, sensor.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(lightSensorService, Mockito.never()).handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(sensor.getId()), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + void expect_handleUpdateLightSensor_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(lightSensorService, Mockito.never()).handleUpdateSensor(Mockito.eq(camera.getCamId()), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + void expect_handleUpdateLightSensor_withSensorNotUpdatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotUpdatedException("Error occurred while deleting sensor")) + .when(lightSensorService).handleUpdateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID), ArgumentMatchers.any(LightSensor.class)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(lightSensorService).handleUpdateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID), ArgumentMatchers.any(LightSensor.class)); + } + + @Test + void expect_handleDeleteLightSensor_withValidRequest_returnNoContent() throws Exception { + // Act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON)); + + // Assert + response.andExpect(MockMvcResultMatchers.status().isNoContent()); + + Mockito.verify(lightSensorService).handleDeleteSensor(CAMERA_ID, SENSOR_ID); + } + + @Test + void expect_handleDeleteLightSensor_withNullSensorId_returnNotFound() throws Exception { + + // arrange + sensor.setId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", CAMERA_ID, sensor.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(lightSensorService, Mockito.never()).handleDeleteSensor(Mockito.eq(CAMERA_ID), Mockito.eq(sensor.getId())); + } + + @Test + void expect_handleDeleteLightSensor_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(lightSensorService, Mockito.never()).handleDeleteSensor(Mockito.eq(camera.getCamId()), Mockito.eq(SENSOR_ID)); + } + + @Test + void expect_handleDeleteLightSensor_withSensorNotUpdatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotUpdatedException("Error occurred while deleting sensor")) + .when(lightSensorService).handleDeleteSensor(CAMERA_ID, SENSOR_ID); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/light/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(lightSensorService).handleDeleteSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID)); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/controller/MotionSensorControllerTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/controller/MotionSensorControllerTest.java new file mode 100644 index 0000000..ea78dd4 --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/controller/MotionSensorControllerTest.java @@ -0,0 +1,327 @@ +package com.onboarding.camera.cameraonboarding.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onboarding.camera.cameraonboarding.converter.SensorDtoConverter; +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.MotionSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.service.impl.MotionSensorService; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.Collections; +import java.util.UUID; + +@WebMvcTest(controllers = MotionSensorController.class) +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +@Import(SensorDtoConverter.class) +class MotionSensorControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private MotionSensorService motionSensorService; + + @Autowired + private ObjectMapper objectMapper; + + private SensorDto sensorDto; + + private MotionSensor sensor; + + private Camera camera; + + private final UUID SENSOR_ID = UUID.randomUUID(); + private final String SENSOR_NAME = "Motion Sensor 1"; + private final SensorType SENSOR_TYPE = SensorType.MOTION; + private final String SENSOR_VERSION = "v1.0"; + private final UUID CAMERA_ID = UUID.randomUUID(); + private final String CAMERA_NAME = "Camera 1"; + private final String FIRMWARE_VERSION = "v1.0.0"; + + @BeforeEach + void setUp() { + sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setSensorType(SENSOR_TYPE); + sensorDto.setVersion(SENSOR_VERSION); + sensor = new MotionSensor(); + camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + } + + @Test + public void expect_handleCreateSensor_withValidSensorDto_returnCreated() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(motionSensorService.handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(MotionSensor.class))).thenReturn(sensor); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/motion", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isCreated()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", CoreMatchers.is(SENSOR_NAME))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(motionSensorService).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + public void expect_handleCreateSensor_withNullSensorName_returnBadRequest() throws Exception { + + // arrange + sensorDto.setName(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/motion", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isBadRequest()); + + Mockito.verify(motionSensorService, Mockito.never()).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + public void expect_handleCreateSensor_withNullSensorType_returnBadRequest() throws Exception { + + // arrange + sensorDto.setSensorType(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/motion", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isBadRequest()); + + Mockito.verify(motionSensorService, Mockito.never()).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + void expect_handleCreateMotionSensor_withSensorNotCreatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotCreatedException("Failed to create sensor")) + .when(motionSensorService).handleCreateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.any(MotionSensor.class)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/motion", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(motionSensorService).handleCreateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + void expect_getMotionSensors_withValidCameraId_returnOk() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(motionSensorService.handleGetSensorsByCameraId(CAMERA_ID)) + .thenReturn(Collections.singletonList(sensor)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/camera/{cameraId}/sensor/motion", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON)); + + // assert + response.andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].name", CoreMatchers.is(SENSOR_NAME))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(motionSensorService).handleGetSensorsByCameraId(CAMERA_ID); + } + + @Test + void expect_getMotionSensors_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/camera/{cameraId}/sensor/motion", camera.getCamId()) + .contentType(MediaType.APPLICATION_JSON)); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + void expect_handleUpdateMotionSensor_withValidRequest_returnOk() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + String updatedName = "Updated Name"; + sensor.setName(updatedName); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(motionSensorService.handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(MotionSensor.class))) + .thenReturn(sensor); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", CoreMatchers.is(updatedName))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(motionSensorService).handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + void expect_handleUpdateMotionSensor_withNullSensorId_returnNotFound() throws Exception { + + // arrange + sensor.setId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", CAMERA_ID, sensor.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(motionSensorService, Mockito.never()).handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(sensor.getId()), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + void expect_handleUpdateMotionSensor_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(motionSensorService, Mockito.never()).handleUpdateSensor(Mockito.eq(camera.getCamId()), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + void expect_handleUpdateMotionSensor_withSensorNotUpdatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotUpdatedException("Error occurred while deleting sensor")) + .when(motionSensorService).handleUpdateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID), ArgumentMatchers.any(MotionSensor.class)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(motionSensorService).handleUpdateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID), ArgumentMatchers.any(MotionSensor.class)); + } + + @Test + void expect_handleDeleteMotionSensor_withValidRequest_returnNoContent() throws Exception { + // Act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON)); + + // Assert + response.andExpect(MockMvcResultMatchers.status().isNoContent()); + + Mockito.verify(motionSensorService).handleDeleteSensor(CAMERA_ID, SENSOR_ID); + } + + @Test + void expect_handleDeleteMotionSensor_withNullSensorId_returnNotFound() throws Exception { + + // arrange + sensor.setId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", CAMERA_ID, sensor.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(motionSensorService, Mockito.never()).handleDeleteSensor(Mockito.eq(CAMERA_ID), Mockito.eq(sensor.getId())); + } + + @Test + void expect_handleDeleteMotionSensor_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(motionSensorService, Mockito.never()).handleDeleteSensor(Mockito.eq(camera.getCamId()), Mockito.eq(SENSOR_ID)); + } + + @Test + void expect_handleDeleteMotionSensor_withSensorNotUpdatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotUpdatedException("Error occurred while deleting sensor")) + .when(motionSensorService).handleDeleteSensor(CAMERA_ID, SENSOR_ID); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/motion/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(motionSensorService).handleDeleteSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID)); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/controller/TemperatureSensorControllerTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/controller/TemperatureSensorControllerTest.java new file mode 100644 index 0000000..cc75675 --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/controller/TemperatureSensorControllerTest.java @@ -0,0 +1,327 @@ +package com.onboarding.camera.cameraonboarding.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.onboarding.camera.cameraonboarding.converter.SensorDtoConverter; +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.service.impl.TemperatureSensorService; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.Collections; +import java.util.UUID; + +@WebMvcTest(controllers = TemperatureSensorController.class) +@AutoConfigureMockMvc(addFilters = false) +@ExtendWith(MockitoExtension.class) +@Import(SensorDtoConverter.class) +class TemperatureSensorControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private TemperatureSensorService temperatureSensorService; + + @Autowired + private ObjectMapper objectMapper; + + private SensorDto sensorDto; + + private TemperatureSensor sensor; + + private Camera camera; + + private final UUID SENSOR_ID = UUID.randomUUID(); + private final String SENSOR_NAME = "Temperature Sensor 1"; + private final SensorType SENSOR_TYPE = SensorType.TEMPERATURE; + private final String SENSOR_VERSION = "v1.0"; + private final UUID CAMERA_ID = UUID.randomUUID(); + private final String CAMERA_NAME = "Camera 1"; + private final String FIRMWARE_VERSION = "v1.0.0"; + + @BeforeEach + void setUp() { + sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setSensorType(SENSOR_TYPE); + sensorDto.setVersion(SENSOR_VERSION); + sensor = new TemperatureSensor(); + camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + } + + @Test + public void expect_handleCreateSensor_withValidSensorDto_returnCreated() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(temperatureSensorService.handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(TemperatureSensor.class))).thenReturn(sensor); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/temperature", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isCreated()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", CoreMatchers.is(SENSOR_NAME))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(temperatureSensorService).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + public void expect_handleCreateSensor_withNullSensorName_returnBadRequest() throws Exception { + + // arrange + sensorDto.setName(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/temperature", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isBadRequest()); + + Mockito.verify(temperatureSensorService, Mockito.never()).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + public void expect_handleCreateSensor_withNullSensorType_returnBadRequest() throws Exception { + + // arrange + sensorDto.setSensorType(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/temperature", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isBadRequest()); + + Mockito.verify(temperatureSensorService, Mockito.never()).handleCreateSensor(Mockito.eq(CAMERA_ID), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + void expect_handleCreateTemperatureSensor_withSensorNotCreatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotCreatedException("Failed to create sensor")) + .when(temperatureSensorService).handleCreateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.any(TemperatureSensor.class)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/camera/{cameraId}/sensor/temperature", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(temperatureSensorService).handleCreateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + void expect_getTemperatureSensors_withValidCameraId_returnOk() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(temperatureSensorService.handleGetSensorsByCameraId(CAMERA_ID)) + .thenReturn(Collections.singletonList(sensor)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/camera/{cameraId}/sensor/temperature", CAMERA_ID) + .contentType(MediaType.APPLICATION_JSON)); + + // assert + response.andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].name", CoreMatchers.is(SENSOR_NAME))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(temperatureSensorService).handleGetSensorsByCameraId(CAMERA_ID); + } + + @Test + void expect_getTemperatureSensors_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/camera/{cameraId}/sensor/temperature", camera.getCamId()) + .contentType(MediaType.APPLICATION_JSON)); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + void expect_handleUpdateTemperatureSensor_withValidRequest_returnOk() throws Exception { + + // arrange + sensor.setId(SENSOR_ID); + String updatedName = "Updated Name"; + sensor.setName(updatedName); + sensor.setSensorType(SENSOR_TYPE); + Mockito.when(temperatureSensorService.handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(TemperatureSensor.class))) + .thenReturn(sensor); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id", CoreMatchers.is(SENSOR_ID.toString()))) + .andExpect(MockMvcResultMatchers.jsonPath("$.name", CoreMatchers.is(updatedName))) + .andExpect(MockMvcResultMatchers.jsonPath("$.sensorType", CoreMatchers.is(SENSOR_TYPE.toString()))); + + Mockito.verify(temperatureSensorService).handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + void expect_handleUpdateTemperatureSensor_withNullSensorId_returnNotFound() throws Exception { + + // arrange + sensor.setId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", CAMERA_ID, sensor.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(temperatureSensorService, Mockito.never()).handleUpdateSensor(Mockito.eq(CAMERA_ID), Mockito.eq(sensor.getId()), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + void expect_handleUpdateTemperatureSensor_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(temperatureSensorService, Mockito.never()).handleUpdateSensor(Mockito.eq(camera.getCamId()), Mockito.eq(SENSOR_ID), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + void expect_handleUpdateTemperatureSensor_withSensorNotUpdatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotUpdatedException("Error occurred while deleting sensor")) + .when(temperatureSensorService).handleUpdateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID), ArgumentMatchers.any(TemperatureSensor.class)); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.put("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(temperatureSensorService).handleUpdateSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID), ArgumentMatchers.any(TemperatureSensor.class)); + } + + @Test + void expect_handleDeleteTemperatureSensor_withValidRequest_returnNoContent() throws Exception { + // Act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", CAMERA_ID, SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON)); + + // Assert + response.andExpect(MockMvcResultMatchers.status().isNoContent()); + + Mockito.verify(temperatureSensorService).handleDeleteSensor(CAMERA_ID, SENSOR_ID); + } + + @Test + void expect_handleDeleteTemperatureSensor_withNullSensorId_returnNotFound() throws Exception { + + // arrange + sensor.setId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", CAMERA_ID, sensor.getId()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(temperatureSensorService, Mockito.never()).handleDeleteSensor(Mockito.eq(CAMERA_ID), Mockito.eq(sensor.getId())); + } + + @Test + void expect_handleDeleteTemperatureSensor_withNullCameraId_returnNotFound() throws Exception { + + // arrange + camera.setCamId(null); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isNotFound()); + + Mockito.verify(temperatureSensorService, Mockito.never()).handleDeleteSensor(Mockito.eq(camera.getCamId()), Mockito.eq(SENSOR_ID)); + } + + @Test + void expect_handleDeleteTemperatureSensor_withSensorNotUpdatedException_returnInternalServerError() throws Exception { + + // arrange + Mockito.doThrow(new SensorNotUpdatedException("Error occurred while deleting sensor")) + .when(temperatureSensorService).handleDeleteSensor(CAMERA_ID, SENSOR_ID); + + // act + ResultActions response = mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/camera/{cameraId}/sensor/temperature/{sensorId}", camera.getCamId(), SENSOR_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(sensorDto))); + + // assert + response.andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + Mockito.verify(temperatureSensorService).handleDeleteSensor(ArgumentMatchers.eq(CAMERA_ID), ArgumentMatchers.eq(SENSOR_ID)); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/converter/SensorDtoConverterTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/converter/SensorDtoConverterTest.java new file mode 100644 index 0000000..3eaf573 --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/converter/SensorDtoConverterTest.java @@ -0,0 +1,145 @@ +package com.onboarding.camera.cameraonboarding.converter; + +import com.onboarding.camera.cameraonboarding.dto.SensorDto; +import com.onboarding.camera.cameraonboarding.dto.SensorResponse; +import com.onboarding.camera.cameraonboarding.entity.Sensor; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.SensorMismatchException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotCreatedException; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +class SensorDtoConverterTest { + + private SensorDtoConverter sensorDtoConverter; + + private final UUID SENSOR_ID = UUID.randomUUID(); + private final String SENSOR_NAME = "Sensor 1"; + private final String SENSOR_VERSION = "v1.0"; + private final SensorType SENSOR_TYPE_LIGHT = SensorType.LIGHT; + private final String SENSOR_DATA = "Sensor data"; + private final SensorType SENSOR_TYPE_TEMPERATURE = SensorType.TEMPERATURE; + + @BeforeEach + void setUp() { + sensorDtoConverter = new SensorDtoConverter(); + } + + @Test + void expect_convert_withValidSensorDto_returnSensor() { + // arrange + SensorDto sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setVersion(SENSOR_VERSION); + sensorDto.setSensorType(SENSOR_TYPE_LIGHT); + sensorDto.setData(SENSOR_DATA); + + // act + Sensor sensor = sensorDtoConverter.toLightEntity(sensorDto); + + // assert + Assertions.assertThat(sensor).isNotNull(); + Assertions.assertThat(sensor.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(sensor.getVersion()).isEqualTo(SENSOR_VERSION); + Assertions.assertThat(sensor.getSensorType()).isEqualTo(SENSOR_TYPE_LIGHT); + Assertions.assertThat(sensor.getData()).isEqualTo(SENSOR_DATA); + } + + @Test + void expect_convert_withValidSensor_returnSensorDto() { + // arrange + Sensor sensor = new TemperatureSensor(); + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setVersion(SENSOR_VERSION); + sensor.setSensorType(SENSOR_TYPE_LIGHT); + sensor.setData(SENSOR_DATA); + + // act + SensorResponse response = sensorDtoConverter.toSensorResponse(sensor); + + // assert + Assertions.assertThat(response).isNotNull(); + Assertions.assertThat(response.getId()).isEqualTo(SENSOR_ID); + Assertions.assertThat(response.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(response.getVersion()).isEqualTo(SENSOR_VERSION); + Assertions.assertThat(response.getSensorType()).isEqualTo(SENSOR_TYPE_LIGHT); + Assertions.assertThat(response.getData()).isEqualTo(SENSOR_DATA); + } + + @Test + void expect_convert_withNullSensorName_throwsSensorNotCreatedException() { + // arrange + SensorDto sensorDto = new SensorDto(); + sensorDto.setName(null); + + + // act and assert + Assertions.assertThatThrownBy(() -> sensorDtoConverter.toLightEntity(sensorDto)) + .isInstanceOf(SensorNotCreatedException.class) + .hasMessage("Sensor name cannot be null"); + } + + @Test + void expect_convert_withNullSensorVersion_throwsSensorNotCreatedException() { + // arrange + SensorDto sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setVersion(null); + + + // act and assert + Assertions.assertThatThrownBy(() -> sensorDtoConverter.toLightEntity(sensorDto)) + .isInstanceOf(SensorNotCreatedException.class) + .hasMessage("Sensor version cannot be null"); + } + + @Test + void expect_convert_withNullSensorType_throwsSensorNotCreatedException() { + // arrange + SensorDto sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setVersion(SENSOR_VERSION); + sensorDto.setSensorType(null); + + + // act and assert + Assertions.assertThatThrownBy(() -> sensorDtoConverter.toLightEntity(sensorDto)) + .isInstanceOf(SensorNotCreatedException.class) + .hasMessage("Sensor type cannot be null"); + } + + @Test + void expect_convertToLightEntity_withWrongSensorType_throwsSensorMismatchException() { + // arrange + SensorDto sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setVersion(SENSOR_VERSION); + sensorDto.setSensorType(SENSOR_TYPE_TEMPERATURE); + + + // act and assert + Assertions.assertThatThrownBy(() -> sensorDtoConverter.toLightEntity(sensorDto)) + .isInstanceOf(SensorMismatchException.class) + .hasMessage("Invalid sensor type for LightSensor"); + } + + @Test + void expect_convertToTemperatureEntity_withWrongSensorType_throwsSensorMismatchException() { + // arrange + SensorDto sensorDto = new SensorDto(); + sensorDto.setName(SENSOR_NAME); + sensorDto.setVersion(SENSOR_VERSION); + sensorDto.setSensorType(SENSOR_TYPE_LIGHT); + + + // act and assert + Assertions.assertThatThrownBy(() -> sensorDtoConverter.toTemperatureEntity(sensorDto)) + .isInstanceOf(SensorMismatchException.class) + .hasMessage("Invalid sensor type for TemperatureSensor"); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/repository/LightSensorRepositoryTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/repository/LightSensorRepositoryTest.java new file mode 100644 index 0000000..526b975 --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/repository/LightSensorRepositoryTest.java @@ -0,0 +1,211 @@ +package com.onboarding.camera.cameraonboarding.repository; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.LightSensor; +import com.onboarding.camera.cameraonboarding.entity.Sensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import org.assertj.core.api.Assertions; +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.dao.DataIntegrityViolationException; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@DataJpaTest +class LightSensorRepositoryTest { + + @Autowired + LightSensorRepository lightSensorRepository; + + @Autowired + CameraRepository cameraRepository; + + private LightSensor lightSensor; + + private final String SENSOR_NAME = "Light Sensor 1"; + private final String SENSOR_NAME_2 = "Light Sensor 2"; + private final SensorType SENSOR_TYPE = SensorType.LIGHT; + private final UUID NON_EXISTING_UUID = UUID.fromString("ef556dc0-0ddc-4f39-a96d-6886a54eee54"); + private final UUID CAMERA_ID = UUID.randomUUID(); + private final String CAMERA_NAME = "Camera 1"; + private final String FIRMWARE_VERSION = "v1.0"; + + @BeforeEach + void setUp() { + lightSensor = new LightSensor(); + lightSensor.setName(SENSOR_NAME); + lightSensor.setSensorType(SENSOR_TYPE); + } + + @Test + public void expect_save_sensorRepository_saveAll_returnsSavedSensor() { + + // act + Sensor savedSensor = lightSensorRepository.save(lightSensor); + + // assert + Assertions.assertThat(savedSensor).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(savedSensor.getSensorType()).isNotNull(); + Assertions.assertThat(savedSensor.getSensorType()).isEqualTo(SENSOR_TYPE); + Assertions.assertThat(savedSensor.getId()).isNotNull(); + } + + @Test + public void expect_save_sensorWithNullName_throwsException() { + + // arrange + lightSensor.setName(null); + + // act and assert + Assertions.assertThatThrownBy(() -> + lightSensorRepository.saveAndFlush(lightSensor) + ).isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + public void expect_save_sensorWithNullType_throwsException() { + + // arrange + lightSensor.setSensorType(null); + + // act and assert + Assertions.assertThatThrownBy(() -> + lightSensorRepository.saveAndFlush(lightSensor) + ).isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + public void expect_findById_lightSensorRepository_returnsSensor() { + + // arrange + lightSensorRepository.save(lightSensor); + + // act + Optional foundSensor = lightSensorRepository.findById(lightSensor.getId()); + + //assert + Assertions.assertThat(foundSensor).isPresent(); + Assertions.assertThat(foundSensor.get().getId()).isEqualTo(lightSensor.getId()); + } + + @Test + public void expect_findById_sensorWithNotExistingId_throwsException() { + + // act + Optional foundSensor = lightSensorRepository.findById(NON_EXISTING_UUID); + + // assert + Assertions.assertThat(foundSensor).isEmpty(); + } + + @Test + public void expect_delete_sensorWithExistingId_returnsVoid() { + + // Arrange + LightSensor savedSensor = lightSensorRepository.save(lightSensor); + Camera associatedCamera = new Camera(); + associatedCamera.setCamId(CAMERA_ID); + associatedCamera.setCameraName(CAMERA_NAME); + associatedCamera.setFirmwareVersion(FIRMWARE_VERSION); + savedSensor.setCamera(associatedCamera); + lightSensorRepository.save(savedSensor); + + // Act + lightSensorRepository.delete(savedSensor); + + // Assert + Optional foundSensor = lightSensorRepository.findById(savedSensor.getId()); + Assertions.assertThat(foundSensor).isEmpty(); + } + + @Test + public void expect_deleteCamera_removesAssociatedSensors() { + + // Arrange + Camera camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + camera = cameraRepository.save(camera); + + LightSensor sensor1 = new LightSensor(); + sensor1.setName(SENSOR_NAME); + sensor1.setSensorType(SENSOR_TYPE); + sensor1.setCamera(camera); + + LightSensor sensor2 = new LightSensor(); + sensor2.setName(SENSOR_NAME_2); + sensor2.setSensorType(SENSOR_TYPE); + sensor2.setCamera(camera); + + camera.getSensors().add(sensor1); + camera.getSensors().add(sensor2); + + lightSensorRepository.save(sensor1); + lightSensorRepository.save(sensor2); + + // Act + cameraRepository.delete(camera); + + // Assert + Assertions.assertThat(lightSensorRepository.findLightSensorByCamera(camera)).isEmpty(); + } + + @Test + public void expect_findLightSensorsByCamera_returnsLightSensors() { + // Arrange + Camera camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + Camera savedCamera = cameraRepository.save(camera); + + LightSensor sensor1 = new LightSensor(); + sensor1.setName(SENSOR_NAME); + sensor1.setSensorType(SENSOR_TYPE); + sensor1.setCamera(savedCamera); + + LightSensor sensor2 = new LightSensor(); + sensor2.setName(SENSOR_NAME_2); + sensor2.setSensorType(SENSOR_TYPE); + sensor2.setCamera(savedCamera); + + lightSensorRepository.save(sensor1); + lightSensorRepository.save(sensor2); + + // Act + List sensors = lightSensorRepository.findLightSensorByCamera(savedCamera); + + // Assert + Assertions.assertThat(sensors).hasSize(2); + Assertions.assertThat(sensors).extracting(LightSensor::getName) + .containsExactlyInAnyOrder(SENSOR_NAME, SENSOR_NAME_2); + } + + @Test + public void expect_updateSensor_withValidSensor_returnsUpdatedSensor() { + // Arrange + LightSensor savedSensor = lightSensorRepository.save(lightSensor); + String updatedName = "Updated Sensor Name"; + String updatedSensorVersion = "v1.1"; + String updatedSensorData = "Sensor Data"; + + // Act + savedSensor.setName(updatedName); + savedSensor.setVersion(updatedSensorVersion); + savedSensor.setData(updatedSensorData); + LightSensor updatedSensor = lightSensorRepository.save(savedSensor); + + // Assert + Assertions.assertThat(updatedSensor).isNotNull(); + Assertions.assertThat(updatedSensor.getName()).isEqualTo(updatedName); + Assertions.assertThat(updatedSensor.getVersion()).isEqualTo(updatedSensorVersion); + Assertions.assertThat(updatedSensor.getData()).isEqualTo(updatedSensorData); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/repository/MotionSensorRepositoryTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/repository/MotionSensorRepositoryTest.java new file mode 100644 index 0000000..59d9bbd --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/repository/MotionSensorRepositoryTest.java @@ -0,0 +1,211 @@ +package com.onboarding.camera.cameraonboarding.repository; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.MotionSensor; +import com.onboarding.camera.cameraonboarding.entity.Sensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import org.assertj.core.api.Assertions; +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.dao.DataIntegrityViolationException; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@DataJpaTest +class MotionSensorRepositoryTest { + + @Autowired + MotionSensorRepository motionSensorRepository; + + @Autowired + CameraRepository cameraRepository; + + private MotionSensor motionSensor; + + private final String SENSOR_NAME = "Motion Sensor 1"; + private final String SENSOR_NAME_2 = "Motion Sensor 2"; + private final SensorType SENSOR_TYPE = SensorType.MOTION; + private final UUID NON_EXISTING_UUID = UUID.fromString("ef556dc0-0ddc-4f39-a96d-6886a54eee54"); + private final UUID CAMERA_ID = UUID.randomUUID(); + private final String CAMERA_NAME = "Camera 1"; + private final String FIRMWARE_VERSION = "v1.0"; + + @BeforeEach + void setUp() { + motionSensor = new MotionSensor(); + motionSensor.setName(SENSOR_NAME); + motionSensor.setSensorType(SENSOR_TYPE); + } + + @Test + public void expect_save_sensorRepository_saveAll_returnsSavedSensor() { + + // act + Sensor savedSensor = motionSensorRepository.save(motionSensor); + + // assert + Assertions.assertThat(savedSensor).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(savedSensor.getSensorType()).isNotNull(); + Assertions.assertThat(savedSensor.getSensorType()).isEqualTo(SENSOR_TYPE); + Assertions.assertThat(savedSensor.getId()).isNotNull(); + } + + @Test + public void expect_save_sensorWithNullName_throwsException() { + + // arrange + motionSensor.setName(null); + + // act and assert + Assertions.assertThatThrownBy(() -> + motionSensorRepository.saveAndFlush(motionSensor) + ).isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + public void expect_save_sensorWithNullType_throwsException() { + + // arrange + motionSensor.setSensorType(null); + + // act and assert + Assertions.assertThatThrownBy(() -> + motionSensorRepository.saveAndFlush(motionSensor) + ).isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + public void expect_findById_motionSensorRepository_returnsSensor() { + + // arrange + motionSensorRepository.save(motionSensor); + + // act + Optional foundSensor = motionSensorRepository.findById(motionSensor.getId()); + + //assert + Assertions.assertThat(foundSensor).isPresent(); + Assertions.assertThat(foundSensor.get().getId()).isEqualTo(motionSensor.getId()); + } + + @Test + public void expect_findById_sensorWithNotExistingId_throwsException() { + + // act + Optional foundSensor = motionSensorRepository.findById(NON_EXISTING_UUID); + + // assert + Assertions.assertThat(foundSensor).isEmpty(); + } + + @Test + public void expect_delete_sensorWithExistingId_returnsVoid() { + + // Arrange + MotionSensor savedSensor = motionSensorRepository.save(motionSensor); + Camera associatedCamera = new Camera(); + associatedCamera.setCamId(CAMERA_ID); + associatedCamera.setCameraName(CAMERA_NAME); + associatedCamera.setFirmwareVersion(FIRMWARE_VERSION); + savedSensor.setCamera(associatedCamera); + motionSensorRepository.save(savedSensor); + + // Act + motionSensorRepository.delete(savedSensor); + + // Assert + Optional foundSensor = motionSensorRepository.findById(savedSensor.getId()); + Assertions.assertThat(foundSensor).isEmpty(); + } + + @Test + public void expect_deleteCamera_removesAssociatedSensors() { + + // Arrange + Camera camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + camera = cameraRepository.save(camera); + + MotionSensor sensor1 = new MotionSensor(); + sensor1.setName(SENSOR_NAME); + sensor1.setSensorType(SENSOR_TYPE); + sensor1.setCamera(camera); + + MotionSensor sensor2 = new MotionSensor(); + sensor2.setName(SENSOR_NAME_2); + sensor2.setSensorType(SENSOR_TYPE); + sensor2.setCamera(camera); + + camera.getSensors().add(sensor1); + camera.getSensors().add(sensor2); + + motionSensorRepository.save(sensor1); + motionSensorRepository.save(sensor2); + + // Act + cameraRepository.delete(camera); + + // Assert + Assertions.assertThat(motionSensorRepository.findMotionSensorByCamera(camera)).isEmpty(); + } + + @Test + public void expect_findMotionSensorsByCamera_returnsMotionSensors() { + // Arrange + Camera camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + Camera savedCamera = cameraRepository.save(camera); + + MotionSensor sensor1 = new MotionSensor(); + sensor1.setName(SENSOR_NAME); + sensor1.setSensorType(SENSOR_TYPE); + sensor1.setCamera(savedCamera); + + MotionSensor sensor2 = new MotionSensor(); + sensor2.setName(SENSOR_NAME_2); + sensor2.setSensorType(SENSOR_TYPE); + sensor2.setCamera(savedCamera); + + motionSensorRepository.save(sensor1); + motionSensorRepository.save(sensor2); + + // Act + List sensors = motionSensorRepository.findMotionSensorByCamera(savedCamera); + + // Assert + Assertions.assertThat(sensors).hasSize(2); + Assertions.assertThat(sensors).extracting(MotionSensor::getName) + .containsExactlyInAnyOrder(SENSOR_NAME, SENSOR_NAME_2); + } + + @Test + public void expect_updateSensor_withValidSensor_returnsUpdatedSensor() { + // Arrange + MotionSensor savedSensor = motionSensorRepository.save(motionSensor); + String updatedName = "Updated Sensor Name"; + String updatedSensorVersion = "v1.1"; + String updatedSensorData = "Sensor Data"; + + // Act + savedSensor.setName(updatedName); + savedSensor.setVersion(updatedSensorVersion); + savedSensor.setData(updatedSensorData); + MotionSensor updatedSensor = motionSensorRepository.save(savedSensor); + + // Assert + Assertions.assertThat(updatedSensor).isNotNull(); + Assertions.assertThat(updatedSensor.getName()).isEqualTo(updatedName); + Assertions.assertThat(updatedSensor.getVersion()).isEqualTo(updatedSensorVersion); + Assertions.assertThat(updatedSensor.getData()).isEqualTo(updatedSensorData); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/repository/TemperatureSensorRepositoryTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/repository/TemperatureSensorRepositoryTest.java new file mode 100644 index 0000000..5df5764 --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/repository/TemperatureSensorRepositoryTest.java @@ -0,0 +1,211 @@ +package com.onboarding.camera.cameraonboarding.repository; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.Sensor; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import org.assertj.core.api.Assertions; +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.dao.DataIntegrityViolationException; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@DataJpaTest +class TemperatureSensorRepositoryTest { + + @Autowired + TemperatureSensorRepository temperatureSensorRepository; + + @Autowired + CameraRepository cameraRepository; + + private TemperatureSensor temperatureSensor; + + private final String SENSOR_NAME = "Temperature Sensor 1"; + private final String SENSOR_NAME_2 = "Temperature Sensor 2"; + private final SensorType SENSOR_TYPE = SensorType.TEMPERATURE; + private final UUID NON_EXISTING_UUID = UUID.fromString("ef556dc0-0ddc-4f39-a96d-6886a54eee54"); + private final UUID CAMERA_ID = UUID.randomUUID(); + private final String CAMERA_NAME = "Camera 1"; + private final String FIRMWARE_VERSION = "v1.0"; + + @BeforeEach + void setUp() { + temperatureSensor = new TemperatureSensor(); + temperatureSensor.setName(SENSOR_NAME); + temperatureSensor.setSensorType(SENSOR_TYPE); + } + + @Test + public void expect_save_sensorRepository_saveAll_returnsSavedSensor() { + + // act + Sensor savedSensor = temperatureSensorRepository.save(temperatureSensor); + + // assert + Assertions.assertThat(savedSensor).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(savedSensor.getSensorType()).isNotNull(); + Assertions.assertThat(savedSensor.getSensorType()).isEqualTo(SENSOR_TYPE); + Assertions.assertThat(savedSensor.getId()).isNotNull(); + } + + @Test + public void expect_save_sensorWithNullName_throwsException() { + + // arrange + temperatureSensor.setName(null); + + // act and assert + Assertions.assertThatThrownBy(() -> + temperatureSensorRepository.saveAndFlush(temperatureSensor) + ).isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + public void expect_save_sensorWithNullType_throwsException() { + + // arrange + temperatureSensor.setSensorType(null); + + // act and assert + Assertions.assertThatThrownBy(() -> + temperatureSensorRepository.saveAndFlush(temperatureSensor) + ).isInstanceOf(DataIntegrityViolationException.class); + } + + @Test + public void expect_findById_temperatureSensorRepository_returnsSensor() { + + // arrange + temperatureSensorRepository.save(temperatureSensor); + + // act + Optional foundSensor = temperatureSensorRepository.findById(temperatureSensor.getId()); + + //assert + Assertions.assertThat(foundSensor).isPresent(); + Assertions.assertThat(foundSensor.get().getId()).isEqualTo(temperatureSensor.getId()); + } + + @Test + public void expect_findById_sensorWithNotExistingId_throwsException() { + + // act + Optional foundSensor = temperatureSensorRepository.findById(NON_EXISTING_UUID); + + // assert + Assertions.assertThat(foundSensor).isEmpty(); + } + + @Test + public void expect_delete_sensorWithExistingId_returnsVoid() { + + // Arrange + TemperatureSensor savedSensor = temperatureSensorRepository.save(temperatureSensor); + Camera associatedCamera = new Camera(); + associatedCamera.setCamId(CAMERA_ID); + associatedCamera.setCameraName(CAMERA_NAME); + associatedCamera.setFirmwareVersion(FIRMWARE_VERSION); + savedSensor.setCamera(associatedCamera); + temperatureSensorRepository.save(savedSensor); + + // Act + temperatureSensorRepository.delete(savedSensor); + + // Assert + Optional foundSensor = temperatureSensorRepository.findById(savedSensor.getId()); + Assertions.assertThat(foundSensor).isEmpty(); + } + + @Test + public void expect_deleteCamera_removesAssociatedSensors() { + + // Arrange + Camera camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + camera = cameraRepository.save(camera); + + TemperatureSensor sensor1 = new TemperatureSensor(); + sensor1.setName(SENSOR_NAME); + sensor1.setSensorType(SENSOR_TYPE); + sensor1.setCamera(camera); + + TemperatureSensor sensor2 = new TemperatureSensor(); + sensor2.setName(SENSOR_NAME_2); + sensor2.setSensorType(SENSOR_TYPE); + sensor2.setCamera(camera); + + camera.getSensors().add(sensor1); + camera.getSensors().add(sensor2); + + temperatureSensorRepository.save(sensor1); + temperatureSensorRepository.save(sensor2); + + // Act + cameraRepository.delete(camera); + + // Assert + Assertions.assertThat(temperatureSensorRepository.findTemperatureSensorByCamera(camera)).isEmpty(); + } + + @Test + public void expect_findTemperatureSensorsByCamera_returnsTemperatureSensors() { + // Arrange + Camera camera = new Camera(); + camera.setCamId(CAMERA_ID); + camera.setCameraName(CAMERA_NAME); + camera.setFirmwareVersion(FIRMWARE_VERSION); + Camera savedCamera = cameraRepository.save(camera); + + TemperatureSensor sensor1 = new TemperatureSensor(); + sensor1.setName(SENSOR_NAME); + sensor1.setSensorType(SENSOR_TYPE); + sensor1.setCamera(savedCamera); + + TemperatureSensor sensor2 = new TemperatureSensor(); + sensor2.setName(SENSOR_NAME_2); + sensor2.setSensorType(SENSOR_TYPE); + sensor2.setCamera(savedCamera); + + temperatureSensorRepository.save(sensor1); + temperatureSensorRepository.save(sensor2); + + // Act + List sensors = temperatureSensorRepository.findTemperatureSensorByCamera(savedCamera); + + // Assert + Assertions.assertThat(sensors).hasSize(2); + Assertions.assertThat(sensors).extracting(TemperatureSensor::getName) + .containsExactlyInAnyOrder(SENSOR_NAME, SENSOR_NAME_2); + } + + @Test + public void expect_updateSensor_withValidSensor_returnsUpdatedSensor() { + // Arrange + TemperatureSensor savedSensor = temperatureSensorRepository.save(temperatureSensor); + String updatedName = "Updated Sensor Name"; + String updatedSensorVersion = "v1.1"; + String updatedSensorData = "Sensor Data"; + + // Act + savedSensor.setName(updatedName); + savedSensor.setVersion(updatedSensorVersion); + savedSensor.setData(updatedSensorData); + TemperatureSensor updatedSensor = temperatureSensorRepository.save(savedSensor); + + // Assert + Assertions.assertThat(updatedSensor).isNotNull(); + Assertions.assertThat(updatedSensor.getName()).isEqualTo(updatedName); + Assertions.assertThat(updatedSensor.getVersion()).isEqualTo(updatedSensorVersion); + Assertions.assertThat(updatedSensor.getData()).isEqualTo(updatedSensorData); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/service/CameraServiceImplTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/service/CameraServiceImplTest.java index 753084c..f8149a0 100644 --- a/src/test/java/com/onboarding/camera/cameraonboarding/service/CameraServiceImplTest.java +++ b/src/test/java/com/onboarding/camera/cameraonboarding/service/CameraServiceImplTest.java @@ -245,11 +245,11 @@ void expect_getCameraById_toGetCamera() { } @Test - void expect_getCameraById_withNullCameraId_toThrowIllegalArgumentException() { + void expect_getCameraById_withNonExistingUUID_toThrowCameraNotFoundException() { // act and assert - Assertions.assertThatThrownBy(() -> cameraService.getCameraById(null)) - .isInstanceOf(IllegalArgumentException.class); + Assertions.assertThatThrownBy(() -> cameraService.getCameraById(NON_EXISTING_UUID)) + .isInstanceOf(CameraNotFoundException.class); Mockito.verify(cameraRepository, Mockito.never()).findById(CAMERA_ID); } diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/LightSensorServiceTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/LightSensorServiceTest.java new file mode 100644 index 0000000..aa47bac --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/LightSensorServiceTest.java @@ -0,0 +1,258 @@ +package com.onboarding.camera.cameraonboarding.service.impl; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.LightSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.CameraNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.repository.LightSensorRepository; +import com.onboarding.camera.cameraonboarding.service.CameraService; +import jakarta.transaction.Transactional; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@ExtendWith(MockitoExtension.class) +class LightSensorServiceTest { + + @Mock + private LightSensorRepository lightSensorRepository; + + @Mock + private CameraService cameraService; + + @Mock + private Camera camera; + + @InjectMocks + private LightSensorService lightSensorService; + + private LightSensor sensor; + + + private final UUID SENSOR_ID = UUID.randomUUID(); + private final String SENSOR_NAME = "Light Sensor 1"; + private final SensorType SENSOR_TYPE = SensorType.LIGHT; + private final UUID CAMERA_ID = UUID.randomUUID(); + private final UUID NON_EXISTING_CAM_ID = UUID.fromString("ef556dc0-0ddc-4f39-a96d-6886a54eee54"); + private final String UPDATED_SENSOR_NAME = "Updated Light Sensor"; + private final String SENSOR_VERSION = "V1.0"; + private final String UPDATED_SENSOR_DATA = "Updated Sensor Data"; + + @BeforeEach + void setUp() { + sensor = new LightSensor(); + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + } + + @Test + @Transactional + void expect_handleCreateSensor_withValidSensor_returnSavedSensor() { + + // arrange + Mockito.when(lightSensorRepository.save(sensor)).thenReturn(sensor); + + // act + LightSensor savedSensor = lightSensorService.handleCreateSensor(CAMERA_ID, sensor); + + // assert + Assertions.assertThat(savedSensor).isNotNull(); + Assertions.assertThat(savedSensor).isEqualTo(sensor); + Assertions.assertThat(savedSensor.getId()).isNotNull(); + Assertions.assertThat(savedSensor.getId()).isEqualTo(SENSOR_ID); + Assertions.assertThat(savedSensor.getName()).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(savedSensor.getSensorType()).isNotNull(); + Assertions.assertThat(savedSensor.getSensorType()).isEqualTo(SENSOR_TYPE); + + Mockito.verify(lightSensorRepository).save(sensor); + } + + @Test + void expect_handleCreateSensor_withNonExistingCamera_throwsCameraNotFoundException() { + + // arrange + camera.setCamId(NON_EXISTING_CAM_ID); + Mockito.when(lightSensorRepository.save(sensor)).thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + NON_EXISTING_CAM_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.handleCreateSensor(NON_EXISTING_CAM_ID, sensor)) + .isInstanceOf(CameraNotFoundException.class); + + Mockito.verify(lightSensorRepository).save(sensor); + } + + @Test + void expect_handleUpdateSensor_withValidData_returnsUpdatedSensor() { + // arrange + sensor.setCamera(camera); + sensor.setName(UPDATED_SENSOR_NAME); + sensor.setVersion(SENSOR_VERSION); + sensor.setData(UPDATED_SENSOR_DATA); + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(lightSensorRepository.save(sensor)).thenReturn(sensor); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + + // act + LightSensor updatedSensor = lightSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor); + + // assert + Assertions.assertThat(updatedSensor).isNotNull(); + Assertions.assertThat(updatedSensor).isEqualTo(sensor); + Assertions.assertThat(updatedSensor.getName()).isNotNull(); + Assertions.assertThat(updatedSensor.getName()).isEqualTo(UPDATED_SENSOR_NAME); + Assertions.assertThat(updatedSensor.getVersion()).isNotNull(); + Assertions.assertThat(updatedSensor.getVersion()).isEqualTo(SENSOR_VERSION); + Assertions.assertThat(updatedSensor.getCamera()).isNotNull(); + Assertions.assertThat(updatedSensor.getCamera()).isEqualTo(camera); + Assertions.assertThat(updatedSensor.getData()).isNotNull(); + Assertions.assertThat(updatedSensor.getData()).isEqualTo(UPDATED_SENSOR_DATA); + + Mockito.verify(lightSensorRepository).save(sensor); + } + + @Test + void expect_handleUpdateSensor_withNonExistingSensor_throwsSensorNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(List.of()); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(SensorNotFoundException.class) + .hasMessageContaining("Sensor not found"); + + Mockito.verify(lightSensorRepository, Mockito.never()).save(Mockito.any()); + } + + @Test + void expect_handleUpdateSensor_withNonExistingCamera_throwsCameraNotFoundException() { + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + CAMERA_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(CameraNotFoundException.class) + .hasMessageContaining("Camera not found"); + + Mockito.verify(lightSensorRepository, Mockito.never()).save(Mockito.any()); + } + + @Test + void expect_handleUpdateSensor_withRepositoryError_throwsSensorNotUpdatedException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + Mockito.when(lightSensorRepository.save(sensor)) + .thenThrow(new SensorNotUpdatedException("Error occurred while updating sensors")); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(SensorNotUpdatedException.class) + .hasMessageContaining("Error occurred while updating sensors"); + + Mockito.verify(lightSensorRepository).save(sensor); + } + + @Test + void expect_getSensorById_withValidSensorId_returnsSensor() { + + // arrange + Mockito.when(lightSensorRepository.findById(SENSOR_ID)).thenReturn(java.util.Optional.of(sensor)); + + // act + LightSensor foundSensor = lightSensorService.getSensorById(SENSOR_ID); + + // assert + Assertions.assertThat(foundSensor).isEqualTo(sensor); + Mockito.verify(lightSensorRepository).findById(SENSOR_ID); + } + + @Test + void expect_getSensorById_withInvalidSensorId_throwsSensorNotFoundException() { + + // arrange + Mockito.when(lightSensorRepository.findById(SENSOR_ID)).thenReturn(java.util.Optional.empty()); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.getSensorById(SENSOR_ID)) + .isInstanceOf(SensorNotFoundException.class); + + Mockito.verify(lightSensorRepository).findById(SENSOR_ID); + } + + @Test + void expect_handleDeleteSensor_withValidData_deletesSensor() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + + // act + lightSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID); + + // assert + Mockito.verify(lightSensorRepository).delete(sensor); + } + + @Test + void expect_handleDeleteSensor_withNonExistingSensor_throwsSensorNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(List.of()); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(SensorNotFoundException.class) + .hasMessageContaining("Sensor not found with id"); + + Mockito.verify(lightSensorRepository, Mockito.never()).delete(Mockito.any()); + } + + @Test + void expect_handleDeleteSensor_withNonExistingCamera_throwsCameraNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)) + .thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + CAMERA_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(CameraNotFoundException.class) + .hasMessageContaining("Camera not found, cameraId"); + + Mockito.verify(lightSensorRepository, Mockito.never()).delete(Mockito.any()); + } + + @Test + void expect_handleDeleteSensor_withRepositoryError_throwsSensorNotUpdatedException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + Mockito.doThrow(new RuntimeException("Error occurred while deleting sensor")) + .when(lightSensorRepository).delete(sensor); + + // act and assert + Assertions.assertThatThrownBy(() -> lightSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(SensorNotUpdatedException.class) + .hasMessageContaining("Error occurred while deleting sensor"); + + Mockito.verify(lightSensorRepository).delete(sensor); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/MotionSensorServiceTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/MotionSensorServiceTest.java new file mode 100644 index 0000000..46eaa8e --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/MotionSensorServiceTest.java @@ -0,0 +1,258 @@ +package com.onboarding.camera.cameraonboarding.service.impl; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.MotionSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.CameraNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.repository.MotionSensorRepository; +import com.onboarding.camera.cameraonboarding.service.CameraService; +import jakarta.transaction.Transactional; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@ExtendWith(MockitoExtension.class) +class MotionSensorServiceTest { + + @Mock + private MotionSensorRepository motionSensorRepository; + + @Mock + private CameraService cameraService; + + @Mock + private Camera camera; + + @InjectMocks + private MotionSensorService motionSensorService; + + private MotionSensor sensor; + + + private final UUID SENSOR_ID = UUID.randomUUID(); + private final String SENSOR_NAME = "Motion Sensor 1"; + private final SensorType SENSOR_TYPE = SensorType.MOTION; + private final UUID CAMERA_ID = UUID.randomUUID(); + private final UUID NON_EXISTING_CAM_ID = UUID.fromString("ef556dc0-0ddc-4f39-a96d-6886a54eee54"); + private final String UPDATED_SENSOR_NAME = "Updated Motion Sensor"; + private final String SENSOR_VERSION = "v1.0"; + private final String UPDATED_SENSOR_DATA = "Updated Sensor Data"; + + @BeforeEach + void setUp() { + sensor = new MotionSensor(); + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + } + + @Test + @Transactional + void expect_handleCreateSensor_withValidSensor_returnSavedSensor() { + + // arrange + Mockito.when(motionSensorRepository.save(sensor)).thenReturn(sensor); + + // act + MotionSensor savedSensor = motionSensorService.handleCreateSensor(CAMERA_ID, sensor); + + // assert + Assertions.assertThat(savedSensor).isNotNull(); + Assertions.assertThat(savedSensor).isEqualTo(sensor); + Assertions.assertThat(savedSensor.getId()).isNotNull(); + Assertions.assertThat(savedSensor.getId()).isEqualTo(SENSOR_ID); + Assertions.assertThat(savedSensor.getName()).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(savedSensor.getSensorType()).isNotNull(); + Assertions.assertThat(savedSensor.getSensorType()).isEqualTo(SENSOR_TYPE); + + Mockito.verify(motionSensorRepository).save(sensor); + } + + @Test + void expect_handleCreateSensor_withNonExistingCamera_throwsCameraNotFoundException() { + + // arrange + camera.setCamId(NON_EXISTING_CAM_ID); + Mockito.when(motionSensorRepository.save(sensor)).thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + NON_EXISTING_CAM_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.handleCreateSensor(NON_EXISTING_CAM_ID, sensor)) + .isInstanceOf(CameraNotFoundException.class); + + Mockito.verify(motionSensorRepository).save(sensor); + } + + @Test + void expect_handleUpdateSensor_withValidData_returnsUpdatedSensor() { + // arrange + sensor.setCamera(camera); + sensor.setName(UPDATED_SENSOR_NAME); + sensor.setVersion(SENSOR_VERSION); + sensor.setData(UPDATED_SENSOR_DATA); + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(motionSensorRepository.save(sensor)).thenReturn(sensor); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + + // act + MotionSensor updatedSensor = motionSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor); + + // assert + Assertions.assertThat(updatedSensor).isNotNull(); + Assertions.assertThat(updatedSensor).isEqualTo(sensor); + Assertions.assertThat(updatedSensor.getName()).isNotNull(); + Assertions.assertThat(updatedSensor.getName()).isEqualTo(UPDATED_SENSOR_NAME); + Assertions.assertThat(updatedSensor.getVersion()).isNotNull(); + Assertions.assertThat(updatedSensor.getVersion()).isEqualTo(SENSOR_VERSION); + Assertions.assertThat(updatedSensor.getCamera()).isNotNull(); + Assertions.assertThat(updatedSensor.getCamera()).isEqualTo(camera); + Assertions.assertThat(updatedSensor.getData()).isNotNull(); + Assertions.assertThat(updatedSensor.getData()).isEqualTo(UPDATED_SENSOR_DATA); + + Mockito.verify(motionSensorRepository).save(sensor); + } + + @Test + void expect_handleUpdateSensor_withNonExistingSensor_throwsSensorNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(List.of()); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(SensorNotFoundException.class) + .hasMessageContaining("Sensor not found"); + + Mockito.verify(motionSensorRepository, Mockito.never()).save(Mockito.any()); + } + + @Test + void expect_handleUpdateSensor_withNonExistingCamera_throwsCameraNotFoundException() { + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + CAMERA_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(CameraNotFoundException.class) + .hasMessageContaining("Camera not found"); + + Mockito.verify(motionSensorRepository, Mockito.never()).save(Mockito.any()); + } + + @Test + void expect_handleUpdateSensor_withRepositoryError_throwsSensorNotUpdatedException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + Mockito.when(motionSensorRepository.save(sensor)) + .thenThrow(new SensorNotUpdatedException("Error occurred while updating sensors")); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(SensorNotUpdatedException.class) + .hasMessageContaining("Error occurred while updating sensors"); + + Mockito.verify(motionSensorRepository).save(sensor); + } + + @Test + void expect_getSensorById_withValidSensorId_returnsSensor() { + + // arrange + Mockito.when(motionSensorRepository.findById(SENSOR_ID)).thenReturn(java.util.Optional.of(sensor)); + + // act + MotionSensor foundSensor = motionSensorService.getSensorById(SENSOR_ID); + + // assert + Assertions.assertThat(foundSensor).isEqualTo(sensor); + Mockito.verify(motionSensorRepository).findById(SENSOR_ID); + } + + @Test + void expect_getSensorById_withInvalidSensorId_throwsSensorNotFoundException() { + + // arrange + Mockito.when(motionSensorRepository.findById(SENSOR_ID)).thenReturn(java.util.Optional.empty()); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.getSensorById(SENSOR_ID)) + .isInstanceOf(SensorNotFoundException.class); + + Mockito.verify(motionSensorRepository).findById(SENSOR_ID); + } + + @Test + void expect_handleDeleteSensor_withValidData_deletesSensor() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + + // act + motionSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID); + + // assert + Mockito.verify(motionSensorRepository).delete(sensor); + } + + @Test + void expect_handleDeleteSensor_withNonExistingSensor_throwsSensorNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(List.of()); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(SensorNotFoundException.class) + .hasMessageContaining("Sensor not found with id"); + + Mockito.verify(motionSensorRepository, Mockito.never()).delete(Mockito.any()); + } + + @Test + void expect_handleDeleteSensor_withNonExistingCamera_throwsCameraNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)) + .thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + CAMERA_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(CameraNotFoundException.class) + .hasMessageContaining("Camera not found, cameraId"); + + Mockito.verify(motionSensorRepository, Mockito.never()).delete(Mockito.any()); + } + + @Test + void expect_handleDeleteSensor_withRepositoryError_throwsSensorNotUpdatedException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + Mockito.doThrow(new RuntimeException("Error occurred while deleting sensor")) + .when(motionSensorRepository).delete(sensor); + + // act and assert + Assertions.assertThatThrownBy(() -> motionSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(SensorNotUpdatedException.class) + .hasMessageContaining("Error occurred while deleting sensor"); + + Mockito.verify(motionSensorRepository).delete(sensor); + } +} \ No newline at end of file diff --git a/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/TemperatureSensorServiceTest.java b/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/TemperatureSensorServiceTest.java new file mode 100644 index 0000000..dea4b04 --- /dev/null +++ b/src/test/java/com/onboarding/camera/cameraonboarding/service/impl/TemperatureSensorServiceTest.java @@ -0,0 +1,258 @@ +package com.onboarding.camera.cameraonboarding.service.impl; + +import com.onboarding.camera.cameraonboarding.entity.Camera; +import com.onboarding.camera.cameraonboarding.entity.TemperatureSensor; +import com.onboarding.camera.cameraonboarding.enums.SensorType; +import com.onboarding.camera.cameraonboarding.exception.CameraNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotFoundException; +import com.onboarding.camera.cameraonboarding.exception.SensorNotUpdatedException; +import com.onboarding.camera.cameraonboarding.repository.TemperatureSensorRepository; +import com.onboarding.camera.cameraonboarding.service.CameraService; +import jakarta.transaction.Transactional; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@ExtendWith(MockitoExtension.class) +class TemperatureSensorServiceTest { + + @Mock + private TemperatureSensorRepository temperatureSensorRepository; + + @Mock + private CameraService cameraService; + + @Mock + private Camera camera; + + @InjectMocks + private TemperatureSensorService temperatureSensorService; + + private TemperatureSensor sensor; + + + private final UUID SENSOR_ID = UUID.randomUUID(); + private final String SENSOR_NAME = "Temperature Sensor 1"; + private final SensorType SENSOR_TYPE = SensorType.TEMPERATURE; + private final UUID CAMERA_ID = UUID.randomUUID(); + private final UUID NON_EXISTING_CAM_ID = UUID.fromString("ef556dc0-0ddc-4f39-a96d-6886a54eee54"); + private final String UPDATED_SENSOR_NAME = "Updated Temperature Sensor"; + private final String SENSOR_VERSION = "v1.0"; + private final String UPDATED_SENSOR_DATA = "Updated Sensor Data"; + + @BeforeEach + void setUp() { + sensor = new TemperatureSensor(); + sensor.setId(SENSOR_ID); + sensor.setName(SENSOR_NAME); + sensor.setSensorType(SENSOR_TYPE); + } + + @Test + @Transactional + void expect_handleCreateSensor_withValidSensor_returnSavedSensor() { + + // arrange + Mockito.when(temperatureSensorRepository.save(sensor)).thenReturn(sensor); + + // act + TemperatureSensor savedSensor = temperatureSensorService.handleCreateSensor(CAMERA_ID, sensor); + + // assert + Assertions.assertThat(savedSensor).isNotNull(); + Assertions.assertThat(savedSensor).isEqualTo(sensor); + Assertions.assertThat(savedSensor.getId()).isNotNull(); + Assertions.assertThat(savedSensor.getId()).isEqualTo(SENSOR_ID); + Assertions.assertThat(savedSensor.getName()).isNotNull(); + Assertions.assertThat(savedSensor.getName()).isEqualTo(SENSOR_NAME); + Assertions.assertThat(savedSensor.getSensorType()).isNotNull(); + Assertions.assertThat(savedSensor.getSensorType()).isEqualTo(SENSOR_TYPE); + + Mockito.verify(temperatureSensorRepository).save(sensor); + } + + @Test + void expect_handleCreateSensor_withNonExistingCamera_throwsCameraNotFoundException() { + + // arrange + camera.setCamId(NON_EXISTING_CAM_ID); + Mockito.when(temperatureSensorRepository.save(sensor)).thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + NON_EXISTING_CAM_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.handleCreateSensor(NON_EXISTING_CAM_ID, sensor)) + .isInstanceOf(CameraNotFoundException.class); + + Mockito.verify(temperatureSensorRepository).save(sensor); + } + + @Test + void expect_handleUpdateSensor_withValidData_returnsUpdatedSensor() { + // arrange + sensor.setCamera(camera); + sensor.setName(UPDATED_SENSOR_NAME); + sensor.setVersion(SENSOR_VERSION); + sensor.setData(UPDATED_SENSOR_DATA); + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(temperatureSensorRepository.save(sensor)).thenReturn(sensor); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + + // act + TemperatureSensor updatedSensor = temperatureSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor); + + // assert + Assertions.assertThat(updatedSensor).isNotNull(); + Assertions.assertThat(updatedSensor).isEqualTo(sensor); + Assertions.assertThat(updatedSensor.getName()).isNotNull(); + Assertions.assertThat(updatedSensor.getName()).isEqualTo(UPDATED_SENSOR_NAME); + Assertions.assertThat(updatedSensor.getVersion()).isNotNull(); + Assertions.assertThat(updatedSensor.getVersion()).isEqualTo(SENSOR_VERSION); + Assertions.assertThat(updatedSensor.getCamera()).isNotNull(); + Assertions.assertThat(updatedSensor.getCamera()).isEqualTo(camera); + Assertions.assertThat(updatedSensor.getData()).isNotNull(); + Assertions.assertThat(updatedSensor.getData()).isEqualTo(UPDATED_SENSOR_DATA); + + Mockito.verify(temperatureSensorRepository).save(sensor); + } + + @Test + void expect_handleUpdateSensor_withNonExistingSensor_throwsSensorNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(List.of()); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(SensorNotFoundException.class) + .hasMessageContaining("Sensor not found"); + + Mockito.verify(temperatureSensorRepository, Mockito.never()).save(Mockito.any()); + } + + @Test + void expect_handleUpdateSensor_withNonExistingCamera_throwsCameraNotFoundException() { + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + CAMERA_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(CameraNotFoundException.class) + .hasMessageContaining("Camera not found"); + + Mockito.verify(temperatureSensorRepository, Mockito.never()).save(Mockito.any()); + } + + @Test + void expect_handleUpdateSensor_withRepositoryError_throwsSensorNotUpdatedException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + Mockito.when(temperatureSensorRepository.save(sensor)) + .thenThrow(new SensorNotUpdatedException("Error occurred while updating sensors")); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.handleUpdateSensor(CAMERA_ID, SENSOR_ID, sensor)) + .isInstanceOf(SensorNotUpdatedException.class) + .hasMessageContaining("Error occurred while updating sensors"); + + Mockito.verify(temperatureSensorRepository).save(sensor); + } + + @Test + void expect_getSensorById_withValidSensorId_returnsSensor() { + + // arrange + Mockito.when(temperatureSensorRepository.findById(SENSOR_ID)).thenReturn(java.util.Optional.of(sensor)); + + // act + TemperatureSensor foundSensor = temperatureSensorService.getSensorById(SENSOR_ID); + + // assert + Assertions.assertThat(foundSensor).isEqualTo(sensor); + Mockito.verify(temperatureSensorRepository).findById(SENSOR_ID); + } + + @Test + void expect_getSensorById_withInvalidSensorId_throwsSensorNotFoundException() { + + // arrange + Mockito.when(temperatureSensorRepository.findById(SENSOR_ID)).thenReturn(java.util.Optional.empty()); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.getSensorById(SENSOR_ID)) + .isInstanceOf(SensorNotFoundException.class); + + Mockito.verify(temperatureSensorRepository).findById(SENSOR_ID); + } + + @Test + void expect_handleDeleteSensor_withValidData_deletesSensor() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + + // act + temperatureSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID); + + // assert + Mockito.verify(temperatureSensorRepository).delete(sensor); + } + + @Test + void expect_handleDeleteSensor_withNonExistingSensor_throwsSensorNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(List.of()); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(SensorNotFoundException.class) + .hasMessageContaining("Sensor not found with id"); + + Mockito.verify(temperatureSensorRepository, Mockito.never()).delete(Mockito.any()); + } + + @Test + void expect_handleDeleteSensor_withNonExistingCamera_throwsCameraNotFoundException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)) + .thenThrow(new CameraNotFoundException("Camera not found, cameraId:" + CAMERA_ID)); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(CameraNotFoundException.class) + .hasMessageContaining("Camera not found, cameraId"); + + Mockito.verify(temperatureSensorRepository, Mockito.never()).delete(Mockito.any()); + } + + @Test + void expect_handleDeleteSensor_withRepositoryError_throwsSensorNotUpdatedException() { + + // arrange + Mockito.when(cameraService.getCameraById(CAMERA_ID)).thenReturn(camera); + Mockito.when(camera.getSensors()).thenReturn(new ArrayList<>(List.of(sensor))); + Mockito.doThrow(new RuntimeException("Error occurred while deleting sensor")) + .when(temperatureSensorRepository).delete(sensor); + + // act and assert + Assertions.assertThatThrownBy(() -> temperatureSensorService.handleDeleteSensor(CAMERA_ID, SENSOR_ID)) + .isInstanceOf(SensorNotUpdatedException.class) + .hasMessageContaining("Error occurred while deleting sensor"); + + Mockito.verify(temperatureSensorRepository).delete(sensor); + } +} \ No newline at end of file