Skip to content

Commit

Permalink
feat: extensions for unit tests
Browse files Browse the repository at this point in the history
Refs: #220
  • Loading branch information
grigoriev committed Dec 18, 2024
1 parent cc3d49a commit 778ecd7
Show file tree
Hide file tree
Showing 8 changed files with 347 additions and 205 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,19 @@

import ch.sbb.polarion.extension.generic.fields.converters.ChainConverter;
import ch.sbb.polarion.extension.generic.fields.model.FieldMetadata;
import ch.sbb.polarion.extension.generic.polarion.CustomExtensionMock;
import ch.sbb.polarion.extension.generic.polarion.PlatformContextMockExtension;
import com.polarion.alm.shared.util.Pair;
import com.polarion.alm.tracker.ITrackerService;
import com.polarion.platform.core.IPlatform;
import com.polarion.platform.core.PlatformContext;
import com.polarion.platform.persistence.IDataService;
import com.polarion.platform.persistence.IEnumOption;
import com.polarion.platform.persistence.IEnumeration;
import com.polarion.platform.persistence.spi.EnumOption;
import com.polarion.subterra.base.data.model.internal.EnumType;
import com.polarion.subterra.base.data.model.internal.ListType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
Expand All @@ -32,31 +28,23 @@
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;

@ExtendWith(MockitoExtension.class)
@ExtendWith({MockitoExtension.class, PlatformContextMockExtension.class})
public class CustomFieldEnumConverterTest {

public static final String YES_NO_ENUM_ID = "yes_no";
public static final Pair<String, String> YES = Pair.of("yes", "Ja");
public static final Pair<String, String> NO = Pair.of("no", "Nein");

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
MockedStatic<PlatformContext> mockPlatformContext;
@CustomExtensionMock
private IDataService dataService;
@CustomExtensionMock
private ITrackerService trackerService;

private ArrayList<IEnumOption> allOptions;

@BeforeEach
@SuppressWarnings("unchecked")
void setup() {
IPlatform platform = mock(IPlatform.class);
mockPlatformContext.when(PlatformContext::getPlatform).thenReturn(platform);

IDataService dataService = mock(IDataService.class);
lenient().when(platform.lookupService(IDataService.class)).thenReturn(dataService);

ITrackerService trackerService = mock(ITrackerService.class);
lenient().when(platform.lookupService(ITrackerService.class)).thenReturn(trackerService);
lenient().when(trackerService.getDataService()).thenReturn(dataService);

IEnumeration<IEnumOption> enumeration = mock(IEnumeration.class);
lenient().when(dataService.getEnumerationForEnumId(any(), any())).thenReturn(enumeration);

Expand All @@ -66,11 +54,6 @@ void setup() {
lenient().when(enumeration.getAllOptions()).thenReturn(allOptions);
}

@AfterEach
void cleanup() {
mockPlatformContext.close();
}

@Test
void testGetEnumOptionById() {
FieldMetadata fieldMetadata = ConverterTestUtils.getWorkItemCustomField();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ch.sbb.polarion.extension.generic.polarion;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomExtensionMock {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ch.sbb.polarion.extension.generic.polarion;

import org.junit.jupiter.api.extension.ExtensionContext;

import java.lang.reflect.Field;

public class CustomExtensionMockInjector {

public static <T> void inject(ExtensionContext context, T what) throws IllegalAccessException {
Object testInstance = context.getTestInstance().orElse(null);
if (testInstance != null) {
for (Field field : testInstance.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(CustomExtensionMock.class) && field.getType().isAssignableFrom(what.getClass())) {
field.setAccessible(true);
field.set(testInstance, what);
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package ch.sbb.polarion.extension.generic.polarion;

import com.polarion.alm.projects.IProjectService;
import com.polarion.alm.tracker.ITestManagementService;
import com.polarion.alm.tracker.ITrackerService;
import com.polarion.platform.IPlatformService;
import com.polarion.platform.core.IPlatform;
import com.polarion.platform.core.PlatformContext;
import com.polarion.platform.persistence.IDataService;
import com.polarion.platform.security.ILoginPolicy;
import com.polarion.platform.security.ISecurityService;
import com.polarion.platform.service.repository.IRepositoryService;
import com.polarion.portal.internal.server.navigation.TestManagementServiceAccessor;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;

import static org.mockito.Mockito.*;

public class PlatformContextMockExtension implements BeforeEachCallback, AfterEachCallback {

private MockedConstruction<TestManagementServiceAccessor> testManagementServiceAccessorMockedConstruction;
private MockedStatic<PlatformContext> platformContextMockedStatic;

@Override
public void beforeEach(ExtensionContext context) throws Exception {
IPlatform platformMock = mock(IPlatform.class);

ITrackerService trackerService = mock(ITrackerService.class);
IProjectService projectService = mock(IProjectService.class);
ISecurityService securityService = mock(ISecurityService.class);
IPlatformService platformService = mock(IPlatformService.class);
IRepositoryService repositoryService = mock(IRepositoryService.class);
IDataService dataService = mock(IDataService.class);
ILoginPolicy loginPolicy = mock(ILoginPolicy.class);
ITestManagementService testManagementService = mock(ITestManagementService.class);

lenient().when(platformMock.lookupService(ITrackerService.class)).thenReturn(trackerService);
lenient().when(platformMock.lookupService(IProjectService.class)).thenReturn(projectService);
lenient().when(platformMock.lookupService(ISecurityService.class)).thenReturn(securityService);
lenient().when(platformMock.lookupService(IPlatformService.class)).thenReturn(platformService);
lenient().when(platformMock.lookupService(IRepositoryService.class)).thenReturn(repositoryService);
lenient().when(platformMock.lookupService(IDataService.class)).thenReturn(dataService);
lenient().when(platformMock.lookupService(ILoginPolicy.class)).thenReturn(loginPolicy);

lenient().when(trackerService.getDataService()).thenReturn(dataService);

platformContextMockedStatic = mockStatic(PlatformContext.class);
platformContextMockedStatic.when(PlatformContext::getPlatform).thenReturn(platformMock);

CustomExtensionMockInjector.inject(context, trackerService);
CustomExtensionMockInjector.inject(context, projectService);
CustomExtensionMockInjector.inject(context, securityService);
CustomExtensionMockInjector.inject(context, platformService);
CustomExtensionMockInjector.inject(context, repositoryService);
CustomExtensionMockInjector.inject(context, dataService);
CustomExtensionMockInjector.inject(context, loginPolicy);

testManagementServiceAccessorMockedConstruction = mockConstruction(TestManagementServiceAccessor.class, (testManagementServiceAccessor, mockedContructionContext) -> {
lenient().when(testManagementServiceAccessor.getTestingService()).thenReturn(testManagementService);
});
}

@Override
public void afterEach(ExtensionContext context) throws Exception {
if (testManagementServiceAccessorMockedConstruction != null) {
testManagementServiceAccessorMockedConstruction.close();
}
if (platformContextMockedStatic != null) {
platformContextMockedStatic.close();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package ch.sbb.polarion.extension.generic.polarion;

import com.polarion.alm.shared.api.transaction.RunnableInReadOnlyTransaction;
import com.polarion.alm.shared.api.transaction.TransactionalExecutor;
import com.polarion.alm.shared.api.transaction.internal.InternalReadOnlyTransaction;
import com.polarion.alm.shared.api.utils.RunnableWithResult;
import com.polarion.alm.shared.api.utils.internal.InternalPolarionUtils;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.mockito.MockedStatic;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

public class TransactionalExecutorExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {

private MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic;

@Override
public void beforeEach(ExtensionContext context) throws Exception {
transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class);

InternalReadOnlyTransaction internalReadOnlyTransactionMock = mock(InternalReadOnlyTransaction.class);
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenAnswer(invocation -> {
RunnableInReadOnlyTransaction<?> runnable = invocation.getArgument(0);
return runnable.run(internalReadOnlyTransactionMock);
});
transactionalExecutorMockedStatic.when(TransactionalExecutor::currentTransaction).thenReturn(internalReadOnlyTransactionMock);

InternalPolarionUtils internalPolarionUtils = mock(InternalPolarionUtils.class);
lenient().when(internalPolarionUtils.executeInBaseline(any(), any())).thenAnswer(invocation -> {
RunnableWithResult<?> runnableWithResult = invocation.getArgument(1);
return runnableWithResult.run();
});
lenient().when(internalReadOnlyTransactionMock.utils()).thenReturn(internalPolarionUtils);

CustomExtensionMockInjector.inject(context, internalPolarionUtils);
CustomExtensionMockInjector.inject(context, internalReadOnlyTransactionMock);
}

@Override
public void afterEach(ExtensionContext context) throws Exception {
if (transactionalExecutorMockedStatic != null) {
transactionalExecutorMockedStatic.close();
}
}

@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
return parameterContext.getParameter().getType().equals(ExtensionContext.class);
}

@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
return extensionContext;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
import ch.sbb.polarion.extension.generic.fields.FieldType;
import ch.sbb.polarion.extension.generic.fields.model.FieldMetadata;
import ch.sbb.polarion.extension.generic.fields.model.Option;
import ch.sbb.polarion.extension.generic.polarion.PlatformContextMockExtension;
import ch.sbb.polarion.extension.generic.polarion.TransactionalExecutorExtension;
import ch.sbb.polarion.extension.generic.util.AssigneeUtils;
import ch.sbb.polarion.extension.generic.util.TestUtils;
import com.polarion.alm.projects.IProjectService;
import com.polarion.alm.projects.model.IProject;
import com.polarion.alm.shared.api.transaction.TransactionalExecutor;
import com.polarion.alm.shared.api.model.baselinecollection.BaselineCollection;
import com.polarion.alm.shared.api.model.baselinecollection.BaselineCollectionReference;
import com.polarion.alm.shared.api.transaction.ReadOnlyTransaction;
import com.polarion.alm.tracker.IModuleManager;
import com.polarion.alm.tracker.ITrackerService;
import com.polarion.alm.tracker.model.IModule;
Expand All @@ -34,6 +38,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;

Expand All @@ -48,7 +53,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
@ExtendWith({MockitoExtension.class, PlatformContextMockExtension.class, TransactionalExecutorExtension.class})
@SuppressWarnings({"rawtypes", "unchecked", "UnusedReturnValue"})
public class PolarionServiceTest {

Expand Down Expand Up @@ -120,11 +125,14 @@ void testGetNotExistentModule() {

@Test
void testGetNotExistentCollection() {
try (MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class)) {
mockProject(Boolean.TRUE);
IBaselineCollection collection = mockCollection(Boolean.FALSE);
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenReturn(collection);
mockProject(Boolean.TRUE);
IBaselineCollection collection = mockCollection(Boolean.FALSE);

try (MockedConstruction<BaselineCollectionReference> baselineCollectionReferenceMockedConstruction = mockConstruction(BaselineCollectionReference.class, (mock, context) -> {
BaselineCollection baselineCollection = mock(BaselineCollection.class);
when(baselineCollection.getOldApi()).thenReturn(collection);
when(mock.get(any(ReadOnlyTransaction.class))).thenReturn(baselineCollection);
})) {
ObjectNotFoundException exception = assertThrows(ObjectNotFoundException.class, () -> polarionService.getCollection(PROJECT_ID, COLLECTION_ID));
assertEquals("Collection with id '1' not found in project 'project_id'", exception.getMessage());

Expand Down Expand Up @@ -217,22 +225,28 @@ void testGetModuleWithRevision() {

@Test
void testGetCollection() {
try (MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class)) {
mockProject(Boolean.TRUE);
IBaselineCollection collection = mockCollection(Boolean.TRUE);
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenReturn(collection);
mockProject(Boolean.TRUE);
IBaselineCollection collection = mockCollection(Boolean.TRUE);

try (MockedConstruction<BaselineCollectionReference> baselineCollectionReferenceMockedConstruction = mockConstruction(BaselineCollectionReference.class, (mock, context) -> {
BaselineCollection baselineCollection = mock(BaselineCollection.class);
when(baselineCollection.getOldApi()).thenReturn(collection);
when(mock.get(any(ReadOnlyTransaction.class))).thenReturn(baselineCollection);
})) {
assertNotNull(polarionService.getCollection(PROJECT_ID, COLLECTION_ID));
}
}

@Test
void testGetCollectionWithRevision() {
try (MockedStatic<TransactionalExecutor> transactionalExecutorMockedStatic = mockStatic(TransactionalExecutor.class)) {
mockProject(Boolean.TRUE);
IBaselineCollection collection = mockCollection(Boolean.TRUE);
transactionalExecutorMockedStatic.when(() -> TransactionalExecutor.executeSafelyInReadOnlyTransaction(any())).thenReturn(collection);
mockProject(Boolean.TRUE);
IBaselineCollection collection = mockCollection(Boolean.TRUE);

try (MockedConstruction<BaselineCollectionReference> baselineCollectionReferenceMockedConstruction = mockConstruction(BaselineCollectionReference.class, (mock, context) -> {
BaselineCollection baselineCollection = mock(BaselineCollection.class);
when(baselineCollection.getOldApi()).thenReturn(collection);
when(mock.get(any(ReadOnlyTransaction.class))).thenReturn(baselineCollection);
})) {
assertNotNull(polarionService.getCollection(PROJECT_ID, COLLECTION_ID, REVISION));

IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
Expand Down
Loading

0 comments on commit 778ecd7

Please sign in to comment.