1 /*******************************************************************************
2  * Copyright (c) 2009, 2017 Cloudsmith Inc. and others.
3  * The code, documentation and other materials contained herein have been
4  * licensed under the Eclipse Public License - v 1.0 by the copyright holder
5  * listed above, as the Initial Contributor under such license. The text of
6  * such license is available at www.eclipse.org.
7  ******************************************************************************/
8 
9 package org.eclipse.equinox.p2.tests.repository;
10 
11 import java.io.ByteArrayOutputStream;
12 import java.net.URI;
13 import java.security.cert.Certificate;
14 import org.eclipse.core.runtime.*;
15 import org.eclipse.equinox.internal.p2.transport.ecf.RepositoryTransport;
16 import org.eclipse.equinox.p2.core.ProvisionException;
17 import org.eclipse.equinox.p2.core.UIServices;
18 import org.eclipse.equinox.p2.tests.metadata.repository.AllServerTests;
19 import org.eclipse.equinox.p2.tests.testserver.helper.AbstractTestServerClientCase;
20 
21 /**
22  * Test handling of timeout in FileInfoReader and FileReader
23  */
24 public class TimeoutTest extends AbstractTestServerClientCase {
25 	private static final int MODIFIED = 1;
26 	private static final int DOWNLOAD = 2;
27 	private static final int STREAM = 3;
28 
29 	protected String authTestFailMessage;
30 
31 	@Override
tearDown()32 	public void tearDown() throws Exception {
33 		AllServerTests.setServiceUI(null); // cleanup hook
34 		super.tearDown();
35 	}
36 
37 	/**
38 	 * Test that timeout occurs, that the expected exception is thrown, and with correct detail
39 	 * and message.
40 	 * Note that test takes at least 120 seconds to complete due to length of timeout.
41 	 * @throws ProvisionException
42 	 * @throws Exception
43 	 */
doTimeout(int type)44 	public void doTimeout(int type) throws Exception {
45 		System.out.print("Note that test takes at least 120 seconds before timing out\n");
46 		AllServerTests.setServiceUI(new AladdinNotSavedService());
47 		RepositoryTransport transport = new RepositoryTransport();
48 		URI toDownload = new URI(getBaseURL() + "/timeout/whatever.txt");
49 		long startTime = System.currentTimeMillis();
50 		boolean caught = false;
51 		try {
52 			switch (type) {
53 				case DOWNLOAD :
54 					IStatus status = transport.download(toDownload, new ByteArrayOutputStream(), null);
55 					assertSocketTimeout(status, null);
56 					caught = true;
57 					break;
58 				case MODIFIED :
59 					transport.getLastModified(toDownload, null);
60 					break;
61 				case STREAM :
62 					transport.stream(toDownload, null);
63 					break;
64 			}
65 		} catch (OperationCanceledException e) {
66 			fail("The getLastModified was canceled - the UI auth service is probably not running");
67 		} catch (CoreException e) {
68 
69 			IStatus status = e.getStatus();
70 			assertSocketTimeout(status, e);
71 			caught = true;
72 		} catch (Exception e) {
73 			e.printStackTrace();
74 		}
75 		long endTime = System.currentTimeMillis();
76 		System.out.print("The timeout took:" + Long.valueOf((endTime - startTime) / 1000).toString() + "\n");
77 		assertTrue("timeout should have been caught", caught);
78 	}
79 
assertSocketTimeout(IStatus status, Exception e)80 	private void assertSocketTimeout(IStatus status, Exception e) {
81 		Throwable ex = status.getException();
82 		String msg = e == null ? "" : e.getMessage();
83 		if (ex instanceof CoreException)
84 			msg = ((CoreException) ex).getStatus().getMessage();
85 
86 		// Print for human inspection
87 		System.out.print(String.format("%s e-message: [%s], detail:[%s]\n", //
88 				provisionCodeToText(status.getCode()), msg, ex != null ? ex.getMessage() : "<no detailed message>"));
89 		assertEquals("Socket timeout exception should be found as detail", ex.getClass(), java.net.SocketTimeoutException.class);
90 
91 	}
92 
93 	/**
94 	 * Test that timeout occurs, that the expected exception is thrown, and with correct detail
95 	 * and message.
96 	 * Note that test takes at least 120 seconds to complete due to length of timeout.
97 	 * @throws ProvisionException
98 	 * @throws Exception
99 	 */
testInfoTimeout()100 	public void testInfoTimeout() throws Exception {
101 		doTimeout(MODIFIED);
102 	}
103 
104 	/**
105 	 * Test that it is possible to cancel a repository load that hangs on a HEAD request.
106 	 * Note that test takes at least 10 seconds (the cancel delay time). The real timeout is
107 	 * 120 seconds.
108 	 * @throws ProvisionException
109 	 * @throws Exception
110 	 */
testInfoTimeoutCancelation()111 	public void testInfoTimeoutCancelation() throws Exception {
112 		doTimeoutCancelation(MODIFIED);
113 	}
114 
testDownloadTimeout()115 	public void testDownloadTimeout() throws Exception {
116 		doTimeout(DOWNLOAD);
117 	}
118 
testDownloadTimeoutCancelation()119 	public void testDownloadTimeoutCancelation() throws Exception {
120 		doTimeoutCancelation(DOWNLOAD);
121 	}
122 
testStreamTimeout()123 	public void testStreamTimeout() throws Exception {
124 		doTimeout(STREAM);
125 	}
126 
testStreamTimeoutCancelation()127 	public void testStreamTimeoutCancelation() throws Exception {
128 		doTimeoutCancelation(STREAM);
129 	}
130 
doTimeoutCancelation(int type)131 	public void doTimeoutCancelation(int type) throws Exception {
132 		System.out.print("Note that test takes at least 10 seconds before timing out (and >120 if it fails)\n");
133 
134 		AllServerTests.setServiceUI(new AladdinNotSavedService());
135 		RepositoryTransport transport = new RepositoryTransport();
136 		URI toDownload = new URI(getBaseURL() + "/timeout/whatever.txt");
137 
138 		IProgressMonitor monitor = new NullProgressMonitor();
139 		MonitorCancelation cancelHandler = new MonitorCancelation(monitor, 10000);
140 		Thread proc = new Thread(cancelHandler, "cancelHandler");
141 		proc.start();
142 		boolean caught = false;
143 		long startTime = System.currentTimeMillis();
144 		try {
145 			switch (type) {
146 				case DOWNLOAD :
147 					transport.download(toDownload, new ByteArrayOutputStream(), monitor);
148 					break;
149 				case MODIFIED :
150 					transport.getLastModified(toDownload, monitor);
151 					break;
152 				case STREAM :
153 					transport.stream(toDownload, monitor);
154 					break;
155 			}
156 		} catch (OperationCanceledException e) {
157 			caught = true;
158 		} catch (CoreException e) {
159 
160 			IStatus status = e.getStatus();
161 			Throwable ex = status.getException();
162 			String msg = e.getMessage();
163 			if (ex instanceof CoreException)
164 				msg = ((CoreException) ex).getStatus().getMessage();
165 
166 			// Print for human inspection
167 			System.out.print(String.format("%s e-message: [%s], detail:[%s]\n", //
168 					provisionCodeToText(status.getCode()), msg, ex != null ? ex.getMessage() : "<no detailed message>"));
169 			assertEquals("Socket exception (socket closed) should be found as detail", ex.getClass(), java.net.SocketException.class);
170 			assertEquals("Exception message from SocketException", "Socket closed", ex.getMessage());
171 			caught = true;
172 
173 		} catch (Exception e) {
174 			e.printStackTrace();
175 		}
176 		long endTime = System.currentTimeMillis();
177 		assertTrue("The timeout should have been canceled", caught);
178 		assertTrue("The cancel should happen before the timeout", endTime - startTime < 50000);
179 
180 		// ignore testing if repo was loaded - it may or may not, depending on where the cancellation took place.
181 		// commented code kept, in case there is a change in API - should cancellation of load keep the repository.
182 		// assertFalse("Repository should not have been added", mgr.contains(repoLoc));
183 	}
184 
provisionCodeToText(int code)185 	private static String provisionCodeToText(int code) {
186 		String msg = "REPOSITORY_";
187 		switch (code) {
188 			case ProvisionException.REPOSITORY_EXISTS :
189 				return msg + "EXISTS";
190 			case ProvisionException.REPOSITORY_FAILED_AUTHENTICATION :
191 				return msg + "FAILED_AUTHENTICATION";
192 			case ProvisionException.REPOSITORY_FAILED_READ :
193 				return msg + "FAILED_READ";
194 			case ProvisionException.REPOSITORY_FAILED_WRITE :
195 				return msg + "FAILED_WRITE";
196 			case ProvisionException.REPOSITORY_INVALID_LOCATION :
197 				return msg + "INVALID_LOCATION";
198 			case ProvisionException.REPOSITORY_NOT_FOUND :
199 				return msg + "NOT_FOUND";
200 			case ProvisionException.REPOSITORY_READ_ONLY :
201 				return msg + "READ_ONLY";
202 			case ProvisionException.REPOSITORY_UNKNOWN_TYPE :
203 				return msg + "UNKNOWN_TYPE";
204 			default :
205 				return msg + String.format("<unrecognized error code: %d >", code);
206 		}
207 	}
208 
209 	public class AladdinNotSavedService extends UIServices {
210 		public int counter = 0;
211 
212 		@Override
getUsernamePassword(String location)213 		public AuthenticationInfo getUsernamePassword(String location) {
214 			counter++;
215 			return new AuthenticationInfo("Aladdin", "open sesame", false);
216 		}
217 
218 		@Override
getUsernamePassword(String location, AuthenticationInfo previousInfo)219 		public AuthenticationInfo getUsernamePassword(String location, AuthenticationInfo previousInfo) {
220 			counter++;
221 			assertEquals("Aladdin", previousInfo.getUserName());
222 			assertEquals("open sesame", previousInfo.getPassword());
223 			assertEquals(false, previousInfo.saveResult());
224 			return previousInfo;
225 		}
226 
227 		/**
228 		 * Not used
229 		 */
230 		@Override
getTrustInfo(Certificate[][] untrustedChain, String[] unsignedDetail)231 		public TrustInfo getTrustInfo(Certificate[][] untrustedChain, String[] unsignedDetail) {
232 			return new TrustInfo(null, false, true);
233 		}
234 	}
235 
236 	public static class MonitorCancelation implements Runnable {
237 		private IProgressMonitor theMonitor;
238 		private long theDelay;
239 
MonitorCancelation(IProgressMonitor monitor, long delay)240 		MonitorCancelation(IProgressMonitor monitor, long delay) {
241 			theMonitor = monitor;
242 			theDelay = delay;
243 		}
244 
245 		@Override
run()246 		public void run() {
247 			try {
248 				Thread.sleep(theDelay);
249 			} catch (InterruptedException e) {
250 				/* ignore */
251 			}
252 			System.out.print("TimeoutTest: Cancelling monitor\n");
253 			theMonitor.setCanceled(true);
254 
255 		}
256 	}
257 }
258