Repository: ignite
Updated Branches:
  refs/heads/master 92fae6006 -> 248c0b8e7


IGNITE-1260 S3 IP finder should have an option to use a subfolder instead of 
bucket root - Fixes #4153.

Signed-off-by: Dmitriy Pavlov <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/ea5a2be1
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/ea5a2be1
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/ea5a2be1

Branch: refs/heads/master
Commit: ea5a2be1ed44290cc2e4ef33d034c94a6f444ebb
Parents: 92fae60
Author: uday <[email protected]>
Authored: Mon Jul 16 20:48:57 2018 +0300
Committer: Dmitriy Pavlov <[email protected]>
Committed: Mon Jul 16 20:48:57 2018 +0300

----------------------------------------------------------------------
 modules/aws/pom.xml                             |    7 +
 .../tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java |   64 +-
 .../TcpDiscoveryS3IpFinderAbstractSelfTest.java |   15 +-
 ...TcpDiscoveryS3IpFinderKeyPrefixSelfTest.java |   72 ++
 .../ipfinder/s3/client/DummyObjectListing.java  |   82 ++
 .../s3/client/DummyObjectListingTest.java       |   62 +
 .../tcp/ipfinder/s3/client/DummyS3Client.java   | 1110 ++++++++++++++++++
 .../ipfinder/s3/client/DummyS3ClientTest.java   |  147 +++
 .../tcp/ipfinder/s3/client/package-info.java    |   22 +
 .../ignite/testsuites/IgniteS3TestSuite.java    |    8 +-
 10 files changed, 1573 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/pom.xml
----------------------------------------------------------------------
diff --git a/modules/aws/pom.xml b/modules/aws/pom.xml
index 6174c5b..914d864 100644
--- a/modules/aws/pom.xml
+++ b/modules/aws/pom.xml
@@ -122,6 +122,13 @@
         </dependency>
 
         <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <version>${mockito.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-beans</artifactId>
             <version>${spring.version}</version>

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
 
b/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
index 79559e8..7feed93 100644
--- 
a/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
+++ 
b/modules/aws/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinder.java
@@ -33,6 +33,7 @@ import java.util.LinkedList;
 import java.util.StringTokenizer;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
 import org.apache.ignite.internal.util.tostring.GridToStringExclude;
@@ -63,6 +64,7 @@ import org.jetbrains.annotations.Nullable;
  *      <li>Shared flag (see {@link #setShared(boolean)})</li>
  *      <li>Bucket endpoint (see {@link #setBucketEndpoint(String)})</li>
  *      <li>Server side encryption algorithm (see {@link 
#setSSEAlgorithm(String)})</li>
+ *      <li>Server side encryption algorithm (see {@link 
#setKeyPrefix(String)})</li>
  * </ul>
  * <p>
  * The finder will create S3 bucket with configured name. The bucket will 
contain entries named
@@ -102,6 +104,9 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
     /** Server side encryption algorithm */
     private @Nullable String sseAlg;
 
+    /** Sub-folder name to write node addresses. */
+    private @Nullable String keyPrefix;
+
     /** Init guard. */
     @GridToStringExclude
     private final AtomicBoolean initGuard = new AtomicBoolean();
@@ -135,16 +140,28 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
         Collection<InetSocketAddress> addrs = new LinkedList<>();
 
         try {
-            ObjectListing list = s3.listObjects(bucketName);
+            ObjectListing list;
+
+            if (keyPrefix == null) {
+                list = s3.listObjects(bucketName);
+            }
+            else {
+                list = s3.listObjects(bucketName, keyPrefix);
+            }
 
             while (true) {
                 for (S3ObjectSummary sum : list.getObjectSummaries()) {
                     String key = sum.getKey();
+                    String addr = key;
+
+                    if (keyPrefix != null) {
+                        addr = key.replaceFirst(Pattern.quote(keyPrefix), "");
+                    }
 
-                    StringTokenizer st = new StringTokenizer(key, DELIM);
+                    StringTokenizer st = new StringTokenizer(addr, DELIM);
 
                     if (st.countTokens() != 2)
-                        U.error(log, "Failed to parse S3 entry due to invalid 
format: " + key);
+                        U.error(log, "Failed to parse S3 entry due to invalid 
format: " + addr);
                     else {
                         String addrStr = st.nextToken();
                         String portStr = st.nextToken();
@@ -155,7 +172,7 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
                             port = Integer.parseInt(portStr);
                         }
                         catch (NumberFormatException e) {
-                            U.error(log, "Failed to parse port for S3 entry: " 
+ key, e);
+                            U.error(log, "Failed to parse port for S3 entry: " 
+ addr, e);
                         }
 
                         if (port != -1)
@@ -163,7 +180,7 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
                                 addrs.add(new InetSocketAddress(addrStr, 
port));
                             }
                             catch (IllegalArgumentException e) {
-                                U.error(log, "Failed to parse port for S3 
entry: " + key, e);
+                                U.error(log, "Failed to parse port for S3 
entry: " + addr, e);
                             }
                     }
                 }
@@ -230,7 +247,13 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
 
         SB sb = new SB();
 
-        sb.a(addr.getAddress().getHostAddress())
+        String addrStr = addr.getAddress().getHostAddress();
+
+        if (keyPrefix != null) {
+            sb.a(keyPrefix);
+        }
+
+        sb.a(addrStr)
             .a(DELIM)
             .a(addr.getPort());
 
@@ -307,7 +330,7 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
      *
      * @return Client instance to use to connect to AWS.
      */
-    private AmazonS3Client createAmazonS3Client() {
+    AmazonS3Client createAmazonS3Client() {
         AmazonS3Client cln = cfg != null
             ? (cred != null ? new AmazonS3Client(cred, cfg) : new 
AmazonS3Client(credProvider, cfg))
             : (cred != null ? new AmazonS3Client(cred) : new 
AmazonS3Client(credProvider));
@@ -332,9 +355,8 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
     }
 
     /**
-     * Sets bucket endpoint for IP finder.
-     * If the endpoint is not set then IP finder will go to each region to 
find a corresponding bucket.
-     * For information about possible endpoint names visit
+     * Sets bucket endpoint for IP finder. If the endpoint is not set then IP 
finder will go to each region to find a
+     * corresponding bucket. For information about possible endpoint names 
visit
      * <a 
href="http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region";>docs.aws.amazon.com</a>.
      *
      * @param bucketEndpoint Bucket endpoint, for example, 
s3.us-east-2.amazonaws.com.
@@ -348,8 +370,8 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
     }
 
     /**
-     * Sets server-side encryption algorithm for Amazon S3-managed encryption 
keys.
-     * For information about possible S3-managed encryption keys visit
+     * Sets server-side encryption algorithm for Amazon S3-managed encryption 
keys. For information about possible
+     * S3-managed encryption keys visit
      * <a 
href="http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingServerSideEncryption.html";>docs.aws.amazon.com</a>.
      *
      * @param sseAlg Server-side encryption algorithm, for example, AES256 or 
SSES3.
@@ -407,6 +429,22 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
         return this;
     }
 
+    /**
+     * This can be thought of as the sub-folder within the bucket that will 
hold the node addresses.
+     * <p>
+     * For details visit
+     * <a 
href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ListingKeysHierarchy.html"/>
+     *
+     * @param keyPrefix AWS credentials provider.
+     * @return {@code this} for chaining.
+     */
+    @IgniteSpiConfiguration(optional = true)
+    public TcpDiscoveryS3IpFinder setKeyPrefix(String keyPrefix) {
+        this.keyPrefix = keyPrefix;
+
+        return this;
+    }
+
     /** {@inheritDoc} */
     @Override public TcpDiscoveryS3IpFinder setShared(boolean shared) {
         super.setShared(shared);
@@ -418,4 +456,4 @@ public class TcpDiscoveryS3IpFinder extends 
TcpDiscoveryIpFinderAdapter {
     @Override public String toString() {
         return S.toString(TcpDiscoveryS3IpFinder.class, this, "super", 
super.toString());
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
index af4a47a..08503fd 100644
--- 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
+++ 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderAbstractSelfTest.java
@@ -40,6 +40,9 @@ abstract class TcpDiscoveryS3IpFinderAbstractSelfTest
     /** Server-side encryption algorithm for Amazon S3-managed encryption 
keys. */
     protected @Nullable String SSEAlgorithm;
 
+    /** Key prefix of the address. */
+    protected @Nullable String keyPrefix;
+
     /**
      * Constructor.
      *
@@ -60,6 +63,7 @@ abstract class TcpDiscoveryS3IpFinderAbstractSelfTest
         setBucketEndpoint(finder);
         setBucketName(finder);
         setSSEAlgorithm(finder);
+        setKeyPrefix(finder);
 
         for (int i = 0; i < 5; i++) {
             Collection<InetSocketAddress> addrs = 
finder.getRegisteredAddresses();
@@ -100,7 +104,6 @@ abstract class TcpDiscoveryS3IpFinderAbstractSelfTest
 
     /**
      * Set server-side encryption algorithm for Amazon S3-managed encryption 
keys into the provided {@code finder}.
-     *
      * @param finder finder encryption algorithm to set into.
      */
     private void setSSEAlgorithm(TcpDiscoveryS3IpFinder finder) {
@@ -116,6 +119,14 @@ abstract class TcpDiscoveryS3IpFinderAbstractSelfTest
     }
 
     /**
+     * Set the ip address key prefix into the provided {@code finder}.
+     * @param finder finder encryption algorithm to set into.
+     */
+    protected void setKeyPrefix(TcpDiscoveryS3IpFinder finder) {
+        finder.setKeyPrefix(keyPrefix);
+    }
+
+    /**
      * Gets Bucket name.
      * Bucket name should be unique for the host to parallel test run on one 
bucket.
      * Please note that the final bucket name should not exceed 63 chars.
@@ -135,4 +146,4 @@ abstract class TcpDiscoveryS3IpFinderAbstractSelfTest
 
         return bucketName;
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderKeyPrefixSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderKeyPrefixSelfTest.java
 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderKeyPrefixSelfTest.java
new file mode 100644
index 0000000..839affa
--- /dev/null
+++ 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/TcpDiscoveryS3IpFinderKeyPrefixSelfTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.ignite.spi.discovery.tcp.ipfinder.s3;
+
+import com.amazonaws.auth.BasicAWSCredentials;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.s3.client.DummyS3Client;
+import org.mockito.Mockito;
+
+/**
+ * TcpDiscoveryS3IpFinder tests key prefix for IP finder. For information 
about key prefix visit:
+ * <a 
href="https://docs.aws.amazon.com/AmazonS3/latest/dev/ListingKeysHierarchy.html"/>.
+ */
+public class TcpDiscoveryS3IpFinderKeyPrefixSelfTest extends 
TcpDiscoveryS3IpFinderAbstractSelfTest {
+    /**
+     * Constructor.
+     *
+     * @throws Exception If any error occurs.
+     */
+    public TcpDiscoveryS3IpFinderKeyPrefixSelfTest() throws Exception {
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void setAwsCredentials(TcpDiscoveryS3IpFinder finder) {
+        finder.setAwsCredentials(new BasicAWSCredentials("dummy", "dummy"));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void setKeyPrefix(TcpDiscoveryS3IpFinder finder) {
+        finder.setKeyPrefix("/test/key/prefix");
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void setBucketName(TcpDiscoveryS3IpFinder finder) {
+        finder.setBucketName(getBucketName());
+    }
+
+    /** {@inheritDoc} */
+    @Override protected TcpDiscoveryS3IpFinder ipFinder() throws Exception {
+        TcpDiscoveryS3IpFinder ipFinder = Mockito.spy(new 
TcpDiscoveryS3IpFinder());
+        Mockito.doReturn(new 
DummyS3Client()).when(ipFinder).createAmazonS3Client();
+
+        setAwsCredentials(ipFinder);
+        setBucketName(ipFinder);
+        setKeyPrefix(ipFinder);
+
+        return ipFinder;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void testIpFinder() throws Exception {
+        injectLogger(finder);
+
+        assert finder.isShared() : "Ip finder should be shared by default.";
+
+        super.testIpFinder();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListing.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListing.java
 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListing.java
new file mode 100644
index 0000000..e75f166
--- /dev/null
+++ 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListing.java
@@ -0,0 +1,82 @@
+/*
+ * 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.ignite.spi.discovery.tcp.ipfinder.s3.client;
+
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Class to simulate the functionality of {@link ObjectListing}.
+ */
+public class DummyObjectListing extends ObjectListing {
+
+    /** Iterator over the S3 object summaries. */
+    private Iterator<S3ObjectSummary> objectSummariesIter;
+
+    /**
+     * Constructor
+     *
+     * @param objectSummaries Iterator over the S3 object summaries.
+     */
+    private DummyObjectListing(Iterator<S3ObjectSummary> objectSummaries) {
+        this.objectSummariesIter = objectSummaries;
+    }
+
+    /**
+     * Creates an instance of {@link DummyObjectListing}. The object summaries 
are created using the given  bucket name
+     * and object keys.
+     *
+     * @param bucketName AWS Bucket name.
+     * @param keys The keys in the bucket.
+     * @return Instance of this object.
+     */
+    static DummyObjectListing of(String bucketName, Set<String> keys) {
+        List<S3ObjectSummary> objectSummaries = keys.stream().map(key -> {
+            S3ObjectSummary s3ObjectSummary = new S3ObjectSummary();
+            s3ObjectSummary.setBucketName(bucketName);
+            s3ObjectSummary.setKey(key);
+            return s3ObjectSummary;
+        }).collect(Collectors.toList());
+
+        return new DummyObjectListing(objectSummaries.iterator());
+    }
+
+    /** {@inheritDoc} */
+    @Override public List<S3ObjectSummary> getObjectSummaries() {
+        if (objectSummariesIter.hasNext()) {
+            S3ObjectSummary s3ObjectSummary = objectSummariesIter.next();
+            List<S3ObjectSummary> list = new LinkedList<>();
+            list.add(s3ObjectSummary);
+            return list;
+        }
+        else {
+            return Collections.emptyList();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isTruncated() {
+        return objectSummariesIter.hasNext();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListingTest.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListingTest.java
 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListingTest.java
new file mode 100644
index 0000000..98fce00
--- /dev/null
+++ 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyObjectListingTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.ignite.spi.discovery.tcp.ipfinder.s3.client;
+
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * Class to test {@link DummyObjectListing}.
+ */
+public class DummyObjectListingTest extends GridCommonAbstractTest {
+
+    /**
+     * Test cases for various object listing functions for S3 bucket.
+     */
+    public void testDummyObjectListing() {
+        Set<String> fakeKeyPrefixSet = new HashSet<>();
+        fakeKeyPrefixSet.add("/test/path/val");
+        fakeKeyPrefixSet.add("/test/val/test/path");
+        fakeKeyPrefixSet.add("/test/test/path/val");
+
+        ObjectListing listing = DummyObjectListing.of("bucket", 
fakeKeyPrefixSet);
+        List<S3ObjectSummary> summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' contains keys", summaries.isEmpty());
+        assertTrue("'testBucket' contains more keys to fetch", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' contains keys", summaries.isEmpty());
+        assertTrue("'testBucket' contains more keys to fetch", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' contains keys", summaries.isEmpty());
+        assertFalse("'testBucket' does not contain anymore keys", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        listing = DummyObjectListing.of("bucket", new HashSet<>());
+        summaries = listing.getObjectSummaries();
+        assertTrue("'testBucket' does not contains keys", summaries.isEmpty());
+        assertFalse("'testBucket' does not contain anymore keys", 
listing.isTruncated());
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3Client.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3Client.java
 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3Client.java
new file mode 100644
index 0000000..4bdee5e
--- /dev/null
+++ 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3Client.java
@@ -0,0 +1,1110 @@
+/*
+ * 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.ignite.spi.discovery.tcp.ipfinder.s3.client;
+
+import com.amazonaws.AmazonWebServiceRequest;
+import com.amazonaws.HttpMethod;
+import com.amazonaws.SdkClientException;
+import com.amazonaws.regions.Region;
+import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.S3ClientOptions;
+import com.amazonaws.services.s3.S3ResponseMetadata;
+import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
+import com.amazonaws.services.s3.model.AccessControlList;
+import com.amazonaws.services.s3.model.AmazonS3Exception;
+import com.amazonaws.services.s3.model.Bucket;
+import com.amazonaws.services.s3.model.BucketAccelerateConfiguration;
+import com.amazonaws.services.s3.model.BucketCrossOriginConfiguration;
+import com.amazonaws.services.s3.model.BucketLifecycleConfiguration;
+import com.amazonaws.services.s3.model.BucketLoggingConfiguration;
+import com.amazonaws.services.s3.model.BucketNotificationConfiguration;
+import com.amazonaws.services.s3.model.BucketPolicy;
+import com.amazonaws.services.s3.model.BucketReplicationConfiguration;
+import com.amazonaws.services.s3.model.BucketTaggingConfiguration;
+import com.amazonaws.services.s3.model.BucketVersioningConfiguration;
+import com.amazonaws.services.s3.model.BucketWebsiteConfiguration;
+import com.amazonaws.services.s3.model.CannedAccessControlList;
+import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest;
+import com.amazonaws.services.s3.model.CompleteMultipartUploadResult;
+import com.amazonaws.services.s3.model.CopyObjectRequest;
+import com.amazonaws.services.s3.model.CopyObjectResult;
+import com.amazonaws.services.s3.model.CopyPartRequest;
+import com.amazonaws.services.s3.model.CopyPartResult;
+import com.amazonaws.services.s3.model.CreateBucketRequest;
+import 
com.amazonaws.services.s3.model.DeleteBucketAnalyticsConfigurationRequest;
+import 
com.amazonaws.services.s3.model.DeleteBucketAnalyticsConfigurationResult;
+import 
com.amazonaws.services.s3.model.DeleteBucketCrossOriginConfigurationRequest;
+import 
com.amazonaws.services.s3.model.DeleteBucketInventoryConfigurationRequest;
+import 
com.amazonaws.services.s3.model.DeleteBucketInventoryConfigurationResult;
+import 
com.amazonaws.services.s3.model.DeleteBucketLifecycleConfigurationRequest;
+import com.amazonaws.services.s3.model.DeleteBucketMetricsConfigurationRequest;
+import com.amazonaws.services.s3.model.DeleteBucketMetricsConfigurationResult;
+import com.amazonaws.services.s3.model.DeleteBucketPolicyRequest;
+import 
com.amazonaws.services.s3.model.DeleteBucketReplicationConfigurationRequest;
+import com.amazonaws.services.s3.model.DeleteBucketRequest;
+import com.amazonaws.services.s3.model.DeleteBucketTaggingConfigurationRequest;
+import com.amazonaws.services.s3.model.DeleteBucketWebsiteConfigurationRequest;
+import com.amazonaws.services.s3.model.DeleteObjectRequest;
+import com.amazonaws.services.s3.model.DeleteObjectTaggingRequest;
+import com.amazonaws.services.s3.model.DeleteObjectTaggingResult;
+import com.amazonaws.services.s3.model.DeleteObjectsRequest;
+import com.amazonaws.services.s3.model.DeleteObjectsResult;
+import com.amazonaws.services.s3.model.DeleteVersionRequest;
+import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
+import com.amazonaws.services.s3.model.GetBucketAccelerateConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketAclRequest;
+import com.amazonaws.services.s3.model.GetBucketAnalyticsConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketAnalyticsConfigurationResult;
+import 
com.amazonaws.services.s3.model.GetBucketCrossOriginConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketInventoryConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketInventoryConfigurationResult;
+import com.amazonaws.services.s3.model.GetBucketLifecycleConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketLocationRequest;
+import com.amazonaws.services.s3.model.GetBucketLoggingConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketMetricsConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketMetricsConfigurationResult;
+import 
com.amazonaws.services.s3.model.GetBucketNotificationConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketPolicyRequest;
+import 
com.amazonaws.services.s3.model.GetBucketReplicationConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketTaggingConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketVersioningConfigurationRequest;
+import com.amazonaws.services.s3.model.GetBucketWebsiteConfigurationRequest;
+import com.amazonaws.services.s3.model.GetObjectAclRequest;
+import com.amazonaws.services.s3.model.GetObjectMetadataRequest;
+import com.amazonaws.services.s3.model.GetObjectRequest;
+import com.amazonaws.services.s3.model.GetObjectTaggingRequest;
+import com.amazonaws.services.s3.model.GetObjectTaggingResult;
+import com.amazonaws.services.s3.model.GetS3AccountOwnerRequest;
+import com.amazonaws.services.s3.model.HeadBucketRequest;
+import com.amazonaws.services.s3.model.HeadBucketResult;
+import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest;
+import com.amazonaws.services.s3.model.InitiateMultipartUploadResult;
+import 
com.amazonaws.services.s3.model.ListBucketAnalyticsConfigurationsRequest;
+import com.amazonaws.services.s3.model.ListBucketAnalyticsConfigurationsResult;
+import 
com.amazonaws.services.s3.model.ListBucketInventoryConfigurationsRequest;
+import com.amazonaws.services.s3.model.ListBucketInventoryConfigurationsResult;
+import com.amazonaws.services.s3.model.ListBucketMetricsConfigurationsRequest;
+import com.amazonaws.services.s3.model.ListBucketMetricsConfigurationsResult;
+import com.amazonaws.services.s3.model.ListBucketsRequest;
+import com.amazonaws.services.s3.model.ListMultipartUploadsRequest;
+import com.amazonaws.services.s3.model.ListNextBatchOfObjectsRequest;
+import com.amazonaws.services.s3.model.ListNextBatchOfVersionsRequest;
+import com.amazonaws.services.s3.model.ListObjectsRequest;
+import com.amazonaws.services.s3.model.ListObjectsV2Request;
+import com.amazonaws.services.s3.model.ListObjectsV2Result;
+import com.amazonaws.services.s3.model.ListPartsRequest;
+import com.amazonaws.services.s3.model.ListVersionsRequest;
+import com.amazonaws.services.s3.model.MultipartUploadListing;
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.ObjectMetadata;
+import com.amazonaws.services.s3.model.Owner;
+import com.amazonaws.services.s3.model.PartListing;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+import com.amazonaws.services.s3.model.PutObjectResult;
+import com.amazonaws.services.s3.model.RestoreObjectRequest;
+import com.amazonaws.services.s3.model.S3Object;
+import com.amazonaws.services.s3.model.SetBucketAccelerateConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketAclRequest;
+import com.amazonaws.services.s3.model.SetBucketAnalyticsConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketAnalyticsConfigurationResult;
+import 
com.amazonaws.services.s3.model.SetBucketCrossOriginConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketInventoryConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketInventoryConfigurationResult;
+import com.amazonaws.services.s3.model.SetBucketLifecycleConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketLoggingConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketMetricsConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketMetricsConfigurationResult;
+import 
com.amazonaws.services.s3.model.SetBucketNotificationConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketPolicyRequest;
+import 
com.amazonaws.services.s3.model.SetBucketReplicationConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketTaggingConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketVersioningConfigurationRequest;
+import com.amazonaws.services.s3.model.SetBucketWebsiteConfigurationRequest;
+import com.amazonaws.services.s3.model.SetObjectAclRequest;
+import com.amazonaws.services.s3.model.SetObjectTaggingRequest;
+import com.amazonaws.services.s3.model.SetObjectTaggingResult;
+import com.amazonaws.services.s3.model.StorageClass;
+import com.amazonaws.services.s3.model.UploadPartRequest;
+import com.amazonaws.services.s3.model.UploadPartResult;
+import com.amazonaws.services.s3.model.VersionListing;
+import com.amazonaws.services.s3.model.analytics.AnalyticsConfiguration;
+import com.amazonaws.services.s3.model.inventory.InventoryConfiguration;
+import com.amazonaws.services.s3.model.metrics.MetricsConfiguration;
+import com.amazonaws.services.s3.waiters.AmazonS3Waiters;
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Class to simulate the functionality of {@link AmazonS3Client}.
+ */
+public final class DummyS3Client extends AmazonS3Client {
+
+    /** Map of Bucket names as keys and the keys as set of values. */
+    private final Map<String, Set<String>> objectMap;
+
+    /**
+     * Constructor.
+     */
+    public DummyS3Client() {
+        this.objectMap = new HashMap<>();
+    }
+
+    /**
+     * Constructor to add an object map with fake data.
+     */
+    public DummyS3Client(Map<String, Set<String>> objectMap) {
+        this.objectMap = Objects.requireNonNull(objectMap, "Object map cannot 
be null");
+    }
+
+    /** Empty Method. */
+    @Override public void setEndpoint(String endpoint) {
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setRegion(Region region) throws 
IllegalArgumentException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setS3ClientOptions(S3ClientOptions clientOptions) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void changeObjectStorageClass(String bucketName, String 
key,
+        StorageClass newStorageClass) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setObjectRedirectLocation(String bucketName, String 
key,
+        String newRedirectLocation) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public ObjectListing listObjects(String bucketName) throws 
SdkClientException {
+        checkBucketExists(bucketName);
+        return DummyObjectListing.of(bucketName, objectMap.get(bucketName));
+    }
+
+    /** {@inheritDoc} */
+    @Override public ObjectListing listObjects(String bucketName, String 
prefix) throws SdkClientException {
+        checkBucketExists(bucketName);
+        Set<String> keys = objectMap.get(bucketName).stream()
+            .filter(key -> key.startsWith(prefix)).collect(Collectors.toSet());
+        return DummyObjectListing.of(bucketName, keys);
+    }
+
+    /** Unsupported Operation. */
+    @Override public ObjectListing listObjects(ListObjectsRequest 
listObjectsRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ListObjectsV2Result listObjectsV2(String bucketName) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ListObjectsV2Result listObjectsV2(String bucketName,
+        String prefix) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ListObjectsV2Result listObjectsV2(
+        ListObjectsV2Request listObjectsV2Request) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public ObjectListing listNextBatchOfObjects(
+        ObjectListing previousObjectListing) throws SdkClientException {
+        return previousObjectListing;
+    }
+
+    /** Unsupported Operation. */
+    @Override public ObjectListing listNextBatchOfObjects(
+        ListNextBatchOfObjectsRequest listNextBatchOfObjectsRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public VersionListing listVersions(String bucketName,
+        String prefix) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public VersionListing listNextBatchOfVersions(
+        VersionListing previousVersionListing) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public VersionListing listNextBatchOfVersions(
+        ListNextBatchOfVersionsRequest listNextBatchOfVersionsRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public VersionListing listVersions(String bucketName, String 
prefix, String keyMarker,
+        String versionIdMarker,
+        String delimiter, Integer maxResults) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public VersionListing listVersions(
+        ListVersionsRequest listVersionsRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public Owner getS3AccountOwner() throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public Owner getS3AccountOwner(
+        GetS3AccountOwnerRequest getS3AccountOwnerRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean doesBucketExist(String bucketName) throws 
SdkClientException {
+        return objectMap.containsKey(bucketName);
+    }
+
+    /** Unsupported Operation. */
+    @Override public HeadBucketResult headBucket(
+        HeadBucketRequest headBucketRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public List<Bucket> listBuckets() throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public List<Bucket> listBuckets(
+        ListBucketsRequest listBucketsRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public String getBucketLocation(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public String getBucketLocation(
+        GetBucketLocationRequest getBucketLocationRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public Bucket createBucket(
+        CreateBucketRequest createBucketRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Bucket createBucket(String bucketName) throws 
SdkClientException {
+        if (doesBucketExist(bucketName)) {
+            throw new AmazonS3Exception("The specified bucket already exist");
+        }
+        else {
+            objectMap.put(bucketName, new HashSet<>());
+            return new Bucket();
+        }
+    }
+
+    /** Unsupported Operation. */
+    @Override public Bucket createBucket(String bucketName,
+        com.amazonaws.services.s3.model.Region region) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public Bucket createBucket(String bucketName, String region) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public AccessControlList getObjectAcl(String bucketName,
+        String key) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public AccessControlList getObjectAcl(String bucketName, String 
key,
+        String versionId) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public AccessControlList getObjectAcl(
+        GetObjectAclRequest getObjectAclRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setObjectAcl(String bucketName, String key,
+        AccessControlList acl) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setObjectAcl(String bucketName, String key,
+        CannedAccessControlList acl) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setObjectAcl(String bucketName, String key, String 
versionId,
+        AccessControlList acl) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setObjectAcl(String bucketName, String key, String 
versionId,
+        CannedAccessControlList acl) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setObjectAcl(
+        SetObjectAclRequest setObjectAclRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public AccessControlList getBucketAcl(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketAcl(
+        SetBucketAclRequest setBucketAclRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public AccessControlList getBucketAcl(
+        GetBucketAclRequest getBucketAclRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketAcl(String bucketName,
+        AccessControlList acl) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketAcl(String bucketName,
+        CannedAccessControlList acl) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ObjectMetadata getObjectMetadata(String bucketName,
+        String key) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ObjectMetadata getObjectMetadata(
+        GetObjectMetadataRequest getObjectMetadataRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public S3Object getObject(String bucketName, String key) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public S3Object getObject(GetObjectRequest getObjectRequest) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ObjectMetadata getObject(GetObjectRequest 
getObjectRequest,
+        File destinationFile) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public String getObjectAsString(String bucketName, String key) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public GetObjectTaggingResult 
getObjectTagging(GetObjectTaggingRequest getObjectTaggingRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public SetObjectTaggingResult 
setObjectTagging(SetObjectTaggingRequest setObjectTaggingRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteObjectTaggingResult deleteObjectTagging(
+        DeleteObjectTaggingRequest deleteObjectTaggingRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucket(
+        DeleteBucketRequest deleteBucketRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucket(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public PutObjectResult putObject(
+        PutObjectRequest putObjectRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public PutObjectResult putObject(String bucketName, String key,
+        File file) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public PutObjectResult putObject(String bucketName, String key, 
InputStream input,
+        ObjectMetadata metadata) throws SdkClientException {
+        checkBucketExists(bucketName);
+        Set<String> keys = objectMap.get(bucketName);
+        keys.add(key);
+        return new PutObjectResult();
+    }
+
+    /** Unsupported Operation. */
+    @Override public PutObjectResult putObject(String bucketName, String key,
+        String content) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public CopyObjectResult copyObject(String sourceBucketName, 
String sourceKey,
+        String destinationBucketName,
+        String destinationKey) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public CopyObjectResult copyObject(
+        CopyObjectRequest copyObjectRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public CopyPartResult copyPart(CopyPartRequest copyPartRequest) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void deleteObject(String bucketName, String key) throws 
SdkClientException {
+        checkBucketExists(bucketName);
+        Set<String> keys = objectMap.get(bucketName);
+        Set<String> keysToDelete = keys.stream().filter(k -> 
k.contains(key)).collect(Collectors.toSet());
+        keys.removeAll(keysToDelete);
+        objectMap.put(bucketName, keys);
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteObject(DeleteObjectRequest 
deleteObjectRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteObjectsResult deleteObjects(DeleteObjectsRequest 
deleteObjectsRequest)
+        throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteVersion(String bucketName, String key,
+        String versionId) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteVersion(
+        DeleteVersionRequest deleteVersionRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketLoggingConfiguration getBucketLoggingConfiguration(
+        String bucketName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketLoggingConfiguration getBucketLoggingConfiguration(
+        GetBucketLoggingConfigurationRequest 
getBucketLoggingConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketLoggingConfiguration(
+        SetBucketLoggingConfigurationRequest 
setBucketLoggingConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketVersioningConfiguration 
getBucketVersioningConfiguration(
+        String bucketName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketVersioningConfiguration 
getBucketVersioningConfiguration(
+        GetBucketVersioningConfigurationRequest 
getBucketVersioningConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketVersioningConfiguration(
+        SetBucketVersioningConfigurationRequest 
setBucketVersioningConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketLifecycleConfiguration 
getBucketLifecycleConfiguration(String bucketName) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketLifecycleConfiguration 
getBucketLifecycleConfiguration(
+        GetBucketLifecycleConfigurationRequest 
getBucketLifecycleConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketLifecycleConfiguration(String bucketName,
+        BucketLifecycleConfiguration bucketLifecycleConfiguration) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketLifecycleConfiguration(
+        SetBucketLifecycleConfigurationRequest 
setBucketLifecycleConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketLifecycleConfiguration(String 
bucketName) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketLifecycleConfiguration(
+        DeleteBucketLifecycleConfigurationRequest 
deleteBucketLifecycleConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketCrossOriginConfiguration 
getBucketCrossOriginConfiguration(String bucketName) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketCrossOriginConfiguration 
getBucketCrossOriginConfiguration(
+        GetBucketCrossOriginConfigurationRequest 
getBucketCrossOriginConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketCrossOriginConfiguration(String bucketName,
+        BucketCrossOriginConfiguration bucketCrossOriginConfiguration) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketCrossOriginConfiguration(
+        SetBucketCrossOriginConfigurationRequest 
setBucketCrossOriginConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketCrossOriginConfiguration(String 
bucketName) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketCrossOriginConfiguration(
+        DeleteBucketCrossOriginConfigurationRequest 
deleteBucketCrossOriginConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketTaggingConfiguration 
getBucketTaggingConfiguration(String bucketName) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketTaggingConfiguration getBucketTaggingConfiguration(
+        GetBucketTaggingConfigurationRequest 
getBucketTaggingConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketTaggingConfiguration(String bucketName,
+        BucketTaggingConfiguration bucketTaggingConfiguration) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketTaggingConfiguration(
+        SetBucketTaggingConfigurationRequest 
setBucketTaggingConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketTaggingConfiguration(String bucketName) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketTaggingConfiguration(
+        DeleteBucketTaggingConfigurationRequest 
deleteBucketTaggingConfigurationRequest) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketNotificationConfiguration 
getBucketNotificationConfiguration(
+        String bucketName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketNotificationConfiguration 
getBucketNotificationConfiguration(
+        GetBucketNotificationConfigurationRequest 
getBucketNotificationConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketNotificationConfiguration(
+        SetBucketNotificationConfigurationRequest 
setBucketNotificationConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketNotificationConfiguration(String bucketName,
+        BucketNotificationConfiguration bucketNotificationConfiguration) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketWebsiteConfiguration getBucketWebsiteConfiguration(
+        String bucketName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketWebsiteConfiguration getBucketWebsiteConfiguration(
+        GetBucketWebsiteConfigurationRequest 
getBucketWebsiteConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketWebsiteConfiguration(String bucketName,
+        BucketWebsiteConfiguration configuration) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketWebsiteConfiguration(
+        SetBucketWebsiteConfigurationRequest 
setBucketWebsiteConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketWebsiteConfiguration(String bucketName) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketWebsiteConfiguration(
+        DeleteBucketWebsiteConfigurationRequest 
deleteBucketWebsiteConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketPolicy getBucketPolicy(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketPolicy getBucketPolicy(
+        GetBucketPolicyRequest getBucketPolicyRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketPolicy(String bucketName,
+        String policyText) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketPolicy(
+        SetBucketPolicyRequest setBucketPolicyRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketPolicy(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketPolicy(
+        DeleteBucketPolicyRequest deleteBucketPolicyRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public URL generatePresignedUrl(String bucketName, String key,
+        Date expiration) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public URL generatePresignedUrl(String bucketName, String key, 
Date expiration,
+        HttpMethod method) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public URL generatePresignedUrl(
+        GeneratePresignedUrlRequest generatePresignedUrlRequest) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public InitiateMultipartUploadResult initiateMultipartUpload(
+        InitiateMultipartUploadRequest request) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public UploadPartResult uploadPart(UploadPartRequest request) 
throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public PartListing listParts(ListPartsRequest request) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void abortMultipartUpload(
+        AbortMultipartUploadRequest request) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public CompleteMultipartUploadResult completeMultipartUpload(
+        CompleteMultipartUploadRequest request) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public MultipartUploadListing listMultipartUploads(
+        ListMultipartUploadsRequest request) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public S3ResponseMetadata 
getCachedResponseMetadata(AmazonWebServiceRequest request) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void restoreObject(RestoreObjectRequest request) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void restoreObject(String bucketName, String key, int 
expirationInDays) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void enableRequesterPays(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void disableRequesterPays(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public boolean isRequesterPaysEnabled(String bucketName) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketReplicationConfiguration(String bucketName,
+        BucketReplicationConfiguration configuration) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketReplicationConfiguration(
+        SetBucketReplicationConfigurationRequest 
setBucketReplicationConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketReplicationConfiguration 
getBucketReplicationConfiguration(
+        String bucketName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketReplicationConfiguration 
getBucketReplicationConfiguration(
+        GetBucketReplicationConfigurationRequest 
getBucketReplicationConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketReplicationConfiguration(
+        String bucketName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void deleteBucketReplicationConfiguration(
+        DeleteBucketReplicationConfigurationRequest request) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public boolean doesObjectExist(String bucketName,
+        String objectName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketAccelerateConfiguration 
getBucketAccelerateConfiguration(
+        String bucketName) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public BucketAccelerateConfiguration 
getBucketAccelerateConfiguration(
+        GetBucketAccelerateConfigurationRequest 
getBucketAccelerateConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketAccelerateConfiguration(String bucketName,
+        BucketAccelerateConfiguration accelerateConfiguration) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public void setBucketAccelerateConfiguration(
+        SetBucketAccelerateConfigurationRequest 
setBucketAccelerateConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteBucketMetricsConfigurationResult 
deleteBucketMetricsConfiguration(String bucketName,
+        String id) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteBucketMetricsConfigurationResult 
deleteBucketMetricsConfiguration(
+        DeleteBucketMetricsConfigurationRequest 
deleteBucketMetricsConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public GetBucketMetricsConfigurationResult 
getBucketMetricsConfiguration(String bucketName,
+        String id) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public GetBucketMetricsConfigurationResult 
getBucketMetricsConfiguration(
+        GetBucketMetricsConfigurationRequest 
getBucketMetricsConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public SetBucketMetricsConfigurationResult 
setBucketMetricsConfiguration(String bucketName,
+        MetricsConfiguration metricsConfiguration) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public SetBucketMetricsConfigurationResult 
setBucketMetricsConfiguration(
+        SetBucketMetricsConfigurationRequest 
setBucketMetricsConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ListBucketMetricsConfigurationsResult 
listBucketMetricsConfigurations(
+        ListBucketMetricsConfigurationsRequest 
listBucketMetricsConfigurationsRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteBucketAnalyticsConfigurationResult 
deleteBucketAnalyticsConfiguration(String bucketName,
+        String id) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteBucketAnalyticsConfigurationResult 
deleteBucketAnalyticsConfiguration(
+        DeleteBucketAnalyticsConfigurationRequest 
deleteBucketAnalyticsConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public GetBucketAnalyticsConfigurationResult 
getBucketAnalyticsConfiguration(String bucketName,
+        String id) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public GetBucketAnalyticsConfigurationResult 
getBucketAnalyticsConfiguration(
+        GetBucketAnalyticsConfigurationRequest 
getBucketAnalyticsConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public SetBucketAnalyticsConfigurationResult 
setBucketAnalyticsConfiguration(String bucketName,
+        AnalyticsConfiguration analyticsConfiguration) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public SetBucketAnalyticsConfigurationResult 
setBucketAnalyticsConfiguration(
+        SetBucketAnalyticsConfigurationRequest 
setBucketAnalyticsConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ListBucketAnalyticsConfigurationsResult 
listBucketAnalyticsConfigurations(
+        ListBucketAnalyticsConfigurationsRequest 
listBucketAnalyticsConfigurationsRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteBucketInventoryConfigurationResult 
deleteBucketInventoryConfiguration(String bucketName,
+        String id) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public DeleteBucketInventoryConfigurationResult 
deleteBucketInventoryConfiguration(
+        DeleteBucketInventoryConfigurationRequest 
deleteBucketInventoryConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public GetBucketInventoryConfigurationResult 
getBucketInventoryConfiguration(String bucketName,
+        String id) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public GetBucketInventoryConfigurationResult 
getBucketInventoryConfiguration(
+        GetBucketInventoryConfigurationRequest 
getBucketInventoryConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public SetBucketInventoryConfigurationResult 
setBucketInventoryConfiguration(String bucketName,
+        InventoryConfiguration inventoryConfiguration) throws 
SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public SetBucketInventoryConfigurationResult 
setBucketInventoryConfiguration(
+        SetBucketInventoryConfigurationRequest 
setBucketInventoryConfigurationRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public ListBucketInventoryConfigurationsResult 
listBucketInventoryConfigurations(
+        ListBucketInventoryConfigurationsRequest 
listBucketInventoryConfigurationsRequest) throws SdkClientException {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public com.amazonaws.services.s3.model.Region getRegion() {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public String getRegionName() {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public URL getUrl(String bucketName, String key) {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /** Unsupported Operation. */
+    @Override public AmazonS3Waiters waiters() {
+        throw new UnsupportedOperationException("Operation not supported");
+    }
+
+    /**
+     * Check if a bucket exists.
+     *
+     * @param bucketName bucket name to check.
+     * @throws AmazonS3Exception If the specified bucket does not exist.
+     */
+    private void checkBucketExists(String bucketName) {
+        if (!doesBucketExist(bucketName)) {
+            throw new AmazonS3Exception("The specified bucket does not exist");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3ClientTest.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3ClientTest.java
 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3ClientTest.java
new file mode 100644
index 0000000..0138ac1
--- /dev/null
+++ 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/DummyS3ClientTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.ignite.spi.discovery.tcp.ipfinder.s3.client;
+
+import com.amazonaws.services.s3.model.AmazonS3Exception;
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ * Class to test {@link DummyS3Client}.
+ */
+public class DummyS3ClientTest extends GridCommonAbstractTest {
+
+    /** Instance of {@link DummyS3Client} to be used for tests. */
+    private DummyS3Client s3;
+
+    /** Holds fake key prefixes. */
+    private Set<String> fakeKeyPrefixSet;
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() {
+        fakeKeyPrefixSet = new HashSet<>();
+        fakeKeyPrefixSet.add("/test/path/val");
+        fakeKeyPrefixSet.add("/test/val/test/path");
+        fakeKeyPrefixSet.add("/test/test/path/val");
+
+        Map<String, Set<String>> fakeObjectMap = new HashMap<>();
+        fakeObjectMap.put("testBucket", fakeKeyPrefixSet);
+
+        s3 = new DummyS3Client(fakeObjectMap);
+    }
+
+    /**
+     * Test cases to check the 'doesBucketExist' method.
+     */
+    public void testDoesBucketExist() {
+        assertTrue("The bucket 'testBucket' should exist", 
s3.doesBucketExist("testBucket"));
+        assertFalse("The bucket 'nonExistentBucket' should not exist", 
s3.doesBucketExist("nonExistentBucket"));
+    }
+
+    /**
+     * Test cases for various object listing functions for S3 bucket.
+     */
+    public void testListObjects() {
+        ObjectListing listing = s3.listObjects("testBucket");
+        List<S3ObjectSummary> summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' contains keys", summaries.isEmpty());
+        assertTrue("'testBucket' contains more keys to fetch", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        listing = s3.listNextBatchOfObjects(listing);
+        summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' contains keys", summaries.isEmpty());
+        assertTrue("'testBucket' contains more keys to fetch", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        listing = s3.listNextBatchOfObjects(listing);
+        summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' contains keys", summaries.isEmpty());
+        assertFalse("'testBucket' does not contain anymore keys", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        try {
+            s3.listObjects("nonExistentBucket");
+        }
+        catch (AmazonS3Exception e) {
+            assertTrue(e.getMessage().contains("The specified bucket does not 
exist"));
+        }
+    }
+
+    /**
+     * Test cases for various object listing functions for S3 bucket and key 
prefix.
+     */
+    public void testListObjectsWithAPrefix() {
+        ObjectListing listing = s3.listObjects("testBucket", "/test");
+        List<S3ObjectSummary> summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' must contain key with prefix '/test'", 
summaries.isEmpty());
+        assertTrue("'testBucket' contains more keys with prefix '/test'", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        listing = s3.listNextBatchOfObjects(listing);
+        summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' must contain key with prefix '/test'", 
summaries.isEmpty());
+        assertTrue("'testBucket' contains more keys with prefix '/test'", 
listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        listing = s3.listNextBatchOfObjects(listing);
+        summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' must contain key with prefix '/test'", 
summaries.isEmpty());
+        assertFalse("'testBucket' does not contain anymore keys with prefix 
'/test'", listing.isTruncated());
+        assertTrue(fakeKeyPrefixSet.contains(summaries.get(0).getKey()));
+
+        listing = s3.listObjects("testBucket", "/test/path");
+        summaries = listing.getObjectSummaries();
+        assertFalse("'testBucket' must contain key with prefix '/test'", 
summaries.isEmpty());
+        assertFalse("'testBucket' does not contain anymore keys with prefix 
'/test/path'", listing.isTruncated());
+        assertEquals("/test/path/val", summaries.get(0).getKey());
+
+        listing = s3.listObjects("testBucket", "/non/existent/test/path");
+        summaries = listing.getObjectSummaries();
+        assertTrue("'testBucket' must not contain key with prefix 
'/non/existent/test/path'", summaries.isEmpty());
+        assertFalse("'testBucket' does not contain anymore keys with prefix 
'/non/existent/test/path'", listing.isTruncated());
+
+        try {
+            s3.listObjects("nonExistentBucket", "/test");
+        }
+        catch (AmazonS3Exception e) {
+            assertTrue(e.getMessage().contains("The specified bucket does not 
exist"));
+        }
+    }
+
+    /**
+     * Test case to check if a bucket is created properly.
+     */
+    public void testCreateBucket() {
+        s3.createBucket("testBucket1");
+        assertTrue("The bucket 'testBucket1' should exist", 
s3.doesBucketExist("testBucket1"));
+
+        try {
+            s3.createBucket("testBucket");
+        }
+        catch (AmazonS3Exception e) {
+            assertTrue(e.getMessage().contains("The specified bucket already 
exist"));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/package-info.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/package-info.java
 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/package-info.java
new file mode 100644
index 0000000..3d70294
--- /dev/null
+++ 
b/modules/aws/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/s3/client/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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 description. -->
+ * Contains internal tests or test related classes and interfaces.
+ */
+package org.apache.ignite.spi.discovery.tcp.ipfinder.s3.client;

http://git-wip-us.apache.org/repos/asf/ignite/blob/ea5a2be1/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java 
b/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
index f96340e..a5b5eaa 100644
--- 
a/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
+++ 
b/modules/aws/src/test/java/org/apache/ignite/testsuites/IgniteS3TestSuite.java
@@ -28,7 +28,10 @@ import 
org.apache.ignite.spi.checkpoint.s3.S3SessionCheckpointSelfTest;
 import 
org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest;
 import 
org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderAwsCredentialsSelfTest;
 import 
org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderBucketEndpointSelfTest;
+import 
org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderKeyPrefixSelfTest;
 import 
org.apache.ignite.spi.discovery.tcp.ipfinder.s3.TcpDiscoveryS3IpFinderSSEAlgorithmSelfTest;
+import 
org.apache.ignite.spi.discovery.tcp.ipfinder.s3.client.DummyObjectListingTest;
+import 
org.apache.ignite.spi.discovery.tcp.ipfinder.s3.client.DummyS3ClientTest;
 import org.apache.ignite.testframework.IgniteTestSuite;
 
 /**
@@ -52,10 +55,13 @@ public class IgniteS3TestSuite extends TestSuite {
         suite.addTestSuite(S3CheckpointSpiStartStopSSEAlgorithmSelfTest.class);
 
         // S3 IP finder.
+        suite.addTestSuite(DummyS3ClientTest.class);
+        suite.addTestSuite(DummyObjectListingTest.class);
         suite.addTestSuite(TcpDiscoveryS3IpFinderAwsCredentialsSelfTest.class);
         
suite.addTestSuite(TcpDiscoveryS3IpFinderAwsCredentialsProviderSelfTest.class);
         suite.addTestSuite(TcpDiscoveryS3IpFinderBucketEndpointSelfTest.class);
         suite.addTestSuite(TcpDiscoveryS3IpFinderSSEAlgorithmSelfTest.class);
+        suite.addTestSuite(TcpDiscoveryS3IpFinderKeyPrefixSelfTest.class);
 
         return suite;
     }
@@ -87,4 +93,4 @@ public class IgniteS3TestSuite extends TestSuite {
 
         return key;
     }
-}
\ No newline at end of file
+}

Reply via email to