/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.server.service.servicemanager;
import com.foundationdb.server.service.servicemanager.configuration.ServiceBinding;
import com.foundationdb.util.Strings;
import com.google.inject.ProvisionException;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public final class GuicerTest {
@Before
public void clearMessages() {
DummyInterfaces.clearMessages();
}
@Test
public void simple() throws Exception {
Guicer guicer = messageGuicer(
bind(DummyInterfaces.Alpha.class, DummySimpleServices.SimpleAlpha.class, true),
bind(DummyInterfaces.Beta.class, DummySimpleServices.SimpleBeta.class, false),
bind(DummyInterfaces.Gamma.class, DummySimpleServices.SimpleGamma.class, false)
);
startRequiredServices(guicer);
assertEquals(
"messages",
joined(
"starting SimpleAlpha",
"starting SimpleBeta",
"starting SimpleGamma",
"started SimpleGamma",
"started SimpleBeta",
"started SimpleAlpha"
),
Strings.join(DummyInterfaces.messages())
);
}
@Test
public void mixedDI() throws Exception {
Guicer guicer = messageGuicer(
bind(DummyInterfaces.Alpha.class, DummyMixedDIServices.MixedDIAlpha.class, true),
bind(DummyInterfaces.Beta.class, DummyMixedDIServices.MixedDIBeta.class, false),
bind(DummyInterfaces.Gamma.class, DummyMixedDIServices.MixedDIGamma.class, false)
);
startRequiredServices(guicer);
assertEquals(
"messages",
joined(
"starting MixedDIBeta",
"starting MixedDIGamma",
"started MixedDIGamma",
"started MixedDIBeta",
"starting MixedDIAlpha",
"started MixedDIAlpha"
),
Strings.join(DummyInterfaces.messages())
);
}
@Test
public void errorOnStartup() throws Exception {
Guicer guicer = messageGuicer(
bind(DummyInterfaces.Alpha.class, DummyErroringServices.ErroringAlpha.class, true),
bind(DummyInterfaces.Beta.class, DummyErroringServices.ErroringBeta.class, false),
bind(DummyInterfaces.Gamma.class, DummyErroringServices.ErroringGamma.class, false)
);
try{
startRequiredServices(guicer);
fail("should have caught ErroringException");
} catch (ProvisionException e) {
assertEventualCause(e, DummyErroringServices.ErroringException.class);
assertEquals(
"messages",
joined(
"starting ErroringAlpha",
"starting ErroringBeta",
"starting ErroringGamma",
"started ErroringGamma",
"stopping ErroringGamma",
"stopped ErroringGamma"
),
Strings.join(DummyInterfaces.messages())
);
}
}
@Test
public void singletonNess() throws Exception {
Guicer guicer = messageGuicer(
bind(DummyInterfaces.Gamma.class, DummySimpleServices.SimpleGamma.class, false)
);
guicer.get(DummyInterfaces.Gamma.class, MESSAGING_ACTIONS);
guicer.get(DummyInterfaces.Gamma.class, MESSAGING_ACTIONS);
assertEquals(
"messages",
joined(
"starting SimpleGamma",
"started SimpleGamma"
),
Strings.join(DummyInterfaces.messages())
);
}
@Test(expected=IllegalArgumentException.class)
public void getRequiresInterface() throws ClassNotFoundException {
Guicer guicer = messageGuicer(
bind(DummyInterfaces.Alpha.class, DummySimpleServices.SimpleAlpha.class, true),
bind(DummyInterfaces.Beta.class, DummySimpleServices.SimpleBeta.class, false),
bind(DummyInterfaces.Gamma.class, DummySimpleServices.SimpleGamma.class, false)
);
startRequiredServices(guicer);
Object a = guicer.get(DummyInterfaces.Alpha.class, MESSAGING_ACTIONS);
Object b = guicer.get(DummyInterfaces.Alpha.class, MESSAGING_ACTIONS);
assertEquals("two different gets", a, b);
guicer.get(DummySimpleServices.SimpleAlpha.class, MESSAGING_ACTIONS);
}
private void startRequiredServices(Guicer guicer) {
for (Class<?> clazz : guicer.directlyRequiredClasses()) {
guicer.get(clazz, MESSAGING_ACTIONS);
}
}
private void assertEventualCause(Throwable e, Class<? extends Throwable> exceptionClassToFind) {
Throwable cause = e;
while (cause != null) {
if (cause.getClass().equals(exceptionClassToFind)) {
return;
}
cause = cause.getCause();
}
fail(exceptionClassToFind + " was not in the causes of " + e);
}
private static Guicer messageGuicer(ServiceBinding... bindings) throws ClassNotFoundException {
return onlyGuicer = Guicer.forServices(Arrays.asList(bindings));
}
private static <T> ServiceBinding bind(Class<T> theInterface, Class<? extends T> theClass, boolean required) {
if (!theInterface.isInterface()) {
throw new IllegalArgumentException("theInterface must be an interface class: " + theInterface);
}
if (theClass.isInterface()) {
throw new IllegalArgumentException("theClass must not be an interface class: " + theClass);
}
ServiceBinding binding = new ServiceBinding(theInterface.getName());
binding.setImplementingClass(theClass.getName());
if (required) {
binding.markDirectlyRequired();
}
return binding;
}
private static String joined(String... strings) {
return Strings.join(Arrays.asList(strings));
}
// For use within package
static Guicer onlyGuicer() {
if (onlyGuicer == null) {
throw new IllegalStateException("no guicer set");
}
return onlyGuicer;
}
// class state
static final Guicer.ServiceLifecycleActions<DummyInterfaces.DummyService> MESSAGING_ACTIONS
= new Guicer.ServiceLifecycleActions<DummyInterfaces.DummyService>()
{
@Override
public void onStart(DummyInterfaces.DummyService service) {
DummyInterfaces.addMessage("starting " + service.getClass().getSimpleName());
service.start();
DummyInterfaces.addMessage("started " + service.getClass().getSimpleName());
}
@Override
public void onShutdown(DummyInterfaces.DummyService service) {
DummyInterfaces.addMessage("stopping " + service.getClass().getSimpleName());
service.stop();
DummyInterfaces.addMessage("stopped " + service.getClass().getSimpleName());
}
@Override
public DummyInterfaces.DummyService castIfActionable(Object object) {
return (object instanceof DummyInterfaces.DummyService) ? (DummyInterfaces.DummyService) object : null;
}
};
private static Guicer onlyGuicer;
}