/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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.datakernel.jmx;
import com.google.inject.BindingAnnotation;
import com.google.inject.Key;
import org.jmock.Expectations;
import org.jmock.integration.junit4.JUnitRuleMockery;
import org.junit.Rule;
import org.junit.Test;
import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static io.datakernel.jmx.helper.CustomMatchers.objectname;
import static java.util.Arrays.asList;
public class JmxRegistryTest {
@Rule
public JUnitRuleMockery context = new JUnitRuleMockery();
private MBeanServer mBeanServer = context.mock(MBeanServer.class);
private DynamicMBeanFactory mbeanFactory = context.mock(DynamicMBeanFactory.class);
private DynamicMBean dynamicMBean = context.mock(DynamicMBean.class);
private JmxRegistry jmxRegistry = JmxRegistry.create(mBeanServer, mbeanFactory);
private final String domain = ServiceStub.class.getPackage().getName();
private final MBeanSettings settings = MBeanSettings.defaultSettings();
@Test
public void registerSingletonInstanceWithout_Annotation_AndComposeAppropriateObjectName() throws Exception {
final ServiceStub service = new ServiceStub();
context.checking(new Expectations() {{
allowing(mbeanFactory).createFor(with(asList(service)), with(any(MBeanSettings.class)), with(true));
will(returnValue(dynamicMBean));
oneOf(mBeanServer).registerMBean(with(dynamicMBean), with(objectname(domain + ":type=ServiceStub")));
}});
Key<?> key_1 = Key.get(ServiceStub.class);
jmxRegistry.registerSingleton(key_1, service, settings);
}
@Test
public void registerSingletonInstanceWith_AnnotationWithoutParameters_AndComposeAppropriateObjectName()
throws Exception {
final ServiceStub service = new ServiceStub();
context.checking(new Expectations() {{
allowing(mbeanFactory).createFor(with(asList(service)), with(any(MBeanSettings.class)), with(true));
will(returnValue(dynamicMBean));
oneOf(mBeanServer).registerMBean(with(dynamicMBean),
with(objectname(domain + ":type=ServiceStub,annotation=BasicService")));
}});
BasicService basicServiceAnnotation = createBasicServiceAnnotation();
Key<?> key = Key.get(ServiceStub.class, basicServiceAnnotation);
jmxRegistry.registerSingleton(key, service, settings);
}
@Test
public void registerSingletonInstanceWith_AnnotationWithOneDefaultParameter_AndComposeAppropriateObjectName()
throws Exception {
final ServiceStub service = new ServiceStub();
context.checking(new Expectations() {{
allowing(mbeanFactory).createFor(with(asList(service)), with(any(MBeanSettings.class)), with(true));
will(returnValue(dynamicMBean));
oneOf(mBeanServer).registerMBean(with(dynamicMBean), with(objectname(domain + ":Group=major")));
}});
Group groupAnnotation = createGroupAnnotation("major");
Key<?> key = Key.get(ServiceStub.class, groupAnnotation);
jmxRegistry.registerSingleton(key, service, settings);
}
@Test
public void registerSingletonInstanceWith_AnnotationWithSeveralParameters_AndComposeAppropriateObjectName()
throws Exception {
final ServiceStub service = new ServiceStub();
context.checking(new Expectations() {{
allowing(mbeanFactory).createFor(with(asList(service)), with(any(MBeanSettings.class)), with(true));
will(returnValue(dynamicMBean));
oneOf(mBeanServer).registerMBean(
with(dynamicMBean), with(objectname(domain + ":threadId=1,threadName=thread-one")));
}});
ComplexAnnotation complexAnnotation = createComplexAnnotation(1, "thread-one");
Key<?> key = Key.get(ServiceStub.class, complexAnnotation);
jmxRegistry.registerSingleton(key, service, settings);
}
@Test
public void unregisterSingletonInstance() throws Exception {
final ServiceStub service = new ServiceStub();
context.checking(new Expectations() {{
oneOf(mBeanServer).unregisterMBean(with(objectname(domain + ":type=ServiceStub,annotation=BasicService")));
}});
BasicService basicServiceAnnotation = createBasicServiceAnnotation();
Key<?> key = Key.get(ServiceStub.class, basicServiceAnnotation);
jmxRegistry.unregisterSingleton(key, service);
}
@Test
public void registerWorkers_andComposeAppropriateObjectNames() throws Exception {
final ServiceStub worker_1 = new ServiceStub();
final ServiceStub worker_2 = new ServiceStub();
final ServiceStub worker_3 = new ServiceStub();
context.checking(new Expectations() {{
// creating DynamicMBeans for each worker separately
allowing(mbeanFactory).createFor(with(asList(worker_1)), with(any(MBeanSettings.class)), with(false));
will(returnValue(dynamicMBean));
allowing(mbeanFactory).createFor(with(asList(worker_2)), with(any(MBeanSettings.class)), with(false));
will(returnValue(dynamicMBean));
allowing(mbeanFactory).createFor(with(asList(worker_3)), with(any(MBeanSettings.class)), with(false));
will(returnValue(dynamicMBean));
// creating DynamicMBean for worker pool
allowing(mbeanFactory).createFor(with(asList(worker_1, worker_2, worker_3)),
with(any(MBeanSettings.class)), with(true));
will(doAll());
will(returnValue(dynamicMBean));
// checking calls and names for each worker separately
oneOf(mBeanServer).registerMBean(
with(dynamicMBean),
with(objectname(domain + ":type=ServiceStub,annotation=BasicService,workerId=worker-0")));
oneOf(mBeanServer).registerMBean(
with(dynamicMBean),
with(objectname(domain + ":type=ServiceStub,annotation=BasicService,workerId=worker-1")));
oneOf(mBeanServer).registerMBean(
with(dynamicMBean),
with(objectname(domain + ":type=ServiceStub,annotation=BasicService,workerId=worker-2")));
// checking calls and names for worker_pool DynamicMBean
oneOf(mBeanServer).registerMBean(with(dynamicMBean),
with(objectname(domain + ":type=ServiceStub,annotation=BasicService")));
}});
BasicService basicServiceAnnotation = createBasicServiceAnnotation();
Key<?> key = Key.get(ServiceStub.class, basicServiceAnnotation);
jmxRegistry.registerWorkers(key, asList(worker_1, worker_2, worker_3), settings);
}
@Test
public void unregisterWorkers() throws Exception {
final ServiceStub worker_1 = new ServiceStub();
final ServiceStub worker_2 = new ServiceStub();
final ServiceStub worker_3 = new ServiceStub();
context.checking(new Expectations() {{
// checking calls and names for each worker separately
oneOf(mBeanServer).unregisterMBean(
with(objectname(domain + ":type=ServiceStub,annotation=BasicService,workerId=worker-0")));
oneOf(mBeanServer).unregisterMBean(
with(objectname(domain + ":type=ServiceStub,annotation=BasicService,workerId=worker-1")));
oneOf(mBeanServer).unregisterMBean(
with(objectname(domain + ":type=ServiceStub,annotation=BasicService,workerId=worker-2")));
// checking calls and names for worker_pool DynamicMBean
oneOf(mBeanServer).unregisterMBean(
with(objectname(domain + ":type=ServiceStub,annotation=BasicService")));
}});
BasicService basicServiceAnnotation = createBasicServiceAnnotation();
Key<?> key = Key.get(ServiceStub.class, basicServiceAnnotation);
jmxRegistry.unregisterWorkers(key, asList(worker_1, worker_2, worker_3));
}
// annotations
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
public @interface BasicService {
}
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
public @interface Group {
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@BindingAnnotation
public @interface ComplexAnnotation {
int threadId() default -1;
String threadName() default "defaultThread";
}
// helpers for creating annotations
public static BasicService createBasicServiceAnnotation() {
return new BasicService() {
@Override
public Class<? extends Annotation> annotationType() {
return BasicService.class;
}
};
}
public static Group createGroupAnnotation(final String value) {
return new Group() {
@Override
public Class<? extends Annotation> annotationType() {
return Group.class;
}
@Override
public String value() {
return value;
}
};
}
public static ComplexAnnotation createComplexAnnotation(final int threadId, final String threadName) {
return new ComplexAnnotation() {
@Override
public Class<? extends Annotation> annotationType() {
return ComplexAnnotation.class;
}
@Override
public int threadId() {
return threadId;
}
@Override
public String threadName() {
return threadName;
}
};
}
// helper classes
public final class ServiceStub implements ConcurrentJmxMBean {
}
}