| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.ivy.plugins.lock; |
| |
| import java.io.File; |
| import java.text.ParseException; |
| |
| import org.apache.ivy.core.cache.DefaultRepositoryCacheManager; |
| import org.apache.ivy.core.cache.RepositoryCacheManager; |
| import org.apache.ivy.core.event.EventManager; |
| import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; |
| import org.apache.ivy.core.module.id.ModuleRevisionId; |
| import org.apache.ivy.core.resolve.ResolveData; |
| import org.apache.ivy.core.resolve.ResolveEngine; |
| import org.apache.ivy.core.resolve.ResolveOptions; |
| import org.apache.ivy.core.resolve.ResolvedModuleRevision; |
| import org.apache.ivy.core.settings.IvySettings; |
| import org.apache.ivy.core.sort.SortEngine; |
| import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener; |
| import org.apache.ivy.plugins.repository.file.FileRepository; |
| import org.apache.ivy.plugins.resolver.FileSystemResolver; |
| import org.apache.ivy.util.CopyProgressEvent; |
| import org.apache.ivy.util.FileUtil; |
| import org.apache.ivy.util.Message; |
| |
| import junit.framework.TestCase; |
| |
| public class ArtifactLockStrategyTest extends TestCase { |
| protected void setUp() throws Exception { |
| FileUtil.forceDelete(new File("build/test/cache")); |
| } |
| |
| protected void tearDown() throws Exception { |
| FileUtil.forceDelete(new File("build/test/cache")); |
| } |
| |
| public void testConcurrentResolve() throws Exception { |
| // 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. |
| IvySettings settings1 = new IvySettings(); |
| IvySettings settings2 = new IvySettings(); |
| IvySettings settings3 = new IvySettings(); |
| |
| // 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, 100), |
| "org6#mod6.4;3", 10); |
| ResolveThread t2 = asyncResolve(settings2, createSlowResolver(settings2, 20), |
| "org6#mod6.4;3", 20); |
| ResolveThread t3 = asyncResolve(settings3, createSlowResolver(settings3, 5), |
| "org6#mod6.4;3", 50); |
| t1.join(100000); |
| t2.join(20000); |
| t3.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()); |
| } |
| |
| private RepositoryCacheManager newCacheManager(IvySettings settings) { |
| DefaultRepositoryCacheManager cacheManager = new DefaultRepositoryCacheManager("cache", |
| settings, new File("build/test/cache")); |
| cacheManager.setLockStrategy(new CreateFileLockStrategy(false)); |
| return cacheManager; |
| } |
| |
| private FileSystemResolver createSlowResolver(IvySettings settings, final int sleep) { |
| FileSystemResolver resolver = new FileSystemResolver(); |
| resolver.setRepositoryCacheManager(newCacheManager(settings)); |
| resolver.setRepository(new FileRepository() { |
| private RepositoryCopyProgressListener progress = new RepositoryCopyProgressListener( |
| this) { |
| public void progress(CopyProgressEvent evt) { |
| super.progress(evt); |
| sleepSilently(sleep); // makes the file copy longer to test concurrency issues |
| } |
| }; |
| |
| protected RepositoryCopyProgressListener getProgressListener() { |
| return progress; |
| } |
| }); |
| resolver.setName("test"); |
| resolver.setSettings(settings); |
| resolver.addIvyPattern(settings.getBaseDir() |
| + "/test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"); |
| resolver.addArtifactPattern(settings.getBaseDir() |
| + "/test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"); |
| return resolver; |
| } |
| |
| private ResolveThread asyncResolve(IvySettings 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(IvySettings settings, FileSystemResolver resolver, |
| String module) throws ParseException { |
| return resolver.getDependency( |
| new DefaultDependencyDescriptor(ModuleRevisionId.parse(module), false), |
| new ResolveData(new ResolveEngine(settings, new EventManager(), |
| new SortEngine(settings)), new ResolveOptions())); |
| } |
| |
| private void sleepSilently(int timeout) { |
| try { |
| Thread.sleep(timeout); |
| } catch (InterruptedException e) { |
| } |
| } |
| |
| private class ResolveThread extends Thread { |
| private IvySettings settings; |
| |
| private FileSystemResolver resolver; |
| |
| private String module; |
| |
| private final int loop; |
| |
| private ResolvedModuleRevision finalResult; |
| |
| private int count; |
| |
| public ResolveThread(IvySettings settings, FileSystemResolver resolver, String module, |
| int loop) { |
| this.settings = settings; |
| this.resolver = resolver; |
| this.module = module; |
| this.loop = loop; |
| } |
| |
| public synchronized ResolvedModuleRevision getFinalResult() { |
| return finalResult; |
| } |
| |
| public synchronized int getCount() { |
| return count; |
| } |
| |
| 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); |
| } |
| synchronized (this) { |
| // Message.info(this.toString() + " count = " + count); |
| 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; |
| } |
| } |
| synchronized (this) { |
| finalResult = rmr; |
| } |
| } |
| } |
| |
| } |