/*
* $Id$
*
* Janus platform is an open-source multiagent platform.
* More details on http://www.janusproject.io
*
* Copyright (C) 2014-2015 Sebastian RODRIGUEZ, Nicolas GAUD, Stéphane GALLAND.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.janusproject.tests.kernel.services.jdk.contextspace;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import com.google.inject.Injector;
import io.janusproject.kernel.services.jdk.contextspace.Context;
import io.janusproject.kernel.services.jdk.contextspace.SpaceRepository;
import io.janusproject.services.contextspace.SpaceRepositoryListener;
import io.janusproject.services.distributeddata.DMap;
import io.janusproject.services.distributeddata.DistributedDataStructureService;
import io.janusproject.services.logging.LogService;
import io.janusproject.tests.testutils.AbstractJanusTest;
import io.janusproject.util.TwoStepConstruction;
import javassist.Modifier;
import org.hamcrest.core.IsInstanceOf;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Mockito;
import org.mockito.internal.verification.Times;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import io.sarl.core.SpaceCreated;
import io.sarl.lang.core.Event;
import io.sarl.lang.core.Space;
import io.sarl.lang.core.SpaceID;
import io.sarl.lang.util.SynchronizedCollection;
import io.sarl.tests.api.Nullable;
import io.sarl.util.Collections3;
import io.sarl.util.OpenEventSpace;
import io.sarl.util.OpenEventSpaceSpecification;
/**
* @author $Author: sgalland$
* @version $FullVersion$
* @mavengroupid $GroupId$
* @mavenartifactid $ArtifactId$
*/
@SuppressWarnings("all")
public class ContextTest extends AbstractJanusTest {
@Nullable
private UUID contextId;
@Nullable
private UUID spaceId;
@Nullable
private Map<UUID, OpenEventSpace> spaces;
@Nullable
private SpaceRepository spaceRepository;
@Nullable
private Context context;
@Nullable
private SpaceRepositoryListener spaceListener;
@Nullable
private SpaceRepositoryListener privateListener;
@Before
public void setUp() throws Exception {
this.contextId = UUID.randomUUID();
this.spaceId = UUID.randomUUID();
this.spaces = new HashMap<>();
this.spaceListener = Mockito.mock(SpaceRepositoryListener.class);
this.spaceRepository = Mockito.mock(SpaceRepository.class);
Mockito.when(this.spaceRepository.createSpace(ArgumentMatchers.any(SpaceID.class), ArgumentMatchers.any(Class.class)))
.thenAnswer(new Answer<Space>() {
@Override
public Space answer(InvocationOnMock invocation) throws Throwable {
OpenEventSpace space = Mockito.mock(OpenEventSpace.class);
Mockito.when(space.getSpaceID()).thenReturn((SpaceID) invocation.getArguments()[0]);
ContextTest.this.spaces.put(((SpaceID) invocation.getArguments()[0]).getID(), space);
assert (ContextTest.this.privateListener != null);
ContextTest.this.privateListener.spaceCreated(space, true);
return space;
}
});
Mockito.when(this.spaceRepository.getOrCreateSpaceWithSpec(ArgumentMatchers.any(SpaceID.class), ArgumentMatchers.any(Class.class)))
.thenAnswer(new Answer<Space>() {
@Override
public Space answer(InvocationOnMock invocation) throws Throwable {
for (Space s : ContextTest.this.spaces.values()) {
if (s.getSpaceID().equals(invocation.getArguments()[0])) {
return s;
}
}
OpenEventSpace space = Mockito.mock(OpenEventSpace.class);
Mockito.when(space.getSpaceID()).thenReturn((SpaceID) invocation.getArguments()[0]);
ContextTest.this.spaces.put(((SpaceID) invocation.getArguments()[0]).getID(), space);
assert (ContextTest.this.privateListener != null);
ContextTest.this.privateListener.spaceCreated(space, true);
return space;
}
});
Mockito.when(this.spaceRepository.getOrCreateSpaceWithID(ArgumentMatchers.any(SpaceID.class), ArgumentMatchers.any(Class.class)))
.thenAnswer(new Answer<Space>() {
@Override
public Space answer(InvocationOnMock invocation) throws Throwable {
for (Space s : ContextTest.this.spaces.values()) {
if (s.getSpaceID().equals(invocation.getArguments()[0])) {
return s;
}
}
OpenEventSpace space = Mockito.mock(OpenEventSpace.class);
Mockito.when(space.getSpaceID()).thenReturn((SpaceID) invocation.getArguments()[0]);
ContextTest.this.spaces.put(((SpaceID) invocation.getArguments()[0]).getID(), space);
assert (ContextTest.this.privateListener != null);
ContextTest.this.privateListener.spaceCreated(space, true);
return space;
}
});
Mockito.when(this.spaceRepository.getSpaces(ArgumentMatchers.any(Class.class)))
.thenAnswer(new Answer<SynchronizedCollection<? extends Space>>() {
@Override
public SynchronizedCollection<? extends Space> answer(InvocationOnMock invocation) throws Throwable {
Collection<Space> c = new ArrayList<>();
for (OpenEventSpace space : ContextTest.this.spaces.values()) {
if (invocation.getArguments()[0].equals(space.getSpaceID().getSpaceSpecification())) {
c.add(space);
}
}
return Collections3.synchronizedCollection(c, c);
}
});
Mockito.when(this.spaceRepository.getSpace(ArgumentMatchers.any(SpaceID.class))).thenAnswer(new Answer<Space>() {
@Override
public Space answer(InvocationOnMock invocation) throws Throwable {
for (OpenEventSpace space : ContextTest.this.spaces.values()) {
if (invocation.getArguments()[0].equals(space.getSpaceID())) {
return space;
}
}
return null;
}
});
Mockito.when(this.spaceRepository.getSpaces())
.thenReturn(Collections3.synchronizedCollection((Collection) this.spaces.values(), this.spaces));
Context.DefaultSpaceRepositoryFactory spaceRepoFactory = new TestFactory(this);
spaceRepoFactory = Mockito.spy(spaceRepoFactory);
this.context = new Context(this.contextId, this.spaceId, spaceRepoFactory, this.spaceListener);
this.context.postConstruction();
}
@Test
public void twoStepConstruction() throws Exception {
TwoStepConstruction annotation = Context.class.getAnnotation(TwoStepConstruction.class);
assertNotNull(annotation);
for (String name : annotation.names()) {
for (Method method : Context.class.getMethods()) {
if (name.equals(method.getName())) {
assertTrue(Modifier.isPackage(method.getModifiers()) || Modifier.isPublic(method.getModifiers()));
break;
}
}
}
}
@Test
public void postConstruction() {
ArgumentCaptor<SpaceID> argument1 = ArgumentCaptor.forClass(SpaceID.class);
ArgumentCaptor<Class> argument2 = ArgumentCaptor.forClass(Class.class);
Mockito.verify(this.spaceRepository, new Times(1)).createSpace(argument1.capture(), argument2.capture());
assertEquals(this.contextId, argument1.getValue().getContextID());
assertEquals(this.spaceId, argument1.getValue().getID());
}
@Test
public void getID() {
assertSame(this.contextId, this.context.getID());
}
@Test
public void getDefaultSpace() {
OpenEventSpace space = this.context.getDefaultSpace();
assertNotNull(space);
assertEquals(this.contextId, space.getSpaceID().getContextID());
assertEquals(this.spaceId, space.getSpaceID().getID());
}
@Test
public void createSpace() {
Collection<? extends Space> c;
UUID id = UUID.randomUUID();
OpenEventSpace space = this.context.createSpace(OpenEventSpaceSpecification.class, id);
//
assertNotNull(space);
assertEquals(id, space.getSpaceID().getID());
c = this.context.getSpaces();
assertNotNull(c);
assertEquals(2, c.size());
Collection<UUID> ids = new ArrayList<>();
ids.add(this.spaceId);
ids.add(id);
for (Space sp : c) {
ids.remove(sp.getSpaceID().getID());
}
assertTrue(ids.isEmpty());
//
assertNotNull(this.privateListener);
ArgumentCaptor<Space> argument1 = ArgumentCaptor.forClass(Space.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
// CAUTION: invoked two times due to the default space and the created space.
Mockito.verify(this.spaceListener, new Times(2)).spaceCreated(argument1.capture(), argument2.capture());
assertSame(space, argument1.getValue());
assertTrue(argument2.getValue());
//
OpenEventSpace defSpace = this.spaces.get(this.spaceId);
assertNotNull(defSpace);
ArgumentCaptor<Event> argument3 = ArgumentCaptor.forClass(Event.class);
Mockito.verify(defSpace, new Times(1)).emit(argument3.capture());
assertThat(argument3.getValue(), new IsInstanceOf(SpaceCreated.class));
assertEquals(id, ((SpaceCreated) argument3.getValue()).spaceID.getID());
}
@Test
public void getOrCreateSpaceWithSpec() {
Collection<? extends Space> c;
UUID id = UUID.randomUUID();
OpenEventSpace space = this.context.getOrCreateSpaceWithSpec(OpenEventSpaceSpecification.class, id);
//
assertNotNull(space);
assertEquals(id, space.getSpaceID().getID());
c = this.context.getSpaces();
assertNotNull(c);
assertEquals(2, c.size());
Collection<UUID> ids = new ArrayList<>();
ids.add(this.spaceId);
ids.add(id);
for (Space sp : c) {
ids.remove(sp.getSpaceID().getID());
}
assertTrue(ids.isEmpty());
//
assertNotNull(this.privateListener);
ArgumentCaptor<Space> argument1 = ArgumentCaptor.forClass(Space.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
// CAUTION: invoked two times due to the default space and the created space.
Mockito.verify(this.spaceListener, new Times(2)).spaceCreated(argument1.capture(), argument2.capture());
assertSame(space, argument1.getValue());
assertTrue(argument2.getValue());
//
OpenEventSpace defSpace = this.spaces.get(this.spaceId);
assertNotNull(defSpace);
ArgumentCaptor<Event> argument3 = ArgumentCaptor.forClass(Event.class);
Mockito.verify(defSpace, new Times(1)).emit(argument3.capture());
assertThat(argument3.getValue(), new IsInstanceOf(SpaceCreated.class));
assertEquals(id, ((SpaceCreated) argument3.getValue()).spaceID.getID());
//
OpenEventSpace space2 = this.context.getOrCreateSpaceWithSpec(OpenEventSpaceSpecification.class, id);
assertSame(space, space2);
}
@Test
public void getOrCreateSpaceWithID() {
Collection<? extends Space> c;
UUID id = UUID.randomUUID();
OpenEventSpace space = this.context.getOrCreateSpaceWithID(id, OpenEventSpaceSpecification.class);
//
assertNotNull(space);
assertEquals(id, space.getSpaceID().getID());
c = this.context.getSpaces();
assertNotNull(c);
assertEquals(2, c.size());
Collection<UUID> ids = new ArrayList<>();
ids.add(this.spaceId);
ids.add(id);
for (Space sp : c) {
ids.remove(sp.getSpaceID().getID());
}
assertTrue(ids.isEmpty());
//
assertNotNull(this.privateListener);
ArgumentCaptor<Space> argument1 = ArgumentCaptor.forClass(Space.class);
ArgumentCaptor<Boolean> argument2 = ArgumentCaptor.forClass(Boolean.class);
// CAUTION: invoked two times due to the default space and the created space.
Mockito.verify(this.spaceListener, new Times(2)).spaceCreated(argument1.capture(), argument2.capture());
assertSame(space, argument1.getValue());
assertTrue(argument2.getValue());
//
OpenEventSpace defSpace = this.spaces.get(this.spaceId);
assertNotNull(defSpace);
ArgumentCaptor<Event> argument3 = ArgumentCaptor.forClass(Event.class);
Mockito.verify(defSpace, new Times(1)).emit(argument3.capture());
assertThat(argument3.getValue(), new IsInstanceOf(SpaceCreated.class));
assertEquals(id, ((SpaceCreated) argument3.getValue()).spaceID.getID());
//
OpenEventSpace space2 = this.context.getOrCreateSpaceWithID(id, OpenEventSpaceSpecification.class);
assertSame(space, space2);
}
@Test
public void getSpaces() {
Collection<? extends Space> c;
c = this.context.getSpaces();
assertNotNull(c);
assertEquals(1, c.size());
assertEquals(this.spaceId, c.iterator().next().getSpaceID().getID());
//
UUID id = UUID.randomUUID();
this.context.createSpace(OpenEventSpaceSpecification.class, id);
//
c = this.context.getSpaces();
assertNotNull(c);
assertEquals(2, c.size());
Collection<UUID> ids = new ArrayList<>();
ids.add(this.spaceId);
ids.add(id);
for (Space space : c) {
ids.remove(space.getSpaceID().getID());
}
assertTrue(ids.isEmpty());
}
@Test
public void getSpacesClass() {
Collection<OpenEventSpace> c;
c = this.context.getSpaces(OpenEventSpaceSpecification.class);
assertNotNull(c);
assertEquals(1, c.size());
assertEquals(this.spaceId, c.iterator().next().getSpaceID().getID());
//
UUID id = UUID.randomUUID();
this.context.createSpace(OpenEventSpaceSpecification.class, id);
//
c = this.context.getSpaces(OpenEventSpaceSpecification.class);
assertNotNull(c);
assertEquals(2, c.size());
Collection<UUID> ids = new ArrayList<>();
ids.add(this.spaceId);
ids.add(id);
for (Space space : c) {
ids.remove(space.getSpaceID().getID());
}
assertTrue(ids.isEmpty());
}
@Test
public void getSpaceUUID() {
assertNotNull(this.context.getSpace(this.spaceId));
assertNull(this.context.getSpace(UUID.randomUUID()));
}
@Test
public void destroy() {
this.context.destroy();
Mockito.verify(this.spaceRepository, new Times(1)).destroy();
}
public static class TestFactory extends Context.DefaultSpaceRepositoryFactory {
private final ContextTest test;
public TestFactory(ContextTest test) {
super(mock(Injector.class), mock(DistributedDataStructureService.class), mock(LogService.class));
this.test = test;
}
@Override
protected SpaceRepository newInstanceWithPrivateSpaceListener(Context context, String distributedSpaceSetName,
SpaceRepositoryListener listener) {
this.test.privateListener = listener;
return this.test.spaceRepository;
}
}
}