package org.jfrog.wharf.ivy; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.apache.ivy.core.resolve.ResolvedModuleRevision; import org.apache.ivy.core.settings.IvySettings; import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener; import org.apache.ivy.plugins.resolver.FileSystemResolver; import org.apache.ivy.util.CopyProgressEvent; import org.apache.ivy.util.Message; import org.jfrog.wharf.ivy.repository.WharfURLRepository; import org.jfrog.wharf.ivy.resolver.FileSystemWharfResolver; import java.text.ParseException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; /** * Date: 9/15/11 * Time: 6:09 PM * * @author Fred Simon */ public class BaseLockResolverTest extends AbstractDependencyResolverTest { protected void runResolvers() throws InterruptedException { // we use different settings because Ivy do not support multi thread resolve with the same // settings yet and this is not what this test is about: the focus of this test is running // concurrent resolves in separate vms but using the same cache. We don't span the test on // multiple vms, but using separate settings we should only run into shared cache related // issues, and not multi thread related issues. IvySettingsTestHolder settings1 = createNewSettings(); IvySettingsTestHolder settings2 = createNewSettings(); IvySettingsTestHolder settings3 = createNewSettings(); IvySettingsTestHolder settings4 = createNewSettings(); // run 3 concurrent resolves, one taking 100ms to download files, one 20ms and one 5ms // the first one do 10 resolves, the second one 20 and the third 50 // note that the download time is useful only at the very beginning, then the cached file is used ResolveThread t1 = asyncResolve( settings1, createSlowResolver(settings1.settings, 100), "org6#mod6.4;3", 10); ResolveThread t2 = asyncResolve( settings2, createSlowResolver(settings2.settings, 20), "org6#mod6.4;3", 20); ResolveThread t3 = asyncResolve( settings3, createSlowResolver(settings3.settings, 5), "org6#mod6.4;3", 50); ResolveThread t4 = asyncResolve( settings3, createSlowResolver(settings4.settings, 5), "org6#mod6.2;2.0", 50); t1.join(100000); t2.join(20000); t3.join(20000); t4.join(20000); assertEquals(10, t1.getCount()); assertFound("org6#mod6.4;3", t1.getFinalResult()); assertEquals(20, t2.getCount()); assertFound("org6#mod6.4;3", t2.getFinalResult()); assertEquals(50, t3.getCount()); assertFound("org6#mod6.4;3", t3.getFinalResult()); assertEquals(50, t4.getCount()); assertFound("org6#mod6.2;2.0", t4.getFinalResult()); } private FileSystemResolver createSlowResolver(IvySettings settings, final int sleep) { FileSystemWharfResolver resolver = new FileSystemWharfResolver(); resolver.setRepositoryCacheManager(settings.getDefaultRepositoryCacheManager()); resolver.setRepository(new WharfURLRepository() { private RepositoryCopyProgressListener progress = new RepositoryCopyProgressListener(this) { @Override public void progress(CopyProgressEvent evt) { super.progress(evt); sleepSilently(sleep); // makes the file copy longer to test concurrency issues } }; public RepositoryCopyProgressListener getProgressListener() { return progress; } }); resolver.setName("test"); resolver.setSettings(settings); resolver.addIvyPattern(repoTestRoot.getAbsolutePath() + "/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"); resolver.addArtifactPattern(repoTestRoot.getAbsolutePath() + "/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"); resolver.setChecksums(""); settings.addResolver(resolver); return resolver; } private ResolveThread asyncResolve(IvySettingsTestHolder settings, FileSystemResolver resolver, String module, int loop) { ResolveThread thread = new ResolveThread(settings, resolver, module, loop); thread.start(); return thread; } private void assertFound(String module, ResolvedModuleRevision rmr) { assertNotNull(rmr); assertEquals(module, rmr.getId().toString()); } private ResolvedModuleRevision resolveModule(IvySettingsTestHolder settings, FileSystemResolver resolver, String module) throws ParseException { return resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.parse(module), false), settings.data); } private void sleepSilently(int timeout) { try { Thread.sleep(timeout); } catch (InterruptedException e) { } } private class ResolveThread extends Thread { private IvySettingsTestHolder settings; private FileSystemResolver resolver; private String module; private final int loop; private ResolvedModuleRevision finalResult; private int count; public ResolveThread(IvySettingsTestHolder settings, FileSystemResolver resolver, String module, int loop) { this.settings = settings; this.resolver = resolver; this.module = module; this.loop = loop; } public ResolvedModuleRevision getFinalResult() { return finalResult; } public int getCount() { return count; } @Override public void run() { ResolvedModuleRevision rmr = null; for (int i = 0; i < loop; i++) { try { rmr = resolveModule(settings, resolver, module); if (rmr == null) { throw new RuntimeException("module not found: " + module); } count++; } catch (ParseException e) { Message.info("parse exception " + e); } catch (RuntimeException e) { Message.info("exception " + e); e.printStackTrace(); throw e; } catch (Error e) { Message.info("exception " + e); e.printStackTrace(); throw e; } } finalResult = rmr; } } }