/* * 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.flink.runtime.blob; import org.apache.flink.configuration.Configuration; import org.apache.flink.configuration.HighAvailabilityOptions; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.net.URL; import static org.junit.Assert.*; /** * Unit tests for the blob cache retrying the connection to the server. */ public class BlobCacheRetriesTest { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); /** * A test where the connection fails twice and then the get operation succeeds. */ @Test public void testBlobFetchRetries() throws IOException { final Configuration config = new Configuration(); testBlobFetchRetries(config, new VoidBlobStore()); } /** * A test where the connection fails twice and then the get operation succeeds * (with high availability set). */ @Test public void testBlobFetchRetriesHa() throws IOException { final Configuration config = new Configuration(); config.setString(HighAvailabilityOptions.HA_MODE, "ZOOKEEPER"); config.setString(HighAvailabilityOptions.HA_STORAGE_PATH, temporaryFolder.getRoot().getPath()); BlobStoreService blobStoreService = null; try { blobStoreService = BlobUtils.createBlobStoreFromConfig(config); testBlobFetchRetries(config, blobStoreService); } finally { if (blobStoreService != null) { blobStoreService.closeAndCleanupAllData(); } } } /** * A test where the BlobCache must use the BlobServer and the connection * fails twice and then the get operation succeeds. * * @param config * configuration to use (the BlobCache will get some additional settings * set compared to this one) */ private void testBlobFetchRetries(final Configuration config, final BlobStore blobStore) throws IOException { final byte[] data = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; BlobServer server = null; BlobCache cache = null; try { server = new TestingFailingBlobServer(config, blobStore, 2); final InetSocketAddress serverAddress = new InetSocketAddress("localhost", server.getPort()); // upload some blob BlobClient blobClient = null; BlobKey key; try { blobClient = new BlobClient(serverAddress, config); key = blobClient.put(data); } finally { if (blobClient != null) { blobClient.close(); } } cache = new BlobCache(serverAddress, config, new VoidBlobStore()); // trigger a download - it should fail the first two times, but retry, and succeed eventually URL url = cache.getURL(key); InputStream is = url.openStream(); try { byte[] received = new byte[data.length]; assertEquals(data.length, is.read(received)); assertArrayEquals(data, received); } finally { is.close(); } } finally { if (cache != null) { cache.close(); } if (server != null) { server.close(); } } } /** * A test where the connection fails too often and eventually fails the GET request. */ @Test public void testBlobFetchWithTooManyFailures() throws IOException { final Configuration config = new Configuration(); testBlobFetchWithTooManyFailures(config, new VoidBlobStore()); } /** * A test where the connection fails twice and then the get operation succeeds * (with high availability set). */ @Test public void testBlobFetchWithTooManyFailuresHa() throws IOException { final Configuration config = new Configuration(); config.setString(HighAvailabilityOptions.HA_MODE, "ZOOKEEPER"); config.setString(HighAvailabilityOptions.HA_STORAGE_PATH, temporaryFolder.getRoot().getPath()); BlobStoreService blobStoreService = null; try { blobStoreService = BlobUtils.createBlobStoreFromConfig(config); testBlobFetchWithTooManyFailures(config, blobStoreService); } finally { if (blobStoreService != null) { blobStoreService.closeAndCleanupAllData(); } } } /** * A test where the BlobCache must use the BlobServer and the connection * fails too often which eventually fails the GET request. * * @param config * configuration to use (the BlobCache will get some additional settings * set compared to this one) */ private void testBlobFetchWithTooManyFailures(final Configuration config, final BlobStore blobStore) throws IOException { final byte[] data = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; BlobServer server = null; BlobCache cache = null; try { server = new TestingFailingBlobServer(config, blobStore, 10); final InetSocketAddress serverAddress = new InetSocketAddress("localhost", server.getPort()); // upload some blob BlobClient blobClient = null; BlobKey key; try { blobClient = new BlobClient(serverAddress, config); key = blobClient.put(data); } finally { if (blobClient != null) { blobClient.close(); } } cache = new BlobCache(serverAddress, config, new VoidBlobStore()); // trigger a download - it should fail eventually try { cache.getURL(key); fail("This should fail"); } catch (IOException e) { // as we expected } } finally { if (cache != null) { cache.close(); } if (server != null) { server.close(); } } } }