001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.ivy.plugins.lock;
019:
020: import java.io.File;
021: import java.text.ParseException;
022:
023: import junit.framework.TestCase;
024:
025: import org.apache.ivy.core.cache.DefaultRepositoryCacheManager;
026: import org.apache.ivy.core.cache.RepositoryCacheManager;
027: import org.apache.ivy.core.event.EventManager;
028: import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
029: import org.apache.ivy.core.module.id.ModuleRevisionId;
030: import org.apache.ivy.core.resolve.ResolveData;
031: import org.apache.ivy.core.resolve.ResolveEngine;
032: import org.apache.ivy.core.resolve.ResolveOptions;
033: import org.apache.ivy.core.resolve.ResolvedModuleRevision;
034: import org.apache.ivy.core.settings.IvySettings;
035: import org.apache.ivy.core.sort.SortEngine;
036: import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener;
037: import org.apache.ivy.plugins.repository.file.FileRepository;
038: import org.apache.ivy.plugins.resolver.FileSystemResolver;
039: import org.apache.ivy.util.CopyProgressEvent;
040: import org.apache.ivy.util.FileUtil;
041: import org.apache.ivy.util.Message;
042:
043: public class ArtifactLockStrategyTest extends TestCase {
044: protected void setUp() throws Exception {
045: FileUtil.forceDelete(new File("build/test/cache"));
046: }
047:
048: protected void tearDown() throws Exception {
049: FileUtil.forceDelete(new File("build/test/cache"));
050: }
051:
052: public void testConcurrentResolve() throws Exception {
053: // we use different settings because Ivy do not support multi thread resolve with the same
054: // settings yet and this is not what this test is about: the focus of this test is running
055: // concurrent resolves in separate vms but using the same cache. We don't span the test on
056: // multiple vms, but using separate settings we should only run into shared cache related
057: // issues, and not multi thread related issues.
058: IvySettings settings1 = new IvySettings();
059: IvySettings settings2 = new IvySettings();
060: IvySettings settings3 = new IvySettings();
061:
062: // run 3 concurrent resolves, one taking 100ms to download files, one 20ms and one 5ms
063: // the first one do 10 resolves, the second one 20 and the third 50
064: // note that the download time is useful only at the very beginning, then the cached file is used
065: ResolveThread t1 = asyncResolve(settings1, createSlowResolver(
066: settings1, 100), "org6#mod6.4;3", 10);
067: ResolveThread t2 = asyncResolve(settings2, createSlowResolver(
068: settings2, 20), "org6#mod6.4;3", 20);
069: ResolveThread t3 = asyncResolve(settings3, createSlowResolver(
070: settings3, 5), "org6#mod6.4;3", 50);
071: t1.join(100000);
072: t2.join(20000);
073: t3.join(20000);
074: assertEquals(10, t1.getCount());
075: assertFound("org6#mod6.4;3", t1.getFinalResult());
076: assertEquals(20, t2.getCount());
077: assertFound("org6#mod6.4;3", t2.getFinalResult());
078: assertEquals(50, t3.getCount());
079: assertFound("org6#mod6.4;3", t3.getFinalResult());
080: }
081:
082: private RepositoryCacheManager newCacheManager(IvySettings settings) {
083: DefaultRepositoryCacheManager cacheManager = new DefaultRepositoryCacheManager(
084: "cache", settings, new File("build/test/cache"));
085: cacheManager.setLockStrategy(new ArtifactLockStrategy());
086: return cacheManager;
087: }
088:
089: private FileSystemResolver createSlowResolver(IvySettings settings,
090: final int sleep) {
091: FileSystemResolver resolver = new FileSystemResolver();
092: resolver.setRepositoryCacheManager(newCacheManager(settings));
093: resolver.setRepository(new FileRepository() {
094: private RepositoryCopyProgressListener progress = new RepositoryCopyProgressListener(
095: this ) {
096: public void progress(CopyProgressEvent evt) {
097: super .progress(evt);
098: sleepSilently(sleep); // makes the file copy longer to test concurrency issues
099: }
100: };
101:
102: protected RepositoryCopyProgressListener getProgressListener() {
103: return progress;
104: }
105: });
106: resolver.setName("test");
107: resolver.setSettings(settings);
108: resolver
109: .addIvyPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]");
110: resolver
111: .addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]");
112: return resolver;
113: }
114:
115: private ResolveThread asyncResolve(IvySettings settings,
116: FileSystemResolver resolver, String module, int loop) {
117: ResolveThread thread = new ResolveThread(settings, resolver,
118: module, loop);
119: thread.start();
120: return thread;
121: }
122:
123: private void assertFound(String module, ResolvedModuleRevision rmr) {
124: assertNotNull(rmr);
125: assertEquals(module, rmr.getId().toString());
126: }
127:
128: private ResolvedModuleRevision resolveModule(IvySettings settings,
129: FileSystemResolver resolver, String module)
130: throws ParseException {
131: return resolver.getDependency(new DefaultDependencyDescriptor(
132: ModuleRevisionId.parse(module), false),
133: new ResolveData(new ResolveEngine(settings,
134: new EventManager(), new SortEngine(settings)),
135: new ResolveOptions()));
136: }
137:
138: private void sleepSilently(int timeout) {
139: try {
140: Thread.sleep(timeout);
141: } catch (InterruptedException e) {
142: }
143: }
144:
145: private class ResolveThread extends Thread {
146: private IvySettings settings;
147: private FileSystemResolver resolver;
148: private String module;
149: private final int loop;
150:
151: private ResolvedModuleRevision finalResult;
152: private int count;
153:
154: public ResolveThread(IvySettings settings,
155: FileSystemResolver resolver, String module, int loop) {
156: this .settings = settings;
157: this .resolver = resolver;
158: this .module = module;
159: this .loop = loop;
160: }
161:
162: public synchronized ResolvedModuleRevision getFinalResult() {
163: return finalResult;
164: }
165:
166: public synchronized int getCount() {
167: return count;
168: }
169:
170: public void run() {
171: ResolvedModuleRevision rmr = null;
172: for (int i = 0; i < loop; i++) {
173: try {
174: rmr = resolveModule(settings, resolver, module);
175: if (rmr == null) {
176: throw new RuntimeException("module not found: "
177: + module);
178: }
179: synchronized (this ) {
180: //Message.info(this.toString() + " count = " + count);
181: count++;
182: }
183: } catch (ParseException e) {
184: Message.info("parse exception " + e);
185: } catch (RuntimeException e) {
186: Message.info("exception " + e);
187: e.printStackTrace();
188: throw e;
189: } catch (Error e) {
190: Message.info("exception " + e);
191: e.printStackTrace();
192: throw e;
193: }
194: }
195: synchronized (this) {
196: finalResult = rmr;
197: }
198: }
199: }
200:
201: }
|