Initial commit.
This commit is contained in:
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
66
pom.xml
Normal file
66
pom.xml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.5.3</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>org.takiguchi.cerberus</groupId>
|
||||||
|
<artifactId>cerberus</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>Cerberus</name>
|
||||||
|
<description>Project to mangage services on a private server.</description>
|
||||||
|
<properties>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
<postgresql.version>42.2.23</postgresql.version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>${postgresql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class CerberusApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(CerberusApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.controller;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceStatus;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.ApplicationService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.takiguchi.cerberus.cerberusapp.model.Application.anApplication;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/applications")
|
||||||
|
public class ApplicationController {
|
||||||
|
private final ApplicationService service;
|
||||||
|
|
||||||
|
public ApplicationController(ApplicationService service) {
|
||||||
|
this.service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{applicationId}")
|
||||||
|
public Optional<Application> getById(@PathVariable("applicationId") UUID applicationId) {
|
||||||
|
return service.getById(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<Application> getAll() {
|
||||||
|
return service.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public Application add(@RequestBody Application application) {
|
||||||
|
Application applicationToAdd = anApplication()
|
||||||
|
.withName(application.getName())
|
||||||
|
.withServiceName(application.getServiceName())
|
||||||
|
.withServiceType(application.getServiceType())
|
||||||
|
.build();
|
||||||
|
return service.add(applicationToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{applicationId}")
|
||||||
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
public void update(@PathVariable("applicationId") UUID applicationId, @RequestBody Application application) {
|
||||||
|
Application applicationToUpdate = anApplication()
|
||||||
|
.withId(applicationId)
|
||||||
|
.withName(application.getName())
|
||||||
|
.withServiceName(application.getServiceName())
|
||||||
|
.withServiceType(application.getServiceType())
|
||||||
|
.build();
|
||||||
|
service.update(applicationToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{applicationId}")
|
||||||
|
public void remove(@PathVariable("applicationId") UUID applicationId) {
|
||||||
|
service.remove(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{applicationId}/status")
|
||||||
|
public ServiceStatus getStatus(@PathVariable("applicationId") UUID applicationId) {
|
||||||
|
return service.checkStatus(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{applicationId}/start")
|
||||||
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
public void start(@PathVariable("applicationId") UUID applicationId) {
|
||||||
|
service.start(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{applicationId}/stop")
|
||||||
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
public void stop(@PathVariable("applicationId") UUID applicationId) {
|
||||||
|
service.stop(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{applicationId}/restart")
|
||||||
|
@ResponseStatus(HttpStatus.NO_CONTENT)
|
||||||
|
public void restart(@PathVariable("applicationId") UUID applicationId) {
|
||||||
|
service.restart(applicationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||||
|
public class BadRequestException extends BusinessException {
|
||||||
|
public BadRequestException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadRequestException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Business exception.
|
||||||
|
*/
|
||||||
|
public class BusinessException extends RuntimeException {
|
||||||
|
|
||||||
|
public BusinessException() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an exception with a message.
|
||||||
|
* @param message The description of the error met.
|
||||||
|
*/
|
||||||
|
public BusinessException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an exception with a message and a code.
|
||||||
|
* @param message The description of the error met.
|
||||||
|
* @param cause The cause of the exception.
|
||||||
|
*/
|
||||||
|
public BusinessException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when user attempt to access a resource that he has not rights.
|
||||||
|
*/
|
||||||
|
@ResponseStatus(value = HttpStatus.FORBIDDEN)
|
||||||
|
public class ForbiddenException extends BusinessException {
|
||||||
|
|
||||||
|
public ForbiddenException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForbiddenException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForbiddenException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
public class InternalServerErrorException extends TechnicalException {
|
||||||
|
public InternalServerErrorException() {
|
||||||
|
super("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public InternalServerErrorException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InternalServerErrorException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||||
|
public class NoContentException extends BusinessException {
|
||||||
|
public NoContentException() {}
|
||||||
|
|
||||||
|
public NoContentException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NoContentException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||||
|
public class NotFoundException extends BusinessException {
|
||||||
|
public NotFoundException() {}
|
||||||
|
|
||||||
|
public NotFoundException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotFoundException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Technical exception.
|
||||||
|
*/
|
||||||
|
public class TechnicalException extends RuntimeException {
|
||||||
|
/**
|
||||||
|
* Constructs an exception with a message.
|
||||||
|
* @param message The description of the error met.
|
||||||
|
*/
|
||||||
|
public TechnicalException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an exception with a message and a code.
|
||||||
|
* @param message The description of the error met.
|
||||||
|
* @param cause The cause of the exception.
|
||||||
|
*/
|
||||||
|
public TechnicalException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.exception;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when an anonymous user attempt to access to secured resource or if he failed to login.
|
||||||
|
*/
|
||||||
|
@ResponseStatus(value = HttpStatus.UNAUTHORIZED)
|
||||||
|
public class UnauthorizedException extends BusinessException {
|
||||||
|
public UnauthorizedException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnauthorizedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnauthorizedException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.model;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class Application {
|
||||||
|
private final UUID id;
|
||||||
|
/** The name to display. */
|
||||||
|
private final String name;
|
||||||
|
/** The technical service name, like a docker container name or a system V service name. */
|
||||||
|
private final String serviceName;
|
||||||
|
private final ServiceType serviceType;
|
||||||
|
|
||||||
|
public static Builder anApplication() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Application(UUID id, String name, String serviceName, ServiceType serviceType) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
this.serviceType = serviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceType getServiceType() {
|
||||||
|
return serviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private UUID id;
|
||||||
|
private String name;
|
||||||
|
private String serviceName;
|
||||||
|
private ServiceType serviceType;
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withServiceName(String serviceName) {
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder withServiceType(ServiceType serviceType) {
|
||||||
|
this.serviceType = serviceType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application build() {
|
||||||
|
return new Application(id, name, serviceName, serviceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.model;
|
||||||
|
|
||||||
|
public enum ServiceStatus {
|
||||||
|
STARTED,
|
||||||
|
STOPPED,
|
||||||
|
UNKNOWN;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.model;
|
||||||
|
|
||||||
|
public enum ServiceType {
|
||||||
|
FAKE,
|
||||||
|
SERVICE,
|
||||||
|
DOCKER;
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.persistence.adapter;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.persistence.mapper.ApplicationEntityMapper;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.persistence.model.ApplicationEntity;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.persistence.repository.ApplicationRepository;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.ApplicationRepositoryPort;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ApplicationJpaRepositoryAdapter implements ApplicationRepositoryPort {
|
||||||
|
private final ApplicationRepository repository;
|
||||||
|
private final ApplicationEntityMapper applicationMapper;
|
||||||
|
|
||||||
|
public ApplicationJpaRepositoryAdapter(ApplicationRepository repository,
|
||||||
|
ApplicationEntityMapper applicationMapper) {
|
||||||
|
this.repository = repository;
|
||||||
|
this.applicationMapper = applicationMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Application> getById(UUID applicationId) {
|
||||||
|
return repository.findById(applicationId)
|
||||||
|
.map(applicationMapper::mapToDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Application> getAll() {
|
||||||
|
return repository.findAll()
|
||||||
|
.stream()
|
||||||
|
.map(applicationMapper::mapToDomain)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Application add(Application application) {
|
||||||
|
ApplicationEntity entityToSave = applicationMapper.mapToEntity(application);
|
||||||
|
ApplicationEntity savedApplication = repository.save(entityToSave);
|
||||||
|
return applicationMapper.mapToDomain(savedApplication);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Application application) {
|
||||||
|
ApplicationEntity entityToSave = applicationMapper.mapToEntity(application);
|
||||||
|
repository.save(entityToSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(UUID applicationId) {
|
||||||
|
repository.deleteById(applicationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.persistence.mapper;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.persistence.model.ApplicationEntity;
|
||||||
|
|
||||||
|
import static org.takiguchi.cerberus.cerberusapp.model.Application.anApplication;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ApplicationEntityMapper {
|
||||||
|
|
||||||
|
public Application mapToDomain(ApplicationEntity entity) {
|
||||||
|
return anApplication()
|
||||||
|
.withId(entity.getId())
|
||||||
|
.withName(entity.getName())
|
||||||
|
.withServiceName(entity.getServiceName())
|
||||||
|
.withServiceType(entity.getServiceType())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationEntity mapToEntity(Application application) {
|
||||||
|
return new ApplicationEntity(
|
||||||
|
application.getId(),
|
||||||
|
application.getName(),
|
||||||
|
application.getServiceName(),
|
||||||
|
application.getServiceType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.persistence.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceType;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static javax.persistence.EnumType.ORDINAL;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "application")
|
||||||
|
public class ApplicationEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(generator = "system-uuid")
|
||||||
|
private UUID id;
|
||||||
|
private String name;
|
||||||
|
private String serviceName;
|
||||||
|
@Enumerated
|
||||||
|
private ServiceType serviceType;
|
||||||
|
|
||||||
|
public ApplicationEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationEntity(UUID id, String name, String serviceName, ServiceType serviceType) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
this.serviceType = serviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceName(String serviceName) {
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceType getServiceType() {
|
||||||
|
return serviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceType(ServiceType serviceType) {
|
||||||
|
this.serviceType = serviceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.persistence.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.persistence.model.ApplicationEntity;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ApplicationRepository extends JpaRepository<ApplicationEntity, UUID> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service;
|
||||||
|
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public interface ApplicationRepositoryPort {
|
||||||
|
Optional<Application> getById(UUID applicationId);
|
||||||
|
List<Application> getAll();
|
||||||
|
Application add(Application application);
|
||||||
|
void update(Application application);
|
||||||
|
void remove(UUID applicationId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.exception.NotFoundException;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceStatus;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.servicemanager.ServiceManagerProvider;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.validator.ApplicationValidator;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.takiguchi.cerberus.cerberusapp.model.Application.anApplication;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApplicationService {
|
||||||
|
private final ApplicationValidator applicationValidator;
|
||||||
|
private final ApplicationRepositoryPort applicationRepositoryPort;
|
||||||
|
private final ServiceManagerProvider serviceManagerProvider;
|
||||||
|
|
||||||
|
public ApplicationService(ApplicationValidator applicationValidator,
|
||||||
|
ApplicationRepositoryPort applicationRepositoryPort,
|
||||||
|
ServiceManagerProvider serviceManagerProvider) {
|
||||||
|
this.applicationValidator = applicationValidator;
|
||||||
|
this.applicationRepositoryPort = applicationRepositoryPort;
|
||||||
|
this.serviceManagerProvider = serviceManagerProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Application> getById(UUID applicationId) {
|
||||||
|
return applicationRepositoryPort.getById(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Application> getAll() {
|
||||||
|
return applicationRepositoryPort.getAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application add(Application application) {
|
||||||
|
applicationValidator.validate(application);
|
||||||
|
return applicationRepositoryPort.add(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(Application application) {
|
||||||
|
applicationRepositoryPort.getById(application.getId())
|
||||||
|
.map(existingApplication -> anApplication()
|
||||||
|
.withId(existingApplication.getId())
|
||||||
|
.withName(application.getName())
|
||||||
|
.withServiceName(application.getServiceName())
|
||||||
|
.withServiceType(application.getServiceType())
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.ifPresentOrElse(this::validateThenSave, NotFoundException::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateThenSave(Application updatedApplication) {
|
||||||
|
applicationValidator.validate(updatedApplication);
|
||||||
|
applicationRepositoryPort.update(updatedApplication);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(UUID applicationId) {
|
||||||
|
applicationRepositoryPort.remove(applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceStatus checkStatus(UUID applicationId) {
|
||||||
|
return applicationRepositoryPort.getById(applicationId)
|
||||||
|
.map(application -> serviceManagerProvider.getServiceManager(application)
|
||||||
|
.getStatus(application)
|
||||||
|
).orElseThrow(NotFoundException::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(UUID applicationId) {
|
||||||
|
applicationRepositoryPort.getById(applicationId)
|
||||||
|
.ifPresentOrElse(
|
||||||
|
application -> serviceManagerProvider.getServiceManager(application)
|
||||||
|
.start(application),
|
||||||
|
NotFoundException::new
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop(UUID applicationId) {
|
||||||
|
applicationRepositoryPort.getById(applicationId)
|
||||||
|
.ifPresentOrElse(
|
||||||
|
application -> serviceManagerProvider.getServiceManager(application)
|
||||||
|
.stop(application),
|
||||||
|
NotFoundException::new
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restart(UUID applicationId) {
|
||||||
|
applicationRepositoryPort.getById(applicationId)
|
||||||
|
.ifPresentOrElse(
|
||||||
|
application -> serviceManagerProvider.getServiceManager(application)
|
||||||
|
.restart(application),
|
||||||
|
NotFoundException::new
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.exception;
|
||||||
|
|
||||||
|
public class ValidationException extends RuntimeException {
|
||||||
|
public ValidationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.servicemanager;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceStatus;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class DockerServiceManager implements ServiceManager {
|
||||||
|
@Override
|
||||||
|
public ServiceStatus getStatus(Application application) {
|
||||||
|
throw new IllegalStateException("DockerServiceManager#getStatus not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Application application) {
|
||||||
|
throw new IllegalStateException("DockerServiceManager#start not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(Application application) {
|
||||||
|
throw new IllegalStateException("DockerServiceManager#stop not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restart(Application application) {
|
||||||
|
throw new IllegalStateException("DockerServiceManager#restart not implemented.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.servicemanager;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceStatus;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.takiguchi.cerberus.cerberusapp.model.ServiceStatus.*;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FakeServiceManager implements ServiceManager {
|
||||||
|
private final Map<UUID, ServiceStatus> handledApplications = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServiceStatus getStatus(Application application) {
|
||||||
|
return handledApplications.entrySet()
|
||||||
|
.stream()
|
||||||
|
.filter(entry -> entry.getKey().equals(application.getId()))
|
||||||
|
.findFirst()
|
||||||
|
.map(Map.Entry::getValue)
|
||||||
|
.orElse(STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Application application) {
|
||||||
|
handledApplications.put(application.getId(), STARTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(Application application) {
|
||||||
|
handledApplications.put(application.getId(), STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restart(Application application) {
|
||||||
|
start(application);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.servicemanager;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceStatus;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LinuxServiceManager implements ServiceManager {
|
||||||
|
@Override
|
||||||
|
public ServiceStatus getStatus(Application application) {
|
||||||
|
throw new IllegalStateException("LinuxServiceManager#getStatus not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Application application) {
|
||||||
|
throw new IllegalStateException("LinuxServiceManager#start not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(Application application) {
|
||||||
|
throw new IllegalStateException("LinuxServiceManager#stop not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restart(Application application) {
|
||||||
|
throw new IllegalStateException("LinuxServiceManager#restart not implemented.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.servicemanager;
|
||||||
|
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceStatus;
|
||||||
|
|
||||||
|
public interface ServiceManager {
|
||||||
|
ServiceStatus getStatus(Application application);
|
||||||
|
void start(Application application);
|
||||||
|
void stop(Application application);
|
||||||
|
void restart(Application application);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.servicemanager;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.exception.InternalServerErrorException;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ServiceManagerProvider {
|
||||||
|
private final List<ServiceManager> serviceManagers;
|
||||||
|
|
||||||
|
public ServiceManagerProvider(List<ServiceManager> serviceManagers) {
|
||||||
|
this.serviceManagers = serviceManagers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceManager getServiceManager(Application application) {
|
||||||
|
ServiceManager result;
|
||||||
|
switch (application.getServiceType()) {
|
||||||
|
case FAKE:
|
||||||
|
result = getServiceByClass(FakeServiceManager.class);
|
||||||
|
break;
|
||||||
|
case SERVICE:
|
||||||
|
result = getServiceByClass(LinuxServiceManager.class);
|
||||||
|
break;
|
||||||
|
case DOCKER:
|
||||||
|
result = getServiceByClass(DockerServiceManager.class);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InternalServerErrorException("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ServiceManager getServiceByClass(Class<? extends ServiceManager> serviceManagerClass) {
|
||||||
|
return serviceManagers.stream()
|
||||||
|
.filter(serviceManagerClass::isInstance)
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(InternalServerErrorException::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.validator;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.exception.ValidationException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ApplicationValidator {
|
||||||
|
|
||||||
|
public void validate(Application application) {
|
||||||
|
if (application == null) {
|
||||||
|
throw new ValidationException("Application is null.");
|
||||||
|
}
|
||||||
|
if (application.getName() == null) {
|
||||||
|
throw new ValidationException("Application name is mandatory.");
|
||||||
|
}
|
||||||
|
if (application.getServiceName() == null) {
|
||||||
|
throw new ValidationException("Application service name is mandatory.");
|
||||||
|
}
|
||||||
|
if (application.getServiceType() == null) {
|
||||||
|
throw new ValidationException("Application service type is mandatory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/main/resources/application.yml
Normal file
15
src/main/resources/application.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
server:
|
||||||
|
error:
|
||||||
|
whitelabel:
|
||||||
|
enabled: false # Disable html error responses.
|
||||||
|
include-stacktrace: never
|
||||||
|
|
||||||
|
spring:
|
||||||
|
# -------------------------------------------------
|
||||||
|
# Database configuration
|
||||||
|
# -------------------------------------------------
|
||||||
|
datasource:
|
||||||
|
driverClassName: org.postgresql.Driver
|
||||||
|
url: jdbc:postgresql://localhost:50001/cerberus
|
||||||
|
username: h23
|
||||||
|
password: P@ssword1
|
||||||
9
src/main/sql/ddl.sql
Normal file
9
src/main/sql/ddl.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS application (
|
||||||
|
id UUID DEFAULT uuid_generate_v4() NOT NULL,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
service_name VARCHAR NOT NULL,
|
||||||
|
service_type SMALLINT NOT NULL,
|
||||||
|
CONSTRAINT application_pk PRIMARY KEY (id)
|
||||||
|
);
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class CerberusApplicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.*;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.servicemanager.ServiceManagerProvider;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.validator.ApplicationValidator;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.takiguchi.cerberus.cerberusapp.model.Application.anApplication;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class ApplicationServiceTest {
|
||||||
|
private ApplicationService service;
|
||||||
|
@Mock
|
||||||
|
private ApplicationRepositoryPort applicationRepositoryPort;
|
||||||
|
@Mock
|
||||||
|
private ApplicationValidator applicationValidator;
|
||||||
|
@Mock
|
||||||
|
private ServiceManagerProvider serviceManagerProvider;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<Application> applicationCaptor;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
service = new ApplicationService(applicationValidator, applicationRepositoryPort, serviceManagerProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getById_should_return_the_application() {
|
||||||
|
// given
|
||||||
|
UUID applicationId = UUID.randomUUID();
|
||||||
|
|
||||||
|
Application application = anApplication().build();
|
||||||
|
given(applicationRepositoryPort.getById(applicationId)).willReturn(Optional.of(application));
|
||||||
|
|
||||||
|
// when
|
||||||
|
Optional<Application> result = service.getById(applicationId);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result).contains(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAll_should_return_all_applications() {
|
||||||
|
// given
|
||||||
|
Application application1 = anApplication().build();
|
||||||
|
Application application2 = anApplication().build();
|
||||||
|
given(applicationRepositoryPort.getAll()).willReturn(List.of(application1, application2));
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<Application> result = service.getAll();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result).contains(application1, application2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void add_should_validate_the_application_then_add_it() {
|
||||||
|
// given
|
||||||
|
Application application = anApplication().build();
|
||||||
|
|
||||||
|
InOrder inOrder = inOrder(applicationValidator, applicationRepositoryPort);
|
||||||
|
|
||||||
|
Application addedApplication = anApplication().build();
|
||||||
|
given(applicationRepositoryPort.add(application)).willReturn(addedApplication);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Application result = service.add(application);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(result).isEqualTo(addedApplication);
|
||||||
|
inOrder.verify(applicationValidator).validate(application);
|
||||||
|
inOrder.verify(applicationRepositoryPort).add(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void update_should_retrieve_application_then_edit_some_fields_then_validate_it__then_update_it() {
|
||||||
|
// given
|
||||||
|
UUID newId = UUID.randomUUID();
|
||||||
|
String newName = "new name";
|
||||||
|
String newServiceName = "new service name";
|
||||||
|
Application application = anApplication()
|
||||||
|
.withId(newId)
|
||||||
|
.withName(newName)
|
||||||
|
.withServiceName(newServiceName)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InOrder inOrder = inOrder(applicationRepositoryPort, applicationValidator, applicationRepositoryPort);
|
||||||
|
|
||||||
|
UUID oldId = UUID.randomUUID();
|
||||||
|
Application existingApplication = anApplication()
|
||||||
|
.withId(oldId)
|
||||||
|
.build();
|
||||||
|
given(applicationRepositoryPort.getById(newId)).willReturn(Optional.of(existingApplication));
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.update(application);
|
||||||
|
|
||||||
|
// then
|
||||||
|
inOrder.verify(applicationRepositoryPort).getById(newId);
|
||||||
|
inOrder.verify(applicationValidator).validate(applicationCaptor.capture());
|
||||||
|
Application updatedApplication = applicationCaptor.getValue();
|
||||||
|
inOrder.verify(applicationRepositoryPort).update(updatedApplication);
|
||||||
|
|
||||||
|
assertThat(updatedApplication).isNotNull()
|
||||||
|
.extracting(
|
||||||
|
Application::getId,
|
||||||
|
Application::getName,
|
||||||
|
Application::getServiceName
|
||||||
|
)
|
||||||
|
.contains(
|
||||||
|
oldId,
|
||||||
|
newName,
|
||||||
|
newServiceName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package org.takiguchi.cerberus.cerberusapp.service.validator;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.Application;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.model.ServiceType;
|
||||||
|
import org.takiguchi.cerberus.cerberusapp.service.exception.ValidationException;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.catchThrowableOfType;
|
||||||
|
import static org.takiguchi.cerberus.cerberusapp.model.Application.anApplication;
|
||||||
|
import static org.takiguchi.cerberus.cerberusapp.model.ServiceType.FAKE;
|
||||||
|
|
||||||
|
class ApplicationValidatorTest {
|
||||||
|
private ApplicationValidator validator;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
validator = new ApplicationValidator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("should_throw_a_validation_exception_data_provider")
|
||||||
|
void should_throw_a_validation_exception(Application application, String errorMessage) {
|
||||||
|
// when
|
||||||
|
ValidationException exception = catchThrowableOfType(() -> validator.validate(application), ValidationException.class);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(exception).isNotNull()
|
||||||
|
.hasMessage(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<Arguments> should_throw_a_validation_exception_data_provider() {
|
||||||
|
return Stream.of(
|
||||||
|
Arguments.of(
|
||||||
|
null,
|
||||||
|
"Application is null."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication().build(),
|
||||||
|
"Application name is mandatory."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication()
|
||||||
|
.withId(UUID.randomUUID())
|
||||||
|
.build(),
|
||||||
|
"Application name is mandatory."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication()
|
||||||
|
.withName("name")
|
||||||
|
.build(),
|
||||||
|
"Application service name is mandatory."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication()
|
||||||
|
.withServiceName("serviceName")
|
||||||
|
.build(),
|
||||||
|
"Application name is mandatory."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication()
|
||||||
|
.withServiceType(FAKE)
|
||||||
|
.build(),
|
||||||
|
"Application name is mandatory."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication()
|
||||||
|
.withId(UUID.randomUUID())
|
||||||
|
.withName("name")
|
||||||
|
.build(),
|
||||||
|
"Application service name is mandatory."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication()
|
||||||
|
.withId(UUID.randomUUID())
|
||||||
|
.withServiceName("serviceName")
|
||||||
|
.build(),
|
||||||
|
"Application name is mandatory."
|
||||||
|
),
|
||||||
|
Arguments.of(
|
||||||
|
anApplication()
|
||||||
|
.withId(UUID.randomUUID())
|
||||||
|
.withName("name")
|
||||||
|
.withServiceName("serviceName")
|
||||||
|
.build(),
|
||||||
|
"Application service type is mandatory."
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user