Skip to content

Commit

Permalink
add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
EddeCCC committed Jul 22, 2024
1 parent 3902297 commit a9ab84e
Show file tree
Hide file tree
Showing 14 changed files with 377 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package rocks.inspectit.gepard.agent.instrumentation;

import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder;
import java.lang.instrument.Instrumentation;
import java.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -15,8 +17,12 @@ public class InstrumentationManager {

private final PendingClassesCache pendingClassesCache;

private InstrumentationManager(PendingClassesCache pendingClassesCache) {
private final Instrumentation instrumentation;

private InstrumentationManager(
PendingClassesCache pendingClassesCache, Instrumentation instrumentation) {
this.pendingClassesCache = pendingClassesCache;
this.instrumentation = instrumentation;
}

/**
Expand All @@ -26,7 +32,8 @@ private InstrumentationManager(PendingClassesCache pendingClassesCache) {
*/
public static InstrumentationManager create() {
PendingClassesCache pendingClassesCache = new PendingClassesCache();
return new InstrumentationManager(pendingClassesCache);
Instrumentation instrumentation = InstrumentationHolder.getInstrumentation();
return new InstrumentationManager(pendingClassesCache, instrumentation);
}

/**
Expand All @@ -35,7 +42,8 @@ public static InstrumentationManager create() {
*/
public void startClassDiscovery() {
InspectitScheduler scheduler = InspectitScheduler.getInstance();
ClassDiscoveryService discoveryService = new ClassDiscoveryService(pendingClassesCache);
ClassDiscoveryService discoveryService =
new ClassDiscoveryService(pendingClassesCache, instrumentation);
Duration discoveryInterval = Duration.ofSeconds(30);
scheduler.startRunnable(discoveryService, discoveryInterval);
}
Expand All @@ -46,15 +54,17 @@ public void startClassDiscovery() {
*/
public void startBatchInstrumentation() {
InspectitScheduler scheduler = InspectitScheduler.getInstance();
BatchInstrumenter batchInstrumenter = new BatchInstrumenter(pendingClassesCache);
BatchInstrumenter batchInstrumenter =
new BatchInstrumenter(pendingClassesCache, instrumentation);
Duration batchInterval = Duration.ofMillis(500);
scheduler.startRunnable(batchInstrumenter, batchInterval);
}

/** Creates an observer, who listens to {@link ConfigurationReceivedEvent}s. */
public void createConfigurationReceiver() {
log.info("Creating ConfigurationReceiver...");
ConfigurationReceiver configurationReceiver = new ConfigurationReceiver(pendingClassesCache);
ConfigurationReceiver configurationReceiver =
new ConfigurationReceiver(pendingClassesCache, instrumentation);
configurationReceiver.subscribeToConfigurationReceivedEvents();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package rocks.inspectit.gepard.agent.instrumentation.filling;

import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder;
import java.lang.instrument.Instrumentation;
import java.util.Collections;
import java.util.HashSet;
Expand All @@ -23,10 +22,11 @@ public class ClassDiscoveryService implements NamedRunnable {

private final Instrumentation instrumentation;

public ClassDiscoveryService(PendingClassesCache pendingClassesCache) {
public ClassDiscoveryService(
PendingClassesCache pendingClassesCache, Instrumentation instrumentation) {
this.discoveredClasses = Collections.newSetFromMap(new WeakHashMap<>());
this.pendingClassesCache = pendingClassesCache;
this.instrumentation = InstrumentationHolder.getInstrumentation();
this.instrumentation = instrumentation;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package rocks.inspectit.gepard.agent.instrumentation.filling;

import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder;
import java.lang.instrument.Instrumentation;
import java.util.Set;
import org.slf4j.Logger;
Expand All @@ -20,9 +19,10 @@ public class ConfigurationReceiver implements ConfigurationReceivedObserver {

private final Instrumentation instrumentation;

public ConfigurationReceiver(PendingClassesCache pendingClassesCache) {
public ConfigurationReceiver(
PendingClassesCache pendingClassesCache, Instrumentation instrumentation) {
this.pendingClassesCache = pendingClassesCache;
this.instrumentation = InstrumentationHolder.getInstrumentation();
this.instrumentation = instrumentation;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package rocks.inspectit.gepard.agent.instrumentation.processing;

import com.google.common.annotations.VisibleForTesting;
import io.opentelemetry.javaagent.bootstrap.InstrumentationHolder;
import java.lang.instrument.Instrumentation;
import java.util.*;
import org.slf4j.Logger;
Expand All @@ -16,17 +15,14 @@ public class BatchInstrumenter implements NamedRunnable {
/** Hard coded batch size to transform classes */
private static final int BATCH_SIZE = 1000;

/**
* The set of classes which might need instrumentation updates. This service works through this
* set in batches.
*/
private final Instrumentation instrumentation;

private final PendingClassesCache pendingClassesCache;

public BatchInstrumenter(PendingClassesCache pendingClassesCache) {
private final Instrumentation instrumentation;

public BatchInstrumenter(
PendingClassesCache pendingClassesCache, Instrumentation instrumentation) {
this.pendingClassesCache = pendingClassesCache;
this.instrumentation = InstrumentationHolder.getInstrumentation();
this.instrumentation = instrumentation;
}

@Override
Expand All @@ -49,7 +45,7 @@ public void run() {
*/
@VisibleForTesting
Set<Class<?>> getNextBatch(int batchSize) {
Set<Class<?>> batch = new HashSet<>();
Set<Class<?>> classesToBeInstrumented = new HashSet<>();
int checkedClassesCount = 0;
Iterator<Class<?>> queueIterator = pendingClassesCache.getKeyIterator();

Expand All @@ -58,7 +54,7 @@ Set<Class<?>> getNextBatch(int batchSize) {
queueIterator.remove();
checkedClassesCount++;

if (ConfigurationResolver.shouldRetransform(clazz)) batch.add(clazz);
if (ConfigurationResolver.shouldRetransform(clazz)) classesToBeInstrumented.add(clazz);

if (checkedClassesCount >= batchSize) break;
}
Expand All @@ -68,7 +64,7 @@ Set<Class<?>> getNextBatch(int batchSize) {
checkedClassesCount,
pendingClassesCache.getSize());

return batch;
return classesToBeInstrumented;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package rocks.inspectit.gepard.agent.instrumentation.filling;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import rocks.inspectit.gepard.agent.instrumentation.PendingClassesCache;

import java.lang.instrument.Instrumentation;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class ClassDiscoveryServiceTest {

@Mock
private Instrumentation instrumentation;

@Test
void discoveryDoesFillCache() {
Class<?>[] clazz = {getClass()};
when(instrumentation.getAllLoadedClasses()).thenReturn(clazz);
PendingClassesCache cache = new PendingClassesCache();
ClassDiscoveryService service = new ClassDiscoveryService(cache, instrumentation);

service.discoverClasses();

assertEquals(1, cache.getSize());
verify(instrumentation, times(1)).getAllLoadedClasses();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package rocks.inspectit.gepard.agent.instrumentation.filling;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

import java.lang.instrument.Instrumentation;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import rocks.inspectit.gepard.agent.instrumentation.PendingClassesCache;
import rocks.inspectit.gepard.agent.internal.configuration.model.InspectitConfiguration;
import rocks.inspectit.gepard.agent.internal.configuration.observer.ConfigurationReceivedEvent;

@ExtendWith(MockitoExtension.class)
class ConfigurationReceiverTest {

@Mock private Instrumentation instrumentation;

@Test
void receiverDoesFillCache() {
Class<?>[] clazz = {getClass()};
when(instrumentation.getAllLoadedClasses()).thenReturn(clazz);
PendingClassesCache cache = new PendingClassesCache();
ConfigurationReceiver receiver = new ConfigurationReceiver(cache, instrumentation);
ConfigurationReceivedEvent event = new ConfigurationReceivedEvent(this, new InspectitConfiguration());

receiver.handleConfiguration(event);

assertEquals(1, cache.getSize());
verify(instrumentation, times(1)).getAllLoadedClasses();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package rocks.inspectit.gepard.agent.instrumentation.processing;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import rocks.inspectit.gepard.agent.instrumentation.PendingClassesCache;
import rocks.inspectit.gepard.agent.internal.configuration.ConfigurationHolder;
import rocks.inspectit.gepard.agent.internal.configuration.model.InspectitConfiguration;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.InstrumentationConfiguration;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.Scope;
import rocks.inspectit.gepard.agent.internal.configuration.observer.ConfigurationReceivedEvent;

import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class BatchInstrumenterTest {

private final static int BATCH_SIZE = 10;

private final Class<?> TEST_CLASS = getClass();

@Mock
private Instrumentation instrumentation;

@Mock
private PendingClassesCache cache;

@Test
void classIsRemovedFromCacheAndNotAddedToBatch() {
Set<Class<?>> classes = new HashSet<>();
classes.add(TEST_CLASS);
when(cache.getKeyIterator()).thenReturn(classes.iterator());
BatchInstrumenter instrumenter = new BatchInstrumenter(cache, instrumentation);

Set<Class<?>> classesToBeInstrumented = instrumenter.getNextBatch(BATCH_SIZE);

assertEquals(0, classesToBeInstrumented.size());
assertEquals(0, classes.size());
}

@Test
void classIsRemovedFromCacheAndAddedToBatch() {
updateConfigurationHolder();
Set<Class<?>> classes = new HashSet<>();
classes.add(TEST_CLASS);
when(cache.getKeyIterator()).thenReturn(classes.iterator());
BatchInstrumenter instrumenter = new BatchInstrumenter(cache, instrumentation);

Set<Class<?>> classesToBeInstrumented = instrumenter.getNextBatch(BATCH_SIZE);

assertEquals(1, classesToBeInstrumented.size());
assertEquals(0, classes.size());
}

@Test
void classIsRetransformed() throws UnmodifiableClassException {
Set<Class<?>> classes = new HashSet<>();
classes.add(TEST_CLASS);
BatchInstrumenter instrumenter = new BatchInstrumenter(cache, instrumentation);

instrumenter.retransformBatch(classes.iterator());

verify(instrumentation).retransformClasses(TEST_CLASS);
}

/**
* Updates the current {@link InspectitConfiguration}
*/
private void updateConfigurationHolder() {
Scope scope = new Scope(TEST_CLASS.getName(), true);
InstrumentationConfiguration instrumentationConfiguration =
new InstrumentationConfiguration(List.of(scope));
InspectitConfiguration configuration = new InspectitConfiguration(instrumentationConfiguration);

ConfigurationHolder holder = ConfigurationHolder.getInstance();
ConfigurationReceivedEvent event = new ConfigurationReceivedEvent(this, configuration);
holder.handleConfiguration(event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.util.List;
import org.junit.jupiter.api.Test;
import rocks.inspectit.gepard.agent.internal.configuration.model.InspectitConfiguration;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.InstrumentationConfiguration;
import rocks.inspectit.gepard.agent.internal.configuration.model.instrumentation.Scope;
import rocks.inspectit.gepard.agent.internal.configuration.observer.ConfigurationReceivedEvent;

import java.util.List;

public class ConfigurationHolderTest {
class ConfigurationHolderTest {

private final ConfigurationHolder holder = ConfigurationHolder.getInstance();

Expand All @@ -27,15 +26,16 @@ void configurationIsUpdated() {
InspectitConfiguration configuration = createConfiguration();
ConfigurationReceivedEvent event = new ConfigurationReceivedEvent(this, configuration);

holder.handleConfiguration(event);
holder.handleConfiguration(event);

InspectitConfiguration updatedConfiguration = holder.getConfiguration();
assertEquals(configuration, updatedConfiguration);
}

private InspectitConfiguration createConfiguration() {
Scope scope = new Scope("com.example.Application", true);
InstrumentationConfiguration instrumentationConfiguration = new InstrumentationConfiguration(List.of(scope));
InstrumentationConfiguration instrumentationConfiguration =
new InstrumentationConfiguration(List.of(scope));
return new InspectitConfiguration(instrumentationConfiguration);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package rocks.inspectit.gepard.agent.internal.configuration.observer;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.jupiter.api.Test;
import rocks.inspectit.gepard.agent.internal.configuration.model.InspectitConfiguration;

class ConfigurationReceivedSubjectTest {

@Test
void listenersAreNotified() {
AtomicBoolean wasNotified = new AtomicBoolean(false);

ConfigurationReceivedObserver observer = (event) -> wasNotified.set(true);
observer.subscribeToConfigurationReceivedEvents();

ConfigurationReceivedSubject subject = ConfigurationReceivedSubject.getInstance();
subject.notifyListeners(new InspectitConfiguration());

assertTrue(wasNotified.get());
}
}
Loading

0 comments on commit a9ab84e

Please sign in to comment.