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