Skip to content

Commit

Permalink
Fix generated concurrently (#701)
Browse files Browse the repository at this point in the history
  • Loading branch information
seongahjo authored Jul 4, 2023
1 parent 7f1493f commit 948880e
Show file tree
Hide file tree
Showing 15 changed files with 191 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Fixture Monkey
*
* Copyright (c) 2021-present NAVER Corp.
*
* 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 com.navercorp.fixturemonkey.api.container;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;

/**
* It is the Concurrent Least Recently Used cache.
* It would remove the least recently used element when it is full.
*
* @param <K> key of the cache
* @param <V> value of the cache
*/
@SuppressWarnings("NullableProblems")
@API(since = "0.5.10", status = Status.EXPERIMENTAL)
public final class ConcurrentLruCache<K, V> implements Map<K, V> {
private final Map<K, V> lruCache;

public ConcurrentLruCache(int maxSize) {
lruCache = Collections.synchronizedMap(new LruCache<>(maxSize));
}

@Override
public int size() {
return lruCache.size();
}

@Override
public boolean isEmpty() {
return lruCache.isEmpty();
}

@Override
public boolean containsKey(Object key) {
return lruCache.containsKey(key);
}

@Override
public boolean containsValue(Object value) {
return lruCache.containsValue(value);
}

@Override
public V get(Object key) {
return lruCache.get(key);
}

@Override
public V put(K key, V value) {
return lruCache.put(key, value);
}

@Override
public V remove(Object key) {
return lruCache.remove(key);
}

@Override
public void putAll(Map<? extends K, ? extends V> map) {
lruCache.putAll(map);
}

@Override
public void clear() {
lruCache.clear();
}

@Override
public Set<K> keySet() {
return lruCache.keySet();
}

@Override
public Collection<V> values() {
return lruCache.values();
}

@Override
public Set<Entry<K, V>> entrySet() {
return lruCache.entrySet();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*/
@API(since = "0.6.0", status = Status.EXPERIMENTAL)
public final class IteratorCache {
private static final LruCache<Iterator<?>, List<?>> ITERATOR_TO_LIST = new LruCache<>(2048);
private static final ConcurrentLruCache<Iterator<?>, List<?>> ITERATOR_TO_LIST = new ConcurrentLruCache<>(2048);

/**
* Gets the elements of {@link Iterator} in an idempotent manner.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
*/
@API(since = "0.6.0", status = Status.EXPERIMENTAL)
public final class StreamCache {
private static final LruCache<Stream<?>, List<?>> STREAM_TO_LIST = new LruCache<>(2048);
private static final ConcurrentLruCache<Stream<?>, List<?>> STREAM_TO_LIST = new ConcurrentLruCache<>(2048);

/**
* Gets the elements of {@link Stream} in an idempotent manner.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@
import org.apiguardian.api.API.Status;

import com.navercorp.fixturemonkey.api.arbitrary.CombinableArbitrary;
import com.navercorp.fixturemonkey.api.container.LruCache;
import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache;
import com.navercorp.fixturemonkey.api.property.Property;
import com.navercorp.fixturemonkey.api.property.RootProperty;

@API(since = "0.4.0", status = Status.MAINTAINED)
public final class MonkeyContext {
private final LruCache<Property, CombinableArbitrary> arbitrariesByProperty;
private final LruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty;
private final ConcurrentLruCache<Property, CombinableArbitrary> arbitrariesByProperty;
private final ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty;

public MonkeyContext(
LruCache<Property, CombinableArbitrary> arbitrariesByProperty,
LruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty
ConcurrentLruCache<Property, CombinableArbitrary> arbitrariesByProperty,
ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty
) {
this.arbitrariesByProperty = arbitrariesByProperty;
this.generatorContextByRootProperty = generatorContextByRootProperty;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@
import org.apiguardian.api.API.Status;

import com.navercorp.fixturemonkey.api.arbitrary.CombinableArbitrary;
import com.navercorp.fixturemonkey.api.container.LruCache;
import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache;
import com.navercorp.fixturemonkey.api.property.Property;
import com.navercorp.fixturemonkey.api.property.RootProperty;

@API(since = "0.4.0", status = Status.MAINTAINED)
public final class MonkeyContextBuilder {
private LruCache<Property, CombinableArbitrary> arbitrariesByProperty;
private LruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty;
private ConcurrentLruCache<Property, CombinableArbitrary> arbitrariesByProperty;
private ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty;
private int cacheSize = 2048;
private int generatorContextSize = 1000;

public MonkeyContextBuilder arbitrariesByProperty(
LruCache<Property, CombinableArbitrary> arbitrariesByProperty
ConcurrentLruCache<Property, CombinableArbitrary> arbitrariesByProperty
) {
this.arbitrariesByProperty = arbitrariesByProperty;
return this;
}

public MonkeyContextBuilder generatorContextByRootProperty(
LruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty
ConcurrentLruCache<RootProperty, MonkeyGeneratorContext> generatorContextByRootProperty
) {
this.generatorContextByRootProperty = generatorContextByRootProperty;
return this;
Expand All @@ -59,11 +59,11 @@ public MonkeyContextBuilder generatorContextSize(int generatorContextSize) {

public MonkeyContext build() {
if (arbitrariesByProperty == null) {
arbitrariesByProperty = new LruCache<>(cacheSize);
arbitrariesByProperty = new ConcurrentLruCache<>(cacheSize);
}

if (generatorContextByRootProperty == null) {
generatorContextByRootProperty = new LruCache<>(generatorContextSize);
generatorContextByRootProperty = new ConcurrentLruCache<>(generatorContextSize);
}

return new MonkeyContext(arbitrariesByProperty, generatorContextByRootProperty);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

@API(since = "0.4.0", status = Status.MAINTAINED)
public final class ArbitraryIntrospectorResult {
private static final Object LOCK = new Object();
public static final ArbitraryIntrospectorResult EMPTY = new ArbitraryIntrospectorResult(
CombinableArbitrary.from(new Object())
);
Expand All @@ -42,7 +43,9 @@ public ArbitraryIntrospectorResult(@Nullable Arbitrary<?> value) {
this.value = CombinableArbitrary.from(LazyArbitrary.lazy(
() -> {
if (value != null) {
return value.sample();
synchronized (LOCK) {
return value.sample();
}
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.navercorp.fixturemonkey.api.container.LruCache;
import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache;

@API(since = "0.4.0", status = Status.MAINTAINED)
public final class TypeCache {
Expand All @@ -53,10 +53,10 @@ public final class TypeCache {
private static final Map<PropertyDescriptor, AnnotatedType> PROPERTY_DESCRIPTOR_ANNOTATED_TYPE_MAP =
new ConcurrentHashMap<>(2048);
private static final Map<Class<?>, Map<String, PropertyDescriptor>> PROPERTY_DESCRIPTORS =
new LruCache<>(2048);
private static final Map<Class<?>, Map<String, Field>> FIELDS = new LruCache<>(2048);
new ConcurrentLruCache<>(2048);
private static final Map<Class<?>, Map<String, Field>> FIELDS = new ConcurrentLruCache<>(2048);
private static final Map<Class<?>, Map.Entry<Constructor<?>, String[]>> PARAMETER_NAMES_BY_PRIMARY_CONSTRUCTOR =
new LruCache<>(2048);
new ConcurrentLruCache<>(2048);

public static AnnotatedType getAnnotatedType(Field field) {
return FIELD_ANNOTATED_TYPE_MAP.computeIfAbsent(field, Field::getAnnotatedType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
package com.navercorp.fixturemonkey.kotlin.introspector

import com.navercorp.fixturemonkey.api.arbitrary.CombinableArbitrary
import com.navercorp.fixturemonkey.api.container.LruCache
import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache
import com.navercorp.fixturemonkey.api.generator.ArbitraryGeneratorContext
import com.navercorp.fixturemonkey.api.introspector.ArbitraryIntrospector
import com.navercorp.fixturemonkey.api.introspector.ArbitraryIntrospectorResult
Expand All @@ -37,7 +37,7 @@ import kotlin.reflect.full.primaryConstructor
class PrimaryConstructorArbitraryIntrospector : ArbitraryIntrospector {
companion object {
val INSTANCE = PrimaryConstructorArbitraryIntrospector()
private val CONSTRUCTOR_CACHE = LruCache<Class<*>, KFunction<*>>(2048)
private val CONSTRUCTOR_CACHE = ConcurrentLruCache<Class<*>, KFunction<*>>(2048)
}

override fun introspect(context: ArbitraryGeneratorContext): ArbitraryIntrospectorResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

package com.navercorp.fixturemonkey.kotlin.property

import com.navercorp.fixturemonkey.api.container.LruCache
import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache
import com.navercorp.fixturemonkey.api.property.Property
import com.navercorp.fixturemonkey.api.type.Types
import com.navercorp.fixturemonkey.kotlin.type.getAnnotatedType
Expand All @@ -27,7 +27,7 @@ import java.lang.reflect.AnnotatedType
import kotlin.reflect.KProperty
import kotlin.reflect.full.memberProperties

private val KPROPERTY_ANNOTATED_TYPE_MAP = LruCache<Class<*>, Collection<KProperty<*>>>(2048)
private val KPROPERTY_ANNOTATED_TYPE_MAP = ConcurrentLruCache<Class<*>, Collection<KProperty<*>>>(2048)

@API(since = "0.4.0", status = API.Status.MAINTAINED)
fun getMemberProperties(annotatedType: AnnotatedType): List<Property> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

package com.navercorp.fixturemonkey.kotlin.property

import com.navercorp.fixturemonkey.api.container.LruCache
import com.navercorp.fixturemonkey.api.container.ConcurrentLruCache
import com.navercorp.fixturemonkey.api.property.CompositeProperty
import com.navercorp.fixturemonkey.api.property.DefaultPropertyGenerator
import com.navercorp.fixturemonkey.api.property.Property
Expand All @@ -36,7 +36,7 @@ import java.lang.reflect.AnnotatedType
class KotlinPropertyGenerator(
private val javaDelegatePropertyGenerator: PropertyGenerator = DefaultPropertyGenerator(),
) : PropertyGenerator {
private val objectChildPropertiesCache = LruCache<AnnotatedType, List<Property>>(2048)
private val objectChildPropertiesCache = ConcurrentLruCache<AnnotatedType, List<Property>>(2048)

override fun generateChildProperties(annotatedType: AnnotatedType): List<Property> =
objectChildPropertiesCache.computeIfAbsent(annotatedType) {
Expand Down
7 changes: 7 additions & 0 deletions fixture-monkey-tests/java-concurrent-tests/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
java {
toolchain { languageVersion = JavaLanguageVersion.of(17) }
}

dependencies {
testImplementation(project(":fixture-monkey-jackson"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.navercorp.fixturemonkey.tests.concurrent;

import static com.navercorp.fixturemonkey.tests.TestEnvironment.TEST_COUNT;
import static org.assertj.core.api.BDDAssertions.then;

import java.util.Map;

import org.junit.jupiter.api.RepeatedTest;

import com.navercorp.fixturemonkey.FixtureMonkey;
import com.navercorp.fixturemonkey.api.introspector.ConstructorPropertiesArbitraryIntrospector;

class ConcurrentTest {
private static final FixtureMonkey SUT = FixtureMonkey.builder()
.objectIntrospector(ConstructorPropertiesArbitraryIntrospector.INSTANCE)
.build();

@RepeatedTest(TEST_COUNT)
void test1() {
JavaObject actual = SUT.giveMeOne(JavaObject.class);

then(actual).isNotNull();
}

@RepeatedTest(TEST_COUNT)
void test2() {
JavaObject actual = SUT.giveMeOne(JavaObject.class);

then(actual).isNotNull();
}

@RepeatedTest(TEST_COUNT)
void test3() {
JavaObject actual = SUT.giveMeOne(JavaObject.class);

then(actual).isNotNull();
}

public record JavaObject(
String value,
Map<String, String> map
) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=CONCURRENT
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ public <T> ArbitraryBuilder<T> giveMeBuilder(T value) {
}

public <T> Stream<T> giveMe(Class<T> type) {
return this.giveMeBuilder(type).build().sampleStream();
return Stream.generate(() -> this.giveMeBuilder(type).sample());
}

public <T> Stream<T> giveMe(TypeReference<T> typeReference) {
return this.giveMeBuilder(typeReference).build().sampleStream();
return Stream.generate(() -> this.giveMeBuilder(typeReference).sample());
}

public <T> List<T> giveMe(Class<T> type, int size) {
Expand Down
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ include 'fixture-monkey-tests:kotlin-tests'
findProject(':fixture-monkey-tests:kotlin-tests')?.name = 'kotlin-tests'
include 'fixture-monkey-tests:java-tests'
findProject(':fixture-monkey-tests:java-tests')?.name = 'java-tests'
include 'fixture-monkey-tests:java-concurrent-tests'
findProject(':fixture-monkey-tests:java-concurrent-tests')?.name = 'java-concurrent-tests'

0 comments on commit 948880e

Please sign in to comment.