Exercise 8 PR #95

Merged
reynisson merged 68 commits from dev into main 2021-11-29 06:46:44 +00:00
15 changed files with 467 additions and 116 deletions
Showing only changes of commit 84c284677e - Show all commits

View File

@ -85,22 +85,6 @@
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>chaos-monkey-spring-boot</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -1,18 +1,14 @@
package ch.unisg.roster; package ch.unisg.roster;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import ch.unisg.roster.roster.adapter.out.persistence.mongodb.RosterRepository; import ch.unisg.roster.roster.adapter.out.persistence.mongodb.RosterRepository;
import ch.unisg.roster.roster.application.port.in.LoadRosterItemPort; import ch.unisg.roster.roster.application.port.in.LoadRosterItemPort;
import ch.unisg.roster.roster.domain.Roster; import ch.unisg.roster.roster.domain.Roster;
import ch.unisg.roster.roster.domain.RosterItem; import ch.unisg.roster.roster.domain.RosterItem;
import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
@ -30,20 +26,14 @@ public class RosterApplication {
private static ConfigurableEnvironment ENVIRONMENT; private static ConfigurableEnvironment ENVIRONMENT;
@Autowired private static LoadRosterItemPort loadRosterItemPort;
private LoadRosterItemPort loadRosterItemPort;
public static void main(String[] args) { public static void main(String[] args) {
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SpringApplication rosterApp = new SpringApplication(RosterApplication.class); SpringApplication rosterApp = new SpringApplication(RosterApplication.class);
ENVIRONMENT = rosterApp.run(args).getEnvironment(); ENVIRONMENT = rosterApp.run(args).getEnvironment();
bootstrapMarketplaceWithMqtt(); bootstrapMarketplaceWithMqtt();
initialiseRoster();
} }
/** /**
@ -62,9 +52,9 @@ public class RosterApplication {
} }
} }
@PostConstruct private static void initialiseRoster(){
private void initialiseRoster(){ List<RosterItem> rosterItemList = loadRosterItemPort.loadAllRosterItems();
Roster.getInstance().initialiseRoster(loadRosterItemPort.loadAllRosterItems()); Roster.getInstance().initialiseRoster(rosterItemList);
} }
} }

View File

@ -1,32 +0,0 @@
package ch.unisg.roster.roster.adapter.in.web;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskCommand;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskUseCase;
import ch.unisg.roster.roster.domain.ExecutorInfo;
import ch.unisg.roster.roster.domain.Task;
@RestController
public class ApplyForTaskController {
private final ApplyForTaskUseCase applyForTaskUseCase;
public ApplyForTaskController(ApplyForTaskUseCase applyForTaskUseCase) {
this.applyForTaskUseCase = applyForTaskUseCase;
}
/**
* Checks if task is available for the requesting executor.
* @return a task or null if no task found
**/
@PostMapping(path = "/task/apply", consumes = {"application/json"})
public Task applyForTask(@RequestBody ExecutorInfo executorInfo) {
ApplyForTaskCommand command = new ApplyForTaskCommand(executorInfo.getExecutorType(),
executorInfo.getExecutorURI());
return applyForTaskUseCase.applyForTask(command);
}
}

View File

@ -0,0 +1,65 @@
package ch.unisg.roster.roster.adapter.in.web;
import ch.unisg.roster.roster.domain.Roster;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.json.JSONObject;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskCommand;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskUseCase;
import ch.unisg.roster.roster.domain.ExecutorInfo;
import ch.unisg.roster.roster.domain.Task;
import org.springframework.web.server.ResponseStatusException;
import javax.validation.ConstraintViolationException;
@RestController
public class ApplyForTaskWebController {
private final ApplyForTaskUseCase applyForTaskUseCase;
public ApplyForTaskWebController(ApplyForTaskUseCase applyForTaskUseCase) {
this.applyForTaskUseCase = applyForTaskUseCase;
}
// TODO fix return type
/**
* Checks if task is available for the requesting executor.
* @return a task or null if no task found
**/
@PostMapping(path = "/task/apply", consumes = {"application/json"})
public ResponseEntity<String> applyForTask (@RequestBody ExecutorInfo executorInfo) {
ApplyForTaskCommand command = new ApplyForTaskCommand(executorInfo.getExecutorType(),
executorInfo.getExecutorURI());
Task task = applyForTaskUseCase.applyForTask(command);
if (task == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
try {
String executorType = command.getTaskType().getValue().toString();
String executorURI = command.getExecutorURI().getValue().toString();
String jsonPayLoad = new JSONObject()
.put("executorType", executorType)
.put("executorURI", executorURI)
.toString();
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.add("Content-Type", "application/json");
return new ResponseEntity<>(jsonPayLoad, responseHeaders, HttpStatus.CREATED);
} catch (ConstraintViolationException e) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage());
}
}
}

View File

@ -1,9 +1,6 @@
package ch.unisg.roster.roster.domain; package ch.unisg.roster.roster.domain;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -90,4 +87,12 @@ public class Roster {
} }
} }
public Collection<RosterItem> getRosterMap(){
return rosterMap.values();
}
public Collection<ArrayList<Task>> getAllTasksFromQueue(){
return queues.values();
}
} }

View File

@ -0,0 +1,20 @@
package ch.unisg.roster;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import org.junit.jupiter.api.Test;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
public class DependencyRuleTests {
@Test
void testPackageDependencies() {
noClasses()
.that()
.resideInAPackage("ch.unisg.roster.roster.domain..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("ch.unisg.roster.roster.application..")
.check(new ClassFileImporter()
.importPackages("ch.unisg.roster.roster.."));
}
}

View File

@ -1,13 +0,0 @@
package ch.unisg.roster;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class RosterApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -0,0 +1,82 @@
package ch.unisg.roster.roster;
import ch.unisg.roster.roster.application.port.in.AddRosterItemPort;
import ch.unisg.roster.roster.domain.Roster;
import ch.unisg.roster.roster.domain.Task;
import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
import org.json.JSONObject;
import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.*;
import static org.assertj.core.api.BDDAssertions.*;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class AddNewAssignmentToRosterServiceSystemTest {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private AddRosterItemPort addRosterItemPort;
@Test
void addNewAssignmentToRosterService() throws JSONException {
String rosterItemId = "TEST-ID";
String executorType = "TEST-TYPE";
String executorURI = "TEST-URI";
ResponseEntity response = whenAddNewAssignmentToRoster(rosterItemId, executorType, executorURI);
System.out.println(response.getBody().toString());
JSONObject responseJson = new JSONObject(response.getBody().toString());
String respExecutorType = responseJson.getString("executorType");
String respExecutorURI = responseJson.getString("executorURI");
then(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
then(respExecutorType).isEqualTo(executorType);
then(respExecutorURI).isEqualTo(executorURI);
then(Roster.getInstance().getRosterMap().size()).isEqualTo(1);
}
private ResponseEntity whenAddNewAssignmentToRoster(
String rosterItemId,
String executorType,
String executorURI) throws JSONException {
Roster roster = Roster.getInstance();
roster.getRosterMap().clear();
roster.addTaskToQueue(new Task(rosterItemId, new ExecutorType(executorType), executorURI));
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
String jsonPayLoad = new JSONObject()
.put("rosterItemId", rosterItemId)
.put("executorType", executorType)
.put("executorURI", executorURI)
.toString();
HttpEntity<String> request = new HttpEntity<>(jsonPayLoad, headers);
return restTemplate.exchange(
"/task/apply/",
HttpMethod.POST,
request,
Object.class
);
}
}

View File

@ -0,0 +1,68 @@
package ch.unisg.roster.roster.adapter.in.web;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.roster.roster.adapter.out.persistence.mongodb.RosterRepository;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskCommand;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskUseCase;
import ch.unisg.roster.roster.domain.RosterItem;
import ch.unisg.roster.roster.domain.Task;
import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.BDDMockito.then;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(controllers = ApplyForTaskWebController.class)
public class ApplyForTaskWebControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ApplyForTaskUseCase applyForTaskUseCase;
@MockBean
RosterRepository rosterRepository;
@Test
void testApplyForTask() throws Exception{
String executorType = "TEST-TYPE";
String executorURI = "http://localhost:6969";
String taskId = "TEST-ID";
String jsonPayLoad = new JSONObject()
.put("executorType", executorType )
.put("executorURI",executorURI)
.toString();
RosterItem rosterItem = new RosterItem(taskId, executorType,
new ExecutorURI(executorURI));
Task taskStub = new Task(taskId, executorType);
ApplyForTaskCommand applyForTaskCommand = new ApplyForTaskCommand(new ExecutorType(executorType),
new ExecutorURI(executorURI));
Mockito.when(applyForTaskUseCase.applyForTask(applyForTaskCommand))
.thenReturn(taskStub);
mockMvc.perform(post("/task/apply/")
.contentType("application/json")
.content(jsonPayLoad))
.andExpect(status().is2xxSuccessful());
then(applyForTaskUseCase).should()
.applyForTask(new ApplyForTaskCommand(new ExecutorType(executorType), new ExecutorURI(executorURI)));
}
}

View File

@ -0,0 +1,68 @@
package ch.unisg.roster.roster.adapter.out.persistence.mongodb;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.roster.roster.domain.RosterItem;
import ch.unisg.roster.roster.domain.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.AutoConfigureDataMongo;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureDataMongo
@Import({RosterPersistenceAdapter.class, RosterMapper.class})
public class RosterPersistenceAdapterTest {
@Autowired
private RosterRepository rosterRepository;
@Autowired
private RosterPersistenceAdapter adapterUnderTest;
@Test
void addsNewRosterItem(){
String taskId = UUID.randomUUID().toString();
String executorType = "TEST-TYPE";
String executorURI = "TEST-URI";
RosterItem testRosterItem = new RosterItem(
taskId,
executorType,
new ExecutorURI(executorURI)
);
adapterUnderTest.addRosterItem(testRosterItem);
MongoRosterDocument retrievedDoc = rosterRepository.findByTaskId(taskId);
assertThat(retrievedDoc.taskId).isEqualTo(taskId);
assertThat(retrievedDoc.executorURI).isEqualTo(executorURI);
assertThat(retrievedDoc.taskType).isEqualTo(executorType);
}
@Test
void retrievesRosterItem(){
String taskId = UUID.randomUUID().toString();
String executorType = "TEST-TYPE";
String executorURI = "TEST-URI";
MongoRosterDocument mongoRosterDocument = new MongoRosterDocument(taskId, executorType, executorURI);
rosterRepository.insert(mongoRosterDocument);
RosterItem retrievedRosterItem = adapterUnderTest.loadRosterItem(taskId);
assertThat(retrievedRosterItem.getTaskID()).isEqualTo(taskId);
assertThat(retrievedRosterItem.getTaskType()).isEqualTo(executorType);
assertThat(retrievedRosterItem.getExecutorURI().getValue().toString()).isEqualTo(executorURI);
}
}

View File

@ -0,0 +1,76 @@
package ch.unisg.roster.roster.application.service;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.roster.roster.application.port.in.AddRosterItemPort;
import ch.unisg.roster.roster.application.port.in.ApplyForTaskCommand;
import ch.unisg.roster.roster.application.port.in.DeleteRosterItem;
import ch.unisg.roster.roster.application.port.in.NewTaskCommand;
import ch.unisg.roster.roster.application.port.out.NewTaskEventPort;
import ch.unisg.roster.roster.application.port.out.TaskAssignedEventPort;
import ch.unisg.roster.roster.application.port.out.TaskCompletedEventPort;
import ch.unisg.roster.roster.domain.Roster;
import ch.unisg.roster.roster.domain.RosterItem;
import ch.unisg.roster.roster.domain.Task;
import ch.unisg.roster.roster.domain.event.NewTaskEvent;
import ch.unisg.roster.roster.domain.event.TaskAssignedEvent;
import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.net.URI;
import java.util.Optional;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
public class AddNewAssignmentToRosterServiceTest {
//private final NewTaskEventPort newTaskEventPort = Mockito.mock(NewTaskEventPort.class);
private final TaskAssignedEventPort taskAssignedEventPort = Mockito.mock(TaskAssignedEventPort.class);
private final AddRosterItemPort addRosterItemPort = Mockito.mock(AddRosterItemPort.class);
//private final TaskCompletedEventPort taskCompletedEventPort = Mockito.mock(TaskCompletedEventPort.class)
//private final DeleteRosterItem deleteRosterItem = Mockito.mock(DeleteRosterItem.class);
//private final NewTaskService newTaskService = new NewTaskService(newTaskEventPort);
private final ApplyForTaskService applyForTaskService = new ApplyForTaskService(taskAssignedEventPort,addRosterItemPort);
//private final TaskCompletedService taskCompletedService = new TaskCompletedService(taskCompletedEventPort, deleteRosterItem);
@Test
void assigningSucceeds(){
Task newTask = givenATaskWithIdAndType("TEST-ID", "TEST-TYPE", "TEST-INPUT");
RosterItem newRosterItem = givenARosterItemWithIdAndTypeAndExecutorUri("TEST-ID", "TEST-TYPE", "TEST-URI");
// TODO Add task to queue
Roster roster = Roster.getInstance();
roster.addTaskToQueue(newTask);
ApplyForTaskCommand applyForTaskCommand = new ApplyForTaskCommand(newTask.getTaskType(), newRosterItem.getExecutorURI());
Task assignedTask = applyForTaskService.applyForTask(applyForTaskCommand);
assertThat(assignedTask).isNotNull();
then(taskAssignedEventPort).should(times(1))
.publishTaskAssignedEvent(any(TaskAssignedEvent.class));
then(addRosterItemPort).should(times(1));
}
private RosterItem givenARosterItemWithIdAndTypeAndExecutorUri(String taskId, String taskType,
String executorURI){
RosterItem rosterItem = Mockito.mock(RosterItem.class);
given(rosterItem.getTaskID()).willReturn(taskId);
given(rosterItem.getTaskType()).willReturn(taskType);
given(rosterItem.getExecutorURI()).willReturn(new ExecutorURI(executorURI));
return rosterItem;
}
private Task givenATaskWithIdAndType(String taskId, String taskType, String inputData) {
Task task = Mockito.mock(Task.class);
given(task.getTaskID()).willReturn(taskId);
given(task.getTaskType()).willReturn(new ExecutorType(taskType));
given(task.getInputData()).willReturn(inputData);
return task;
}
}

View File

@ -0,0 +1,52 @@
package ch.unisg.roster.roster.domain;
import ch.unisg.common.valueobject.ExecutorURI;
import ch.unisg.roster.roster.domain.valueobject.ExecutorType;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import static org.assertj.core.api.Assertions.*;
public class RosterTest {
@Test
void addAssignmentToRosterMapTest(){
Roster roster = Roster.getInstance();
Collection<RosterItem> rosterMap = roster.getRosterMap();
rosterMap.clear();
Collection<ArrayList<Task>> queues = roster.getAllTasksFromQueue();
queues.clear();
roster.addTaskToQueue(new Task("TEST-ID", "TEST-TYPE"));
Task task = roster.assignTaskToExecutor(new ExecutorType("TEST-TYPE"), new ExecutorURI("TEST-URI"));
assertThat(rosterMap.size()).isEqualTo(1);
assertThat(rosterMap.iterator().next().getTaskID()).isEqualTo("TEST-ID");
assertThat(rosterMap.iterator().next().getTaskType()).isEqualTo("TEST-TYPE");
assertThat(rosterMap.iterator().next().getExecutorURI().getValue().toString()).isEqualTo("TEST-URI");
assertThat(task.getTaskType().getValue().toString()).isEqualTo("TEST-TYPE");
assertThat(task.getTaskID()).isEqualTo("TEST-ID");
boolean empty_queue = roster.deleteTask("TEST-ID", new ExecutorType("TEST-TYPE"));
// TODO test that the task was removed from the Queue similar to below --> I don't know if it actually gets deleted or not
//assertThat(empty_queue).isEqualTo(true);
//assertThat(queues.size()).isEqualTo(0);
}
@Test
void removeTaskFromQueue(){
Roster roster = Roster.getInstance();
Collection<ArrayList<Task>> queues = roster.getAllTasksFromQueue();
queues.clear();
roster.addTaskToQueue(new Task("TEST-ID", "TEST-TYPE"));
boolean test = roster.deleteTask("TEST-ID", new ExecutorType("TEST-TYPE"));
assertThat(test).isEqualTo(true);
assertThat(queues.size()).isEqualTo(1);
}
}

View File

@ -0,0 +1,2 @@
spring.data.mongodb.uri=mongodb://127.0.0.1:27017
spring.data.mongodb.database=tapas-roster

View File

@ -1,18 +0,0 @@
package ch.unisg.tapastasks;
import ch.unisg.tapastasks.tasks.application.port.out.AddTaskPort;
import ch.unisg.tapastasks.tasks.application.port.out.NewTaskAddedEventPort;
import ch.unisg.tapastasks.tasks.application.port.out.TaskListLock;
import ch.unisg.tapastasks.tasks.application.service.AddNewTaskToTaskListService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class TapasTasksApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -26,28 +26,30 @@ public class TaskPersistenceAdapterTest {
@Test @Test
void addsNewTask() { void addsNewTask() {
// String testTaskId = UUID.randomUUID().toString(); String testTaskId = UUID.randomUUID().toString();
// String testTaskName = "adds-persistence-task-name"; String testTaskName = "adds-persistence-task-name";
// String testTaskType = "adds-persistence-task-type"; String testTaskType = "adds-persistence-task-type";
// String testTaskOuri = "adds-persistence-test-task-ouri"; String testTaskOuri = "adds-persistence-test-task-ouri";
// String testTaskStatus = Task.Status.OPEN.toString(); String testTaskStatus = Task.Status.OPEN.toString();
// String testTaskListName = "tapas-tasks-tutors"; String testTaskListName = "tapas-tasks-tutors";
// Task testTask = new Task( Task testTask = new Task(
// new Task.TaskId(testTaskId), new Task.TaskId(testTaskId),
// new Task.TaskName(testTaskName), new Task.TaskName(testTaskName),
// new Task.TaskType(testTaskType), new Task.TaskType(testTaskType),
// new Task.OriginalTaskUri(testTaskOuri), new Task.OriginalTaskUri(testTaskOuri),
// new Task.TaskStatus(Task.Status.valueOf(testTaskStatus)) new Task.TaskStatus(Task.Status.valueOf(testTaskStatus)),
// ); new Task.InputData("asd"),
// adapterUnderTest.addTask(testTask); new Task.OutputData("")
);
adapterUnderTest.addTask(testTask);
// MongoTaskDocument retrievedDoc = taskRepository.findByTaskId(testTaskId,testTaskListName); MongoTaskDocument retrievedDoc = taskRepository.findByTaskId(testTaskId,testTaskListName);
// assertThat(retrievedDoc.taskId).isEqualTo(testTaskId); assertThat(retrievedDoc.taskId).isEqualTo(testTaskId);
// assertThat(retrievedDoc.taskName).isEqualTo(testTaskName); assertThat(retrievedDoc.taskName).isEqualTo(testTaskName);
// assertThat(retrievedDoc.taskListName).isEqualTo(testTaskListName); assertThat(retrievedDoc.taskListName).isEqualTo(testTaskListName);
} }