package tech.easyflow.common.cache;

import com.alicp.jetcache.CacheValueHolder;
import com.alicp.jetcache.support.JavaValueEncoder;
import org.junit.Assert;
import org.junit.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * {@link ApplicationClassLoaderJavaValueDecoder} 回归测试。
 */
public class ApplicationClassLoaderJavaValueDecoderTest {

    /**
     * 验证异步线程上下文类加载器不可见应用依赖时仍可解码缓存值。
     *
     * @throws Exception 异步任务执行失败时抛出
     */
    @Test
    public void applyShouldUseApplicationClassLoaderInAsyncThread() throws Exception {
        ApplicationClassLoaderJavaValueDecoder decoder = new ApplicationClassLoaderJavaValueDecoder();
        CacheValueHolder<String> holder = new CacheValueHolder<>("workflow-state", TimeUnit.MINUTES.toMillis(1));
        byte[] encoded = new JavaValueEncoder(true).apply(holder);
        ClassLoader isolatedClassLoader = new ClassLoader(null) {
        };

        assertClassIsInvisible(isolatedClassLoader, CacheValueHolder.class.getName());
        ExecutorService executor = Executors.newSingleThreadExecutor(task -> {
            Thread thread = new Thread(task, "jetcache-decoder-test");
            thread.setContextClassLoader(isolatedClassLoader);
            return thread;
        });
        try {
            Object decoded = executor.submit(() -> decoder.apply(encoded)).get(5, TimeUnit.SECONDS);

            Assert.assertTrue(decoded instanceof CacheValueHolder<?>);
            Assert.assertEquals("workflow-state", ((CacheValueHolder<?>) decoded).getValue());
        } finally {
            executor.shutdownNow();
        }
    }

    /**
     * 验证指定类加载器无法加载目标类。
     *
     * @param classLoader 待验证类加载器
     * @param className 目标类名
     */
    private void assertClassIsInvisible(ClassLoader classLoader, String className) {
        try {
            classLoader.loadClass(className);
            Assert.fail("isolated class loader should not load " + className);
        } catch (ClassNotFoundException expected) {
            // 隔离类加载器符合测试前提。
        }
    }
}
