Skip to content
Snippets Groups Projects

Add testing for the quarkus core module

21 files
+ 828
543
Compare changes
  • Side-by-side
  • Inline
Files
21
/*********************************************************************
* Copyright (c) 2022 Eclipse Foundation.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipsefoundation.core.model;
import java.net.URI;
import java.time.Duration;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.core.MultivaluedMap;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.context.ManagedExecutor;
import org.eclipsefoundation.core.helper.ParameterHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.quarkus.arc.Unremovable;
import io.quarkus.cache.Cache;
import io.quarkus.cache.CacheInvalidate;
import io.quarkus.cache.CacheKey;
import io.quarkus.cache.CacheName;
import io.quarkus.cache.CacheResult;
import io.quarkus.cache.CaffeineCache;
/**
* Represents a cached context recorder to apply back to state for cached requests. This is used to track side effects
* on the request that may not be included in the original cache. These recorded states are sensitive to the response
* status, and should not be recorded or applied on non-2xx requests.
*
* @author Martin Lowe
*
* @param <T> the type that is recorded and applied to the request.
*/
@ApplicationScoped
@Unremovable
public abstract class CacheRecorder<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(CacheRecorder.class);
@ConfigProperty(name = "quarkus.cache.caffeine.\"default\".expire-after-write", defaultValue = "P1H")
Duration recorderTTL;
@Inject
@CacheName("default")
Cache cache;
@Inject
protected ParameterHelper paramHelper;
@Inject
ManagedExecutor exec;
/**
* Generates the record and does internal tracking of the key for the request. The tracked key is only updated on new
* cache entries, and fetching will not modify this time or extend it.
*
* @param key the key to generate a record for
* @param context the current requests context.
* @return the generated record for the current request.
*/
@CacheResult(cacheName = "default")
public T createCacheRecord(@CacheKey String key, RequestWrapper context) {
// track the key
long ttl = System.currentTimeMillis() + recorderTTL.toMillis();
LOGGER.debug("Recording key with ttl of {}({} millis from now)", ttl, recorderTTL.toMillis());
return calculateRecord(context);
}
/**
* Calculates the record that will be applied to following requests with the same key. This method should not be called
* directly as it breaks the flow for recording cached key entries.
*
* @param context the current request context.
* @return the recorded data to cache
*/
protected abstract T calculateRecord(RequestWrapper context);
/**
* Applies the given record to the current request context.
*
* @param cacheRecord the record to apply
* @param wrap the current request context.
*/
public abstract void apply(T cacheRecord, RequestWrapper wrap, ContainerResponseContext responseContext);
/**
* Invalidates the passed key in the record cache and removes the key from internal tracking.
*
* @param key the key to invalidate
*/
@CacheInvalidate(cacheName = "default")
public void remove(@CacheKey String key) {
}
/**
* Does best efforts checking of whether this cache key exists for this recorder and has not expired.
*
* @param key the key to check for a recorded value.
* @return true if value exists and is current, false otherwise.
*/
public boolean hasRecorded(String key) {
// cache.as(CaffeineCache.class).
return cache.as(CaffeineCache.class).keySet().stream().anyMatch(k -> k instanceof String && ((String) k).equals(key));
}
/**
* Generates recorder-specific key for the request which depends on the URI rather than an object ID which is used in
* the standard data cache.
*
* @param context the current request context
* @return recorder-specific cache key for the request
*/
public String generateKey(RequestWrapper context) {
StringBuilder sb = new StringBuilder();
URI uri = context.getURI();
if (uri != null) {
sb.append(uri.getPath());
}
MultivaluedMap<String, String> params = context.asMap();
paramHelper
.filterUnknownParameters(params)
.entrySet()
.stream()
.filter(e -> !e.getValue().isEmpty())
.map(e -> e.getKey() + '=' + String.join(",", e.getValue()))
.forEach(s -> sb.append('|').append(s));
return sb.toString();
}
}
Loading