/* * Copyright (c) 2012-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.systemservices; import java.io.File; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.text.MessageFormat; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.codec.binary.Base64; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import com.emc.storageos.coordinator.client.model.SoftwareVersion; import com.emc.storageos.coordinator.client.model.CoordinatorSerializable; import com.emc.storageos.coordinator.client.model.PropertyInfoExt; import static com.emc.storageos.coordinator.client.model.Constants.*; import com.emc.storageos.db.client.model.EncryptionProvider; import com.emc.storageos.services.util.EnvConfig; import com.emc.storageos.svcs.errorhandling.resources.BadRequestException; import com.emc.storageos.systemservices.exceptions.CoordinatorClientException; import com.emc.storageos.systemservices.exceptions.RemoteRepositoryException; import com.emc.storageos.systemservices.impl.upgrade.*; import com.emc.storageos.systemservices.impl.upgrade.beans.*; public class RemoteRepositoryTest { private static final String REMOTE_PROXY = EnvConfig.get("sanity", "syssvc.RemoteRepositoryTest.remoteProxy"); private static final String DOWNLOAD_DIR = EnvConfig.get("sanity", "syssvc.RemoteRepositoryTest.downloadDir"); private static final String DIRECTORY_REPO = EnvConfig.get("sanity", "syssvc.RemoteRepositoryTest.directoryRepo"); private static final String CATALOG_SERVER_URL = EnvConfig.get("sanity", "syssvc.RemoteRepositoryTest.catalogServerURL"); private static final String USERNAME = EnvConfig.get("sanity", "syssvc.RemoteRepositoryTest.username"); private static final String PASSWORD = EnvConfig.get("sanity", "syssvc.RemoteRepositoryTest.password"); private static volatile String repositoryProxy = null; private static volatile String repositoryUrl; private static volatile String username = USERNAME; private static volatile String password = PASSWORD; private static volatile RemoteRepositoryCache newSoftwareVersions; private RemoteRepository _repo = null; private UpgradeImageDownloader _downloader; private EncryptionProvider _encrypter; private String newVersionCheckLock = "new_version_check_lock"; // Suppress Sonar warning that created objects are never used. The constructors are called to set static fields. @SuppressWarnings("squid:S1848") @Before public void setup() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { new TestProductName(); _encrypter = new TestEncryptonProvider(); new TestSoftwareUpdate(_encrypter); _downloader = UpgradeImageDownloader.getInstance(null); RemoteRepository.setCoordinator(new TestCoordinatorClientExt()); } @Test public void testCatalogRepository() throws Exception { repositoryUrl = CATALOG_SERVER_URL; _repo = RemoteRepository.getInstance(); Assert.assertTrue(_repo != null); final List<SoftwareVersion> remoteVersions = _repo.getVersions(); Assert.assertTrue(remoteVersions != null); Assert.assertTrue(!remoteVersions.isEmpty()); for (SoftwareVersion v : remoteVersions) { System.out.println(v); } int downloadableVersions = 0; for (SoftwareVersion v : remoteVersions) { try { _repo.checkVersionDownloadable(v); } catch (RemoteRepositoryException e) { continue; } catch (BadRequestException e) { continue; } final InputStream in = _repo.getImageInputStream(v); Assert.assertTrue(in != null); byte[] buffer = new byte[0x10000]; Assert.assertTrue("getImageInputStream failed for " + v, in.read(buffer) > 0); in.close(); downloadableVersions++; } // Make sure there are at least some downloadable versiosn Assert.assertTrue(downloadableVersions > 0); System.out.println("Found " + downloadableVersions + " downloadable versions out of " + remoteVersions.size()); SoftwareVersion version = null; // avoid version 121 since it is bad for (SoftwareVersion remoteVersion : remoteVersions) { // / Avoid a specific version on the downloads test site because it is no good if (0 != remoteVersion.compareTo(new SoftwareVersion("vipr-1.0.0.7.121"))) { version = remoteVersion; break; } } Assert.assertNotNull(version); File file = startBackgroundDownload(version); Assert.assertNotNull(file); while (_downloader.isDownloading()) { System.out.println("Downloading " + file); Thread.sleep(2000); } Assert.assertTrue(file.exists()); } @Test public void testDirectoryRepository() throws Exception { repositoryUrl = DIRECTORY_REPO; _repo = RemoteRepository.getInstance(); Assert.assertTrue(_repo != null); final List<SoftwareVersion> remoteVersions = _repo.getVersions(); Assert.assertTrue(remoteVersions != null); Assert.assertTrue(!remoteVersions.isEmpty()); for (SoftwareVersion v : remoteVersions) { System.out.println(v); } int downloadableVersions = 0; for (SoftwareVersion v : remoteVersions) { try { _repo.checkVersionDownloadable(v); } catch (RemoteRepositoryException e) { continue; } catch (BadRequestException e) { continue; } final InputStream in = _repo.getImageInputStream(v); Assert.assertTrue(in != null); byte[] buffer = new byte[0x10000]; Assert.assertTrue("getImageInputStream failed for " + v, in.read(buffer) > 0); in.close(); downloadableVersions++; } // Make sure there are at least some downloadable versiosn Assert.assertTrue(downloadableVersions > 0); System.out.println("Found " + downloadableVersions + " downloadable versions out of " + remoteVersions.size()); final SoftwareVersion version = (SoftwareVersion) remoteVersions.toArray()[0]; File file = startBackgroundDownload(version); Assert.assertNotNull(file); while (_downloader.isDownloading()) { System.out.println("Downloading " + file); Thread.sleep(2000); } Assert.assertTrue(file.exists()); } @Test public void testRemoteDirectoryRepositoryViaProxy() throws Exception { repositoryProxy = REMOTE_PROXY; repositoryUrl = DIRECTORY_REPO; _repo = RemoteRepository.getInstance(); Assert.assertTrue(_repo != null); final List<SoftwareVersion> remoteVersions = _repo.getVersions(); Assert.assertTrue(remoteVersions != null); Assert.assertTrue(!remoteVersions.isEmpty()); for (SoftwareVersion v : remoteVersions) { System.out.println(v); } } @Test public void testCatalogRepositoryViaProxy() throws Exception { repositoryProxy = REMOTE_PROXY; repositoryUrl = CATALOG_SERVER_URL; _repo = RemoteRepository.getInstance(); Assert.assertTrue(_repo != null); final List<SoftwareVersion> remoteVersions = _repo.getVersions(); Assert.assertTrue(remoteVersions != null); Assert.assertTrue(!remoteVersions.isEmpty()); for (SoftwareVersion v : remoteVersions) { System.out.println(v); } } @Test public void testCachedVersions() throws Exception { repositoryProxy = null; newSoftwareVersions = null; repositoryUrl = null; RemoteRepository.startRemoteRepositoryCacheUpdate(); _repo = RemoteRepository.getInstance(); synchronized (newVersionCheckLock) { newVersionCheckLock.wait(60 * 1000); } Assert.assertTrue(newSoftwareVersions.getCachedVersions().isEmpty()); repositoryUrl = CATALOG_SERVER_URL; _repo = RemoteRepository.getInstance(); synchronized (newVersionCheckLock) { newVersionCheckLock.wait(60 * 1000); } Assert.assertEquals(_repo.getVersions(), newSoftwareVersions.getCachedVersions()); Assert.assertEquals(_repo.toString(), newSoftwareVersions.getRepositoryInfo()); repositoryUrl = DIRECTORY_REPO; _repo = RemoteRepository.getInstance(); synchronized (newVersionCheckLock) { newVersionCheckLock.wait(60 * 1000); } Assert.assertEquals(_repo.getVersions(), newSoftwareVersions.getCachedVersions()); Assert.assertEquals(_repo.toString(), newSoftwareVersions.getRepositoryInfo()); long previousCheck = newSoftwareVersions.getLastVersionCheck(); repositoryProxy = REMOTE_PROXY; _repo = RemoteRepository.getInstance(); synchronized (newVersionCheckLock) { newVersionCheckLock.wait(60 * 1000); } Assert.assertTrue(newSoftwareVersions.getLastVersionCheck() > previousCheck); repositoryUrl = null; _repo = RemoteRepository.getInstance(); synchronized (newVersionCheckLock) { newVersionCheckLock.wait(60 * 1000); } Assert.assertTrue(newSoftwareVersions.getCachedVersions().isEmpty()); } @Test public void testAccessDenied() throws Exception { repositoryUrl = CATALOG_SERVER_URL; repositoryProxy = null; username = "tarter"; _repo = RemoteRepository.getInstance(); final List<SoftwareVersion> remoteVersions = _repo.getVersions(); Assert.assertTrue(remoteVersions != null); Assert.assertTrue(!remoteVersions.isEmpty()); try { _repo.checkVersionDownloadable(remoteVersions.get(0)); } catch (BadRequestException e) { Assert.assertTrue(e.getMessage().contains("Verify that the supplied credentials have access to the URL")); } } @Test public void testBadCredentials() throws Exception { repositoryUrl = CATALOG_SERVER_URL; repositoryProxy = null; username = USERNAME; _repo = RemoteRepository.getInstance(); final List<SoftwareVersion> remoteVersions = _repo.getVersions(); Assert.assertTrue(remoteVersions != null); Assert.assertTrue(!remoteVersions.isEmpty()); SoftwareVersion v = remoteVersions.get(0); password = "badpassword"; // NOSONAR ("squid:S2068 Suppressing sonar violation of hard-coded password") _repo = RemoteRepository.getInstance(); try { _repo.checkVersionDownloadable(remoteVersions.get(0)); } catch (RemoteRepositoryException e) { Assert.assertTrue(e.getMessage().contains("Log in to") && e.getMessage().contains("failed")); } } @Test public void testBadVersion() throws Exception { repositoryUrl = DIRECTORY_REPO; repositoryProxy = null; username = USERNAME; password = PASSWORD; _repo = RemoteRepository.getInstance(); try { _repo.checkVersionDownloadable(new SoftwareVersion("1.0.0.0.688")); } catch (BadRequestException e) { Assert.assertTrue(e.getMessage().contains("not accessible at URL")); } } private File startBackgroundDownload(final SoftwareVersion version) { final File file = new File(DOWNLOAD_DIR + '/' + version + SOFTWARE_IMAGE_SUFFIX); final String prefix = MessageFormat.format("startBackGroundDownload(): version={0} path=\"{1}\": ", version, file); InputStream in; URL url; try { url = _repo.getImageURL(version); in = _repo.getImageInputStream(url); } catch (RemoteRepositoryException e) { System.out.println(prefix + e); return null; } System.out.println(prefix + "Starting backgroud download."); _downloader.startBackgroundDownload(prefix, file, in, url.toString(), version.toString()); return file; } private class TestSoftwareUpdate extends SoftwareUpdate { public TestSoftwareUpdate(EncryptionProvider encrypter) { setCatalogName("STORAGEOS.SOFTWARE.EN_US.PRODUCTION"); setCatalogServerHostNames(Collections.singletonList("colu-test.emc.com")); setEncryptionProvider(encrypter); } } private class TestEncryptonProvider implements EncryptionProvider { @Override public void start() { // TODO Auto-generated method stub } @Override public byte[] encrypt(String input) { try { return input.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } @Override public String getEncryptedString(String input) { byte[] data = encrypt(input); try { return new String(Base64.encodeBase64(data), "UTF-8"); } catch (UnsupportedEncodingException e) { // All JVMs must support UTF-8, this really can never happen throw new RuntimeException(e); } } @Override public String decrypt(byte[] input) { try { return new String(input, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } } public class TestCoordinatorClientExt extends CoordinatorClientExt { @SuppressWarnings("unchecked") @Override public <T extends CoordinatorSerializable> T getTargetInfo(final Class<T> clazz) throws CoordinatorClientException { if (clazz.isAssignableFrom(PropertyInfoExt.class)) { Map<String, String> repoProperties = new HashMap<String, String>(); repoProperties.put("system_update_repo", repositoryUrl); repoProperties.put("system_update_proxy", repositoryProxy); repoProperties.put("system_update_username", username); repoProperties.put("system_update_password", new String(Base64.encodeBase64(_encrypter.encrypt(password)))); return (T) new PropertyInfoExt(repoProperties); } else if (clazz.isAssignableFrom(RemoteRepositoryCache.class)) { return (T) newSoftwareVersions; } return null; } @Override public void setTargetInfo(final CoordinatorSerializable info, boolean checkClusterUpgradable) throws CoordinatorClientException { if (info == null) { return; } if (info.getClass().isAssignableFrom(RemoteRepositoryCache.class)) { synchronized (newVersionCheckLock) { newSoftwareVersions = (RemoteRepositoryCache) info; newVersionCheckLock.notifyAll(); } } } /** * The method which try and grant the non-persistent target version lock * * @return True - If node gets the lock False - Otherwise */ @Override public boolean getNewVersionLock() { return true; } /** * The method to release the non-persistent target version lock * */ @Override public void releaseNewVersionLock() { } } }