Skip to content

Commit

Permalink
Moved shared kernel template parts to own package + renaming #3521
Browse files Browse the repository at this point in the history
- added comments
- moved from encryption package to own template package (shared kernel)
- renamed class SecHubProjectTemplates to SecHubProjectTemplateData
- created common logic for assignment and unassignment
- wrote tests for ProjectTemplateService
  • Loading branch information
de-jcup committed Dec 5, 2024
1 parent b48c9e8 commit 91e98bd
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class ProjectDetailInformation {
public static final String PROPERTY_OWNER = "owner";
public static final String PROPERTY_ACCESSLEVEL = "accessLevel";
public static final String PROPERTY_DESCRIPTION = "description";
public static final String PROPERTY_TEMPLATES = "templates";
public static final String PROPERTY_TEMPLATE_IDS = "templateIds";

private String projectId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import org.springframework.stereotype.Service;

import com.mercedesbenz.sechub.sharedkernel.Step;
import com.mercedesbenz.sechub.sharedkernel.encryption.SecHubProjectTemplates;
import com.mercedesbenz.sechub.sharedkernel.encryption.SecHubProjectToTemplate;
import com.mercedesbenz.sechub.sharedkernel.error.NotAcceptableException;
import com.mercedesbenz.sechub.sharedkernel.messaging.DomainMessage;
import com.mercedesbenz.sechub.sharedkernel.messaging.DomainMessageService;
Expand All @@ -20,6 +18,8 @@
import com.mercedesbenz.sechub.sharedkernel.messaging.MessageDataKeys;
import com.mercedesbenz.sechub.sharedkernel.messaging.MessageID;
import com.mercedesbenz.sechub.sharedkernel.security.RoleConstants;
import com.mercedesbenz.sechub.sharedkernel.template.SecHubProjectTemplateData;
import com.mercedesbenz.sechub.sharedkernel.template.SecHubProjectToTemplate;
import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminAssignsTemplateToProject;
import com.mercedesbenz.sechub.sharedkernel.usecases.admin.config.UseCaseAdminUnassignsTemplateFromProject;
import com.mercedesbenz.sechub.sharedkernel.validation.UserInputAssertion;
Expand Down Expand Up @@ -52,23 +52,7 @@ public class ProjectTemplateService {
description = "The service will request the template assignment in domain 'scan' via synchronous event and updates mapping in domain 'administration' afterwards"))
/* @formatter:on */
public void assignTemplateToProject(String templateId, String projectId) {
assertion.assertIsValidTemplateId(templateId);
assertion.assertIsValidProjectId(projectId);

Project project = projectRepository.findOrFailProject(projectId);
Set<String> templateIds = project.getTemplateIds();
LOG.debug("Start assigning template '{}' to project '{}'. Formerly assgined templates : {}", templateId, projectId, templateIds);

SecHubProjectTemplates result = sendAssignRequestAndFetchResult(templateId, projectId);
List<String> newTemplateIds = result.getTemplateIds();
templateIds.clear();
templateIds.addAll(newTemplateIds);

projectTansactionService.saveInOwnTransaction(project);
LOG.info("Assigned template '{}' to project '{}'", templateId, projectId);

LOG.debug("Project '{}' has now following templates: {}", projectId, templateIds);

changeTemplateAssignment(templateId, projectId, (t, p) -> fetchAssignRequestResult(t, p), "assigned to");
}

/* @formatter:off */
Expand All @@ -79,69 +63,71 @@ public void assignTemplateToProject(String templateId, String projectId) {
description = "The service will request the template unassignment in domain 'scan' via synchronous event and updates mapping in domain 'administration' afterwards"))
/* @formatter:on */
public void unassignTemplateFromProject(String templateId, String projectId) {
changeTemplateAssignment(templateId, projectId, (t, p) -> fetchUnassignmentRequestResult(t, p), "unassigned from");
}

private void changeTemplateAssignment(String templateId, String projectId, TemplateChangeResultFetcher fetcher, String assignOrUnassignInfo) {
assertion.assertIsValidTemplateId(templateId);
assertion.assertIsValidProjectId(projectId);

Project project = projectRepository.findOrFailProject(projectId);
Set<String> templateIds = project.getTemplateIds();
LOG.debug("Start unassigning template '{}' from project '{}'. Formerly assgined templates : {}", templateId, projectId, templateIds);
LOG.debug("Project '{}' has following template ids: {}", projectId, templateIds);

SecHubProjectTemplates result = sendUnassignRequestAndFetchResult(templateId, projectId);
SecHubProjectTemplateData result = fetcher.fetchTemplateAssignmentChangeResult(templateId, projectId);
List<String> newTemplateIds = result.getTemplateIds();
templateIds.clear();
templateIds.addAll(newTemplateIds);

projectTansactionService.saveInOwnTransaction(project);
LOG.info("Unassigned template '{}' from project '{}'", templateId, projectId);

LOG.debug("Project '{}' has now following templates: {}", projectId, templateIds);
LOG.info("Template '{}' has been {} project '{}'", templateId, assignOrUnassignInfo, projectId);

LOG.debug("Project '{}' has following template ids: {}", projectId, templateIds);
}

@IsSendingSyncMessage(MessageID.REQUEST_ASSIGN_TEMPLATE_TO_PROJECT)
private SecHubProjectTemplates sendAssignRequestAndFetchResult(String templateId, String projectId) {

DomainMessage message = new DomainMessage(MessageID.REQUEST_ASSIGN_TEMPLATE_TO_PROJECT);
SecHubProjectToTemplate mapping = new SecHubProjectToTemplate();
mapping.setProjectId(projectId);
mapping.setTemplateId(templateId);
message.set(MessageDataKeys.PROJECT_TO_TEMPLATE, mapping);

DomainMessageSynchronousResult result = eventBus.sendSynchron(message);
if (result.hasFailed()) {
throw new NotAcceptableException("Was not able to assign template to project.\nReason:" + result.getErrorMessage());
}

MessageID messageID = result.getMessageId();
if (!(MessageID.RESULT_ASSIGN_TEMPLATE_TO_PROJECT.equals(messageID))) {
throw new IllegalStateException("Result message id not supported: " + messageID);
}

return result.get(MessageDataKeys.PROJECT_TEMPLATES);
private SecHubProjectTemplateData fetchAssignRequestResult(String templateId, String projectId) {
return sendSynchronousProjectTemplateChangeEvent(templateId, projectId, MessageID.REQUEST_ASSIGN_TEMPLATE_TO_PROJECT,
MessageID.RESULT_ASSIGN_TEMPLATE_TO_PROJECT);

}

@IsSendingSyncMessage(MessageID.REQUEST_UNASSIGN_TEMPLATE_FROM_PROJECT)
private SecHubProjectTemplates sendUnassignRequestAndFetchResult(String templateId, String projectId) {
private SecHubProjectTemplateData fetchUnassignmentRequestResult(String templateId, String projectId) {
return sendSynchronousProjectTemplateChangeEvent(templateId, projectId, MessageID.REQUEST_UNASSIGN_TEMPLATE_FROM_PROJECT,
MessageID.RESULT_UNASSIGN_TEMPLATE_FROM_PROJECT);
}

/*
* This method sends a synchronous event to event bus and waits that the
* assignment is done inside other domain (in this case we know it is inside the
* scan domain). When this is done, the change event was successful and the
* event result contains SecHubProjectTemplateData which can be used inside
* administration domain further.
*/
private SecHubProjectTemplateData sendSynchronousProjectTemplateChangeEvent(String templateId, String projectId, MessageID requestMessageId,
MessageID acceptedResultMessageId) {

DomainMessage message = new DomainMessage(requestMessageId);

DomainMessage message = new DomainMessage(MessageID.REQUEST_UNASSIGN_TEMPLATE_FROM_PROJECT);
SecHubProjectToTemplate mapping = new SecHubProjectToTemplate();
mapping.setProjectId(projectId);
mapping.setTemplateId(templateId);
message.set(MessageDataKeys.PROJECT_TO_TEMPLATE, mapping);

DomainMessageSynchronousResult result = eventBus.sendSynchron(message);

if (result.hasFailed()) {
throw new NotAcceptableException("Was not able to assign template to project.\nReason:" + result.getErrorMessage());
throw new NotAcceptableException("Was not able to change template to project assignment.\nReason: " + result.getErrorMessage());
}

MessageID messageID = result.getMessageId();
if (!(MessageID.RESULT_UNASSIGN_TEMPLATE_FROM_PROJECT.equals(messageID))) {
if (!(acceptedResultMessageId.equals(messageID))) {
throw new IllegalStateException("Result message id not supported: " + messageID);
}

return result.get(MessageDataKeys.PROJECT_TEMPLATES);

}

private interface TemplateChangeResultFetcher {
public SecHubProjectTemplateData fetchTemplateAssignmentChangeResult(String templateId, String projectId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package com.mercedesbenz.sechub.domain.administration.project;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

import java.util.List;
import java.util.Set;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.EnumSource.Mode;
import org.mockito.ArgumentCaptor;

import com.mercedesbenz.sechub.sharedkernel.error.NotAcceptableException;
import com.mercedesbenz.sechub.sharedkernel.messaging.DomainMessage;
import com.mercedesbenz.sechub.sharedkernel.messaging.DomainMessageService;
import com.mercedesbenz.sechub.sharedkernel.messaging.DomainMessageSynchronousResult;
import com.mercedesbenz.sechub.sharedkernel.messaging.MessageDataKeys;
import com.mercedesbenz.sechub.sharedkernel.messaging.MessageID;
import com.mercedesbenz.sechub.sharedkernel.template.SecHubProjectTemplateData;
import com.mercedesbenz.sechub.sharedkernel.template.SecHubProjectToTemplate;

class ProjectTemplateServiceTest {

private static final String CORRECT_ASSIGN_TEMPLATE_RESULT_MESSAGE_ID = "RESULT_ASSIGN_TEMPLATE_TO_PROJECT";
private static final String CORRECT_UNASSIGN_TEMPLATE_RESULT_MESSAGE_ID = "RESULT_UNASSIGN_TEMPLATE_FROM_PROJECT";
private static final String ASSIGNED_TEMPLATE_ID_A = "template-a";
private static final String ASSIGNED_TEMPLATE_ID_B = "template-b";

private static final String ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_1 = "template-after_change-1";
private static final String ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_2 = "template-after-change-2";

private static final String PROJECT_ID1 = "project1";
private static final String TEMPLATE_ID1 = "templateId1";
private ProjectTemplateService serviceToTest;
private DomainMessageService eventBus;
private ProjectRepository projectRepository;
private ProjectTransactionService projectTansactionService;

@BeforeEach
void beforeEach() {

eventBus = mock();
projectRepository = mock();
projectTansactionService = mock();

serviceToTest = new ProjectTemplateService();
serviceToTest.assertion = mock();
serviceToTest.eventBus = eventBus;

serviceToTest.projectRepository = projectRepository;
serviceToTest.projectTansactionService = projectTansactionService;
}

@Test
void assignTemplateToProject_sends_assign_request_synchronous_with_expected_data() {

/* prepare */
mockEventBusSynchronResultWithMessageId(MessageID.RESULT_ASSIGN_TEMPLATE_TO_PROJECT);

/* execute */
serviceToTest.assignTemplateToProject(TEMPLATE_ID1, PROJECT_ID1);

/* test */
ArgumentCaptor<DomainMessage> messageCaptor = ArgumentCaptor.captor();
verify(eventBus).sendSynchron(messageCaptor.capture());

DomainMessage sentMessage = messageCaptor.getValue();
assertThat(sentMessage).isNotNull();
assertThat(sentMessage.getMessageId()).isEqualTo(MessageID.REQUEST_ASSIGN_TEMPLATE_TO_PROJECT);
SecHubProjectToTemplate sentMessageData = sentMessage.get(MessageDataKeys.PROJECT_TO_TEMPLATE);
assertThat(sentMessageData).isNotNull();
assertThat(sentMessageData.getProjectId()).isEqualTo(PROJECT_ID1);
assertThat(sentMessageData.getTemplateId()).isEqualTo(TEMPLATE_ID1);

}

@Test
void assignTemplateToProject_updates_template_by_synchronous_event_result() {

/* prepare */
mockEventBusSynchronResultWithMessageId(MessageID.RESULT_ASSIGN_TEMPLATE_TO_PROJECT);

/* execute */
serviceToTest.assignTemplateToProject(TEMPLATE_ID1, PROJECT_ID1);

/* test */
ArgumentCaptor<Project> projectCaptor = ArgumentCaptor.forClass(Project.class);
verify(projectTansactionService).saveInOwnTransaction(projectCaptor.capture());
Project projectSaved = projectCaptor.getValue();
assertThat(projectSaved.getTemplateIds()).hasSize(2).describedAs("project templates must be changed by result data")
.contains(ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_1).contains(ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_2);

}

@Test
void unassignTemplateFromProject_sends_assign_request_synchronous_with_expected_data() {

/* prepare */
mockEventBusSynchronResultWithMessageId(MessageID.RESULT_UNASSIGN_TEMPLATE_FROM_PROJECT);

/* execute */
serviceToTest.unassignTemplateFromProject(TEMPLATE_ID1, PROJECT_ID1);

/* test */
ArgumentCaptor<DomainMessage> messageCaptor = ArgumentCaptor.captor();
verify(eventBus).sendSynchron(messageCaptor.capture());

DomainMessage sentMessage = messageCaptor.getValue();
assertThat(sentMessage).isNotNull();
assertThat(sentMessage.getMessageId()).isEqualTo(MessageID.REQUEST_UNASSIGN_TEMPLATE_FROM_PROJECT);
SecHubProjectToTemplate sentMessageData = sentMessage.get(MessageDataKeys.PROJECT_TO_TEMPLATE);
assertThat(sentMessageData).isNotNull();
assertThat(sentMessageData.getProjectId()).isEqualTo(PROJECT_ID1);
assertThat(sentMessageData.getTemplateId()).isEqualTo(TEMPLATE_ID1);
}

@Test
void unassignTemplateFromProject_updates_template_by_synchronous_event_result() {

/* prepare */
mockEventBusSynchronResultWithMessageId(MessageID.RESULT_UNASSIGN_TEMPLATE_FROM_PROJECT);

/* execute */
serviceToTest.unassignTemplateFromProject(TEMPLATE_ID1, PROJECT_ID1);

/* test */
ArgumentCaptor<Project> projectCaptor = ArgumentCaptor.forClass(Project.class);
verify(projectTansactionService).saveInOwnTransaction(projectCaptor.capture());
Project projectSaved = projectCaptor.getValue();
assertThat(projectSaved.getTemplateIds()).hasSize(2).describedAs("project templates must be changed by result data")
.contains(ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_1).contains(ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_2);

}

@ParameterizedTest
@EnumSource(value = MessageID.class, mode = Mode.EXCLUDE, names = CORRECT_UNASSIGN_TEMPLATE_RESULT_MESSAGE_ID)
void unassignTemplateFromProject_when_synchronous_event_result_has_unsupported_message_throws_invalid_exception(MessageID wrongMessageId) {
/* prepare */
mockEventBusSynchronResultWithMessageId(wrongMessageId);

/* execute + test */
assertThatThrownBy(() -> serviceToTest.unassignTemplateFromProject(TEMPLATE_ID1, PROJECT_ID1)).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Result message id not supported");

}

@ParameterizedTest
@EnumSource(value = MessageID.class, mode = Mode.EXCLUDE, names = CORRECT_ASSIGN_TEMPLATE_RESULT_MESSAGE_ID)
void assignTemplateToProject_when_synchronous_event_result_has_unsupported_message_throws_invalid_exception(MessageID wrongMessageId) {
mockEventBusSynchronResultWithMessageId(wrongMessageId);

/* execute + test */
assertThatThrownBy(() -> serviceToTest.assignTemplateToProject(TEMPLATE_ID1, PROJECT_ID1)).isInstanceOf(IllegalStateException.class)
.hasMessageContaining("Result message id not supported");

}

@Test
void assignTemplateToProject_when_event_result_failed_exception_is_thrown() {
/* prepare */
DomainMessageSynchronousResult mockedResultMessage = mockEventBusSynchronResultWithMessageId(
MessageID.valueOf(CORRECT_UNASSIGN_TEMPLATE_RESULT_MESSAGE_ID));
when(mockedResultMessage.hasFailed()).thenReturn(true);

assertThatThrownBy(() -> serviceToTest.assignTemplateToProject(TEMPLATE_ID1, PROJECT_ID1)).isInstanceOf(NotAcceptableException.class)
.hasMessageContaining("Was not able to change template to project assignment");
}

@Test
void unassignTemplateFromProject_when_event_result_failed_exception_is_thrown() {
/* prepare */
DomainMessageSynchronousResult mockedResultMessage = mockEventBusSynchronResultWithMessageId(
MessageID.valueOf(CORRECT_UNASSIGN_TEMPLATE_RESULT_MESSAGE_ID));
when(mockedResultMessage.hasFailed()).thenReturn(true);

assertThatThrownBy(() -> serviceToTest.unassignTemplateFromProject(TEMPLATE_ID1, PROJECT_ID1)).isInstanceOf(NotAcceptableException.class)
.hasMessageContaining("Was not able to change template to project assignment");
}

private DomainMessageSynchronousResult mockEventBusSynchronResultWithMessageId(MessageID resultMessageId) {
Project project1 = new Project();
project1.getTemplateIds().addAll(Set.of(ASSIGNED_TEMPLATE_ID_A, ASSIGNED_TEMPLATE_ID_B));

when(projectRepository.findOrFailProject(PROJECT_ID1)).thenReturn(project1);

SecHubProjectTemplateData mockedResultData = mock();
when(mockedResultData.getProjectId()).thenReturn("result-project");
when(mockedResultData.getTemplateIds()).thenReturn(List.of(ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_1, ASSIGNED_TEMPLATE_ID_AFTER_CHANGE_2));
DomainMessageSynchronousResult mockedResultMessage = mock();
when(mockedResultMessage.getMessageId()).thenReturn(resultMessageId);
when(mockedResultMessage.get(MessageDataKeys.PROJECT_TEMPLATES)).thenReturn(mockedResultData);

when(eventBus.sendSynchron(any(DomainMessage.class))).thenReturn(mockedResultMessage);

return mockedResultMessage;
}

}
Loading

0 comments on commit 91e98bd

Please sign in to comment.