ignite-734: finished implementation, provided tests

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

Branch: refs/heads/ignite-757
Commit: fcb8d0d13f3d5db92c7a10d342ade879fdeb6364
Parents: b98da84
Author: Denis Magda <dma...@gridgain.com>
Authored: Wed Apr 22 18:03:03 2015 +0300
Committer: Denis Magda <dma...@gridgain.com>
Committed: Wed Apr 22 18:03:03 2015 +0300

----------------------------------------------------------------------
 modules/gce/README.txt                          |  32 ++
 modules/gce/licenses/apache-2.0.txt             | 202 ++++++++++
 modules/gce/pom.xml                             |  35 ++
 .../gce/TcpDiscoveryGoogleStorageIpFinder.java  | 368 +++++++++++++++++++
 .../tcp/ipfinder/gce/package-info.java          |  22 ++
 .../google/TcpDiscoveryGoogleCloudIpFinder.java | 364 ------------------
 .../tcp/ipfinder/google/package-info.java       |  22 --
 ...pDiscoveryGoogleStorageIpFinderSelfTest.java |  72 ++++
 .../tcp/ipfinder/gce/package-info.java          |  22 ++
 .../ignite/testsuites/IgniteGCETestSuite.java   |  71 ++++
 10 files changed, 824 insertions(+), 386 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/README.txt
----------------------------------------------------------------------
diff --git a/modules/gce/README.txt b/modules/gce/README.txt
new file mode 100644
index 0000000..22c0cb9
--- /dev/null
+++ b/modules/gce/README.txt
@@ -0,0 +1,32 @@
+Apache Ignite GCE Module
+------------------------
+
+Apache Ignite GCE module provides Google Cloud Storage based implementations 
of IP finder for TCP discovery.
+
+To enable GCE module when starting a standalone node, move 
'optional/ignite-gce' folder to
+'libs' folder before running 'ignite.{sh|bat}' script. The content of the 
module folder will
+be added to classpath in this case.
+
+Importing GCE Module In Maven Project
+-------------------------------------
+
+If you are using Maven to manage dependencies of your project, you can add GCE 
module
+dependency like this (replace '${ignite.version}' with actual Ignite version 
you are
+interested in):
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                        http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    ...
+    <dependencies>
+        ...
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-gce</artifactId>
+            <version>${ignite.version}</version>
+        </dependency>
+        ...
+    </dependencies>
+    ...
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/licenses/apache-2.0.txt
----------------------------------------------------------------------
diff --git a/modules/gce/licenses/apache-2.0.txt 
b/modules/gce/licenses/apache-2.0.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/modules/gce/licenses/apache-2.0.txt
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/pom.xml
----------------------------------------------------------------------
diff --git a/modules/gce/pom.xml b/modules/gce/pom.xml
index d4452fc..b12bb18 100644
--- a/modules/gce/pom.xml
+++ b/modules/gce/pom.xml
@@ -54,6 +54,41 @@
             <version>v1-rev32-1.20.0</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-core</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+            <version>${spring.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <version>${spring.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+            <version>${spring.version}</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 </project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinder.java
----------------------------------------------------------------------
diff --git 
a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinder.java
 
b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinder.java
new file mode 100644
index 0000000..a84b2fa
--- /dev/null
+++ 
b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinder.java
@@ -0,0 +1,368 @@
+/*
+ * 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.gce;
+
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+import com.google.api.client.googleapis.javanet.*;
+import com.google.api.client.googleapis.json.*;
+import com.google.api.client.http.*;
+import com.google.api.client.http.javanet.*;
+import com.google.api.services.storage.*;
+import com.google.api.services.storage.model.*;
+import com.google.api.client.googleapis.auth.oauth2.*;
+import com.google.api.client.json.jackson2.*;
+
+import org.apache.ignite.*;
+import org.apache.ignite.internal.*;
+import org.apache.ignite.internal.util.typedef.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+import org.apache.ignite.resources.*;
+import org.apache.ignite.spi.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
+
+/**
+ * Google Cloud Storage based IP finder.
+ * <p>
+ * For information about Cloud Storage visit <a 
href="https://cloud.google.com/storage/";>cloud.google.com</a>.
+ * <h1 class="header">Configuration</h1>
+ * <h2 class="header">Mandatory</h2>
+ * <ul>
+ *      <li>Service Account Id (see {@link #setServiceAccountId(String)})</li>
+ *      <li>Service Account P12 key file path (see {@link 
#setServiceAccountP12FilePath(String)})</li>
+ *      <li>Google Platform project name (see {@link 
#setProjectName(String)})</li>
+ *      <li>Google Storage bucket name (see {@link 
#setBucketName(String)})</li>
+ * </ul>
+ * <h2 class="header">Optional</h2>
+ * <ul>
+ *      <li>Shared flag (see {@link #setShared(boolean)})</li>
+ * </ul>
+ * <p>
+ * The finder will create a bucket with the provided name. The bucket will 
contain entries named
+ * like the following: {@code 192.168.1.136#1001}.
+ * <p>
+ * Note that storing data in Google Cloud Storage service will result in 
charges to your Google Cloud Platform account.
+ * Choose another implementation of {@link 
org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder} for local
+ * or home network tests.
+ * <p>
+ * Note that this finder is shared by default (see {@link 
org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder#isShared()}.
+ */
+public class TcpDiscoveryGoogleStorageIpFinder extends 
TcpDiscoveryIpFinderAdapter {
+    /* Default object's content. */
+    private final static ByteArrayInputStream OBJECT_CONTENT =  new 
ByteArrayInputStream(new byte[0]);
+
+    /** Grid logger. */
+    @LoggerResource
+    private IgniteLogger log;
+
+    /* Google Cloud Platform's project name.*/
+    private String projectName;
+
+    /* Google Storage bucket name. */
+    private String bucketName;
+
+    /* Service account p12 private key file name. */
+    private String serviceAccountP12FilePath;
+
+    /* Service account id. */
+    private String serviceAccountId;
+
+    /* Google storage. */
+    private Storage storage;
+
+    /* Init routine guard. */
+    private final AtomicBoolean initGuard = new AtomicBoolean();
+
+    /* Init routine latch. */
+    private final CountDownLatch initLatch = new CountDownLatch(1);
+
+    public TcpDiscoveryGoogleStorageIpFinder() {
+        setShared(true);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Collection<InetSocketAddress> getRegisteredAddresses() 
throws IgniteSpiException {
+        init();
+
+        Collection<InetSocketAddress> addrs = new LinkedList<>();
+
+        try {
+            Storage.Objects.List listObjects = 
storage.objects().list(bucketName);
+
+            com.google.api.services.storage.model.Objects objects;
+
+            do {
+                objects = listObjects.execute();
+
+                if (objects == null || objects.getItems() == null)
+                    break;
+
+                for (StorageObject object : objects.getItems())
+                    addrs.add(addrFromString(object.getName()));
+
+                listObjects.setPageToken(objects.getNextPageToken());
+            } while (null != objects.getNextPageToken());
+        }
+        catch (Exception e) {
+            throw new IgniteSpiException("Failed to get content from the 
bucket: " + bucketName, e);
+        }
+
+        return addrs;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void registerAddresses(Collection<InetSocketAddress> 
addrs) throws IgniteSpiException {
+        assert !F.isEmpty(addrs);
+
+        init();
+
+        for (InetSocketAddress addr : addrs) {
+            String key = keyFromAddr(addr);
+
+            StorageObject object = new StorageObject();
+
+            object.setBucket(bucketName);
+            object.setName(key);
+
+            InputStreamContent content =  new 
InputStreamContent("application/octet-stream", OBJECT_CONTENT);
+            content.setLength(OBJECT_CONTENT.available());
+
+            try {
+                Storage.Objects.Insert insertObject = 
storage.objects().insert(bucketName, object, content);
+
+                insertObject.execute();
+            }
+            catch (Exception e) {
+                throw new IgniteSpiException("Failed to put entry 
[bucketName=" + bucketName +
+                    ", entry=" + key + ']', e);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void unregisterAddresses(Collection<InetSocketAddress> 
addrs) throws IgniteSpiException {
+        assert !F.isEmpty(addrs);
+
+        init();
+
+        for (InetSocketAddress addr : addrs) {
+            String key = keyFromAddr(addr);
+
+            try {
+                Storage.Objects.Delete deleteObject = 
storage.objects().delete(bucketName, key);
+
+                deleteObject.execute();
+            }
+            catch (Exception e) {
+                throw new IgniteSpiException("Failed to delete entry 
[bucketName=" + bucketName +
+                                                     ", entry=" + key + ']', 
e);
+            }
+        }
+    }
+
+    /**
+     * Sets Google Cloud Platforms project name.
+     * Usually this is an auto generated project number (ex. 208709979073) 
that can be found in "Overview" section
+     * of Google Developer Console.
+     * <p>
+     * For details refer to Google Cloud Platform API reference.
+     *
+     * @param projectName Project name.
+     */
+    @IgniteSpiConfiguration(optional = false)
+    public void setProjectName(String projectName) {
+        this.projectName = projectName;
+    }
+
+    /**
+     * Sets Google Cloud Storage bucket name.
+     * If the bucket doesn't exist Ignite will automatically create it. 
However the name must be unique across whole
+     * Google Cloud Storage and Service Account Id (see {@link 
#setServiceAccountId(String)}) must be authorized to
+     * perform this operation.
+     *
+     * @param bucketName Bucket name.
+     */
+    @IgniteSpiConfiguration(optional = false)
+    public void setBucketName(String bucketName) {
+        this.bucketName = bucketName;
+    }
+
+
+    /**
+     * Sets a full path to the private key in PKCS12 format of the Service 
Account.
+     * <p>
+     * For more information refer to
+     * <a 
href="https://cloud.google.com/storage/docs/authentication#service_accounts";>Service
 Account Authentication</a>.
+     *
+     * @param p12FileName Private key file full path.
+     */
+    @IgniteSpiConfiguration(optional = false)
+    public void setServiceAccountP12FilePath(String p12FileName) {
+        this.serviceAccountP12FilePath = p12FileName;
+    }
+
+    /**
+     * Sets the service account ID (typically an e-mail address).
+     * <p>
+     * For more information refer to
+     * <a 
href="https://cloud.google.com/storage/docs/authentication#service_accounts";>Service
 Account Authentication</a>.
+     *
+     * @param id
+     */
+    @IgniteSpiConfiguration(optional = false)
+    public void setServiceAccountId(String id) {
+        this.serviceAccountId = id;
+    }
+
+    /**
+     * Google Cloud Storage initialization.
+     *
+     * @throws IgniteSpiException In case of error.
+     */
+    private void init() throws IgniteSpiException {
+        if (initGuard.compareAndSet(false, true)) {
+            if (serviceAccountId == null || serviceAccountP12FilePath == null 
|| projectName == null ||
+                bucketName == null)
+                throw new IgniteSpiException("One or more of the required 
parameters is not set [serviceAccountId=" +
+                    serviceAccountId + ", serviceAccountP12FilePath=" + 
serviceAccountP12FilePath + ", projectName=" +
+                    projectName + ", bucketName=" + bucketName + "]");
+
+            try {
+                NetHttpTransport httpTransport;
+
+                try {
+                    httpTransport = 
GoogleNetHttpTransport.newTrustedTransport();
+                }
+                catch (GeneralSecurityException | IOException e) {
+                    throw new IgniteSpiException(e);
+                }
+
+                GoogleCredential credential;
+
+                try {
+                    credential = new 
GoogleCredential.Builder().setTransport(httpTransport)
+                        
.setJsonFactory(JacksonFactory.getDefaultInstance()).setServiceAccountId(serviceAccountId)
+                        .setServiceAccountPrivateKeyFromP12File(new 
File(serviceAccountP12FilePath))
+                        
.setServiceAccountScopes(Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL)).build();
+
+                }
+                catch (Exception e) {
+                    throw new IgniteSpiException("Failed to authenticate on 
Google Cloud Platform", e);
+                }
+
+                try {
+                    storage = new Storage.Builder(httpTransport, 
JacksonFactory.getDefaultInstance(), credential)
+                                      .setApplicationName(projectName).build();
+                }
+                catch (Exception e) {
+                    throw new IgniteSpiException("Failed to open a storage for 
given project name: " + projectName, e);
+                }
+
+                boolean createBucket = false;
+
+                try {
+                    Storage.Buckets.Get getBucket = 
storage.buckets().get(bucketName);
+                    getBucket.setProjection("full");
+
+                    getBucket.execute();
+                }
+                catch (GoogleJsonResponseException e) {
+                    if (e.getStatusCode() == 404) {
+                        U.warn(log, "Bucket doesn't exist, will create it 
[bucketName=" + bucketName + "]");
+                        createBucket = true;
+                    }
+                    else
+                        throw new IgniteSpiException("Failed to open the 
bucket: " + bucketName, e);
+                }
+                catch (Exception e) {
+                    throw new IgniteSpiException("Failed to open the bucket: " 
+ bucketName, e);
+                }
+
+                if (createBucket) {
+                    Bucket newBucket = new Bucket();
+                    newBucket.setName(bucketName);
+
+                    try {
+                        Storage.Buckets.Insert insertBucket = 
storage.buckets().insert(projectName, newBucket);
+                        insertBucket.setProjection("full");
+                        
insertBucket.setPredefinedDefaultObjectAcl("projectPrivate");
+
+                        insertBucket.execute();
+                    }
+                    catch (Exception e) {
+                        throw new IgniteSpiException("Failed to create the 
bucket: " + bucketName, e);
+                    }
+                }
+            }
+            finally {
+                initLatch.countDown();
+            }
+        }
+        else {
+            try {
+                U.await(initLatch);
+            }
+            catch (IgniteInterruptedCheckedException e) {
+                throw new IgniteSpiException("Thread has been interrupted.", 
e);
+            }
+
+            if (storage == null)
+                throw new IgniteSpiException("IpFinder has not been 
initialized properly");
+        }
+    }
+
+    /**
+     * Constructs bucket's key from an address.
+     *
+     * @param addr Node address.
+     * @return Bucket key.
+     */
+    private String keyFromAddr(InetSocketAddress addr) {
+        return addr.getAddress().getHostAddress() + "#" +  addr.getPort();
+    }
+
+    /**
+     * Constructs a node address from bucket's key.
+     *
+     * @param key Bucket key.
+     * @return Node address.
+     * @throws IgniteSpiException In case of error.
+     */
+    private InetSocketAddress addrFromString(String key) throws 
IgniteSpiException {
+        String[] res = key.split("#");
+
+        if (res.length != 2)
+            throw new IgniteSpiException("Invalid address string: " + key);
+
+
+        int port;
+        try {
+            port = Integer.parseInt(res[1]);
+        }
+        catch (NumberFormatException e) {
+            throw new IgniteSpiException("Invalid port number: " + res[1]);
+        }
+
+        return new InetSocketAddress(res[0], port);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/package-info.java
----------------------------------------------------------------------
diff --git 
a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/package-info.java
 
b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/package-info.java
new file mode 100644
index 0000000..d46ceb9
--- /dev/null
+++ 
b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/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 Google Cloud Storage IP finder.
+ */
+package org.apache.ignite.spi.discovery.tcp.ipfinder.gce;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java
----------------------------------------------------------------------
diff --git 
a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java
 
b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java
deleted file mode 100644
index 4f7529f..0000000
--- 
a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/TcpDiscoveryGoogleCloudIpFinder.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * 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.google;
-
-import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
-import com.google.api.client.googleapis.json.GoogleJsonResponseException;
-import com.google.api.client.http.InputStreamContent;
-import com.google.api.client.http.javanet.NetHttpTransport;
-import com.google.api.services.storage.Storage;
-import com.google.api.services.storage.StorageScopes;
-import com.google.api.services.storage.model.*;
-import com.google.common.collect.ImmutableMap;
-import org.apache.ignite.IgniteLogger;
-import org.apache.ignite.internal.IgniteInterruptedCheckedException;
-import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.internal.util.typedef.internal.U;
-import org.apache.ignite.resources.LoggerResource;
-import org.apache.ignite.spi.*;
-import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
-
-import com.google.api.client.googleapis.auth.oauth2.*;
-import com.google.api.client.json.jackson2.*;
-
-import java.io.*;
-import java.net.*;
-import java.security.GeneralSecurityException;
-import java.util.*;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Google Cloud Storage based IP finder.
- * <p>
- * For information about Cloud Storage visit <a 
href="https://cloud.google.com/storage/";>cloud.google.com</a>.
- * <h1 class="header">Configuration</h1>
- * <h2 class="header">Mandatory</h2>
- * <ul>
- *      <li>Service Account Id (see {@link #setServiceAccountId(String)})</li>
- *      <li>Service Account P12 key file path (see {@link 
#setServiceAccountP12FilePath(String)})</li>
- *      <li>Google Platform project name (see {@link 
#setProjectName(String)})</li>
- *      <li>Google Storage bucket name (see {@link 
#setBucketName(String)})</li>
- * </ul>
- * <h2 class="header">Optional</h2>
- * <ul>
- *      <li>Shared flag (see {@link #setShared(boolean)})</li>
- * </ul>
- * <p>
- * The finder will create a bucket with the provided name. The bucket will 
contain entries named
- * like the following: {@code 192.168.1.136#1001}.
- * <p>
- * Note that storing data in Google Cloud Storage service will result in 
charges to your Google Cloud Platform account.
- * Choose another implementation of {@link 
org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder} for local
- * or home network tests.
- * <p>
- * Note that this finder is shared by default (see {@link 
org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder#isShared()}.
- */
-public class TcpDiscoveryGoogleCloudIpFinder extends 
TcpDiscoveryIpFinderAdapter {
-    /* Default object's content. */
-    private final static ByteArrayInputStream OBJECT_CONTENT =  new 
ByteArrayInputStream(new byte[0]);
-
-    /** Grid logger. */
-    @LoggerResource
-    private IgniteLogger log;
-
-    /* Google Cloud Platform's project name.*/
-    private String projectName;
-
-    /* Google Storage bucket name. */
-    private String bucketName;
-
-    /* Service account p12 private key file name. */
-    private String serviceAccountP12FilePath;
-
-    /* Service account id. */
-    private String serviceAccountId;
-
-    /* Google storage. */
-    private Storage storage;
-
-    /* Init routine guard. */
-    private final AtomicBoolean initGuard = new AtomicBoolean();
-
-    /* Init routine latch. */
-    private final CountDownLatch initLatch = new CountDownLatch(1);
-
-    public TcpDiscoveryGoogleCloudIpFinder() {
-        setShared(true);
-    }
-
-    /** {@inheritDoc} */
-    @Override public Collection<InetSocketAddress> getRegisteredAddresses() 
throws IgniteSpiException {
-        init();
-
-        Collection<InetSocketAddress> addrs = new LinkedList<>();
-
-        try {
-            Storage.Objects.List listObjects = 
storage.objects().list(bucketName);
-
-            com.google.api.services.storage.model.Objects objects;
-
-            do {
-                objects = listObjects.execute();
-
-                if (objects == null || objects.getItems() == null)
-                    break;
-
-                for (StorageObject object : objects.getItems())
-                    addrs.add(addrFromString(object.getName()));
-
-                listObjects.setPageToken(objects.getNextPageToken());
-            } while (null != objects.getNextPageToken());
-        }
-        catch (Exception e) {
-            throw new IgniteSpiException("Failed to get content from the 
bucket: " + bucketName, e);
-        }
-
-        return addrs;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void registerAddresses(Collection<InetSocketAddress> 
addrs) throws IgniteSpiException {
-        assert !F.isEmpty(addrs);
-
-        init();
-
-        for (InetSocketAddress addr : addrs) {
-            String key = keyFromAddr(addr);
-
-            StorageObject object = new StorageObject();
-
-            object.setBucket(bucketName);
-            object.setName(key);
-
-            InputStreamContent content =  new 
InputStreamContent("application/octet-stream", OBJECT_CONTENT);
-            content.setLength(OBJECT_CONTENT.available());
-
-            try {
-                Storage.Objects.Insert insertObject = 
storage.objects().insert(bucketName, object, content);
-
-                insertObject.execute();
-            }
-            catch (Exception e) {
-                throw new IgniteSpiException("Failed to put entry 
[bucketName=" + bucketName +
-                    ", entry=" + key + ']', e);
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override public void unregisterAddresses(Collection<InetSocketAddress> 
addrs) throws IgniteSpiException {
-        assert !F.isEmpty(addrs);
-
-        init();
-
-        for (InetSocketAddress addr : addrs) {
-            String key = keyFromAddr(addr);
-
-            try {
-                Storage.Objects.Delete deleteObject = 
storage.objects().delete(bucketName, key);
-
-                deleteObject.execute();
-            }
-            catch (Exception e) {
-                throw new IgniteSpiException("Failed to delete entry 
[bucketName=" + bucketName +
-                                                     ", entry=" + key + ']', 
e);
-            }
-        }
-    }
-
-    /**
-     * Sets Google Cloud Platforms project name.
-     * Usually this is an auto generated project number (ex. 208709979073) 
that can be found in "Overview" section
-     * of Google Developer Console.
-     * <p>
-     * For details refer to Google Cloud Platform API reference.
-     *
-     * @param projectName Project name.
-     */
-    @IgniteSpiConfiguration(optional = false)
-    public void setProjectName(String projectName) {
-        this.projectName = projectName;
-    }
-
-    /**
-     * Sets Google Cloud Storage bucket name.
-     * If the bucket doesn't exist Ignite will automatically create it. 
However the name must be unique across whole
-     * Google Cloud Storage and Service Account Id (see {@link 
#setServiceAccountId(String)}) must be authorized to
-     * perform this operation.
-     *
-     * @param bucketName Bucket name.
-     */
-    @IgniteSpiConfiguration(optional = false)
-    public void setBucketName(String bucketName) {
-        this.bucketName = bucketName;
-    }
-
-
-    /**
-     * Sets a full path to the private key in PKCS12 format of the Service 
Account.
-     * <p>
-     * For more information refer to
-     * <a 
href="https://cloud.google.com/storage/docs/authentication#service_accounts";>Service
 Account Authentication</a>.
-     *
-     * @param p12FileName Private key file full path.
-     */
-    @IgniteSpiConfiguration(optional = false)
-    public void setServiceAccountP12FilePath(String p12FileName) {
-        this.serviceAccountP12FilePath = p12FileName;
-    }
-
-    /**
-     * Sets the service account ID (typically an e-mail address).
-     * <p>
-     * For more information refer to
-     * <a 
href="https://cloud.google.com/storage/docs/authentication#service_accounts";>Service
 Account Authentication</a>.
-     *
-     * @param id
-     */
-    @IgniteSpiConfiguration(optional = false)
-    public void setServiceAccountId(String id) {
-        this.serviceAccountId = id;
-    }
-
-    /**
-     * Google Cloud Storage initialization.
-     *
-     * @throws IgniteSpiException In case of error.
-     */
-    private void init() throws IgniteSpiException {
-        if (initGuard.compareAndSet(false, true)) {
-            try {
-                NetHttpTransport httpTransport;
-
-                try {
-                    httpTransport = 
GoogleNetHttpTransport.newTrustedTransport();
-                }
-                catch (GeneralSecurityException | IOException e) {
-                    throw new IgniteSpiException(e);
-                }
-
-                GoogleCredential credential;
-
-                try {
-                    credential = new 
GoogleCredential.Builder().setTransport(httpTransport)
-                        
.setJsonFactory(JacksonFactory.getDefaultInstance()).setServiceAccountId(serviceAccountId)
-                        .setServiceAccountPrivateKeyFromP12File(new 
File(serviceAccountP12FilePath))
-                        
.setServiceAccountScopes(Collections.singleton(StorageScopes.DEVSTORAGE_FULL_CONTROL)).build();
-
-                }
-                catch (Exception e) {
-                    throw new IgniteSpiException("Failed to authenticate on 
Google Cloud Platform", e);
-                }
-
-                try {
-                    storage = new Storage.Builder(httpTransport, 
JacksonFactory.getDefaultInstance(), credential)
-                                      .setApplicationName(projectName).build();
-                }
-                catch (Exception e) {
-                    throw new IgniteSpiException("Failed to open a storage for 
given project name: " + projectName, e);
-                }
-
-                boolean createBucket = false;
-
-                try {
-                    Storage.Buckets.Get getBucket = 
storage.buckets().get(bucketName);
-                    getBucket.setProjection("full");
-
-                    getBucket.execute();
-                }
-                catch (GoogleJsonResponseException e) {
-                    if (e.getStatusCode() == 404) {
-                        U.warn(log, "Bucket doesn't exist, will create it 
[bucketName=" + bucketName + "]");
-                        createBucket = true;
-                    }
-                    else
-                        throw new IgniteSpiException("Failed to open the 
bucket: " + bucketName, e);
-                }
-                catch (Exception e) {
-                    throw new IgniteSpiException("Failed to open the bucket: " 
+ bucketName, e);
-                }
-
-                if (createBucket) {
-                    Bucket newBucket = new Bucket();
-                    newBucket.setName(bucketName);
-
-                    try {
-                        Storage.Buckets.Insert insertBucket = 
storage.buckets().insert(projectName, newBucket);
-                        insertBucket.setProjection("full");
-                        
insertBucket.setPredefinedDefaultObjectAcl("projectPrivate");
-
-                        insertBucket.execute();
-                    }
-                    catch (Exception e) {
-                        throw new IgniteSpiException("Failed to create the 
bucket: " + bucketName, e);
-                    }
-                }
-            }
-            finally {
-                initLatch.countDown();
-            }
-        }
-        else {
-            try {
-                U.await(initLatch);
-            }
-            catch (IgniteInterruptedCheckedException e) {
-                throw new IgniteSpiException("Thread has been interrupted.", 
e);
-            }
-
-            if (storage == null)
-                throw new IgniteSpiException("IpFinder has not been 
initialized properly");
-        }
-    }
-
-    /**
-     * Constructs bucket's key from an address.
-     *
-     * @param addr Node address.
-     * @return Bucket key.
-     */
-    private String keyFromAddr(InetSocketAddress addr) {
-        return addr.getAddress().getHostAddress() + "#" +  addr.getPort();
-    }
-
-    /**
-     * Constructs a node address from bucket's key.
-     *
-     * @param key Bucket key.
-     * @return Node address.
-     * @throws IgniteSpiException In case of error.
-     */
-    private InetSocketAddress addrFromString(String key) throws 
IgniteSpiException {
-        String[] res = key.split("#");
-
-        if (res.length != 2)
-            throw new IgniteSpiException("Invalid address string: " + key);
-
-
-        int port;
-        try {
-            port = Integer.parseInt(res[1]);
-        }
-        catch (NumberFormatException e) {
-            throw new IgniteSpiException("Invalid port number: " + res[1]);
-        }
-
-        return new InetSocketAddress(res[0], port);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/package-info.java
----------------------------------------------------------------------
diff --git 
a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/package-info.java
 
b/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/package-info.java
deleted file mode 100644
index fcf00b4..0000000
--- 
a/modules/gce/src/main/java/org/apache/ignite/spi/discovery/tcp/ipfinder/google/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 Google Cloud Storage IP finder.
- */
-package org.apache.ignite.spi.discovery.tcp.ipfinder.google;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinderSelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinderSelfTest.java
 
b/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinderSelfTest.java
new file mode 100644
index 0000000..b769efe
--- /dev/null
+++ 
b/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/TcpDiscoveryGoogleStorageIpFinderSelfTest.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.gce;
+
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.*;
+import org.apache.ignite.testsuites.*;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Collection;
+
+/**
+ * Google Cloud Storage based IP finder tests.
+ */
+public class TcpDiscoveryGoogleStorageIpFinderSelfTest
+    extends 
TcpDiscoveryIpFinderAbstractSelfTest<TcpDiscoveryGoogleStorageIpFinder> {
+    /**
+     * Constructor.
+     *
+     * @throws Exception If any error occurs.
+     */
+    public TcpDiscoveryGoogleStorageIpFinderSelfTest() throws Exception {
+        // No-op.
+    }
+
+    @Override protected TcpDiscoveryGoogleStorageIpFinder ipFinder() throws 
Exception {
+        TcpDiscoveryGoogleStorageIpFinder finder = new 
TcpDiscoveryGoogleStorageIpFinder();
+
+        injectLogger(finder);
+
+        assert finder.isShared() : "Ip finder must be shared by default.";
+
+        finder.setServiceAccountId(IgniteGCETestSuite.getServiceAccountId());
+        
finder.setServiceAccountP12FilePath(IgniteGCETestSuite.getP12FilePath());
+        finder.setProjectName(IgniteGCETestSuite.getProjectName());
+
+        // Bucket name must be unique across the whole GCE platform.
+        finder.setBucketName("ip-finder-test-bucket-" + 
InetAddress.getLocalHost().getAddress()[3]);
+
+        for (int i = 0; i < 5; i++) {
+            Collection<InetSocketAddress> addrs = 
finder.getRegisteredAddresses();
+
+            if (!addrs.isEmpty())
+                finder.unregisterAddresses(addrs);
+            else
+                return finder;
+
+            U.sleep(1000);
+        }
+
+        if (!finder.getRegisteredAddresses().isEmpty())
+            throw new Exception("Failed to initialize IP finder.");
+
+        return finder;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/package-info.java
----------------------------------------------------------------------
diff --git 
a/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/package-info.java
 
b/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/package-info.java
new file mode 100644
index 0000000..4d33114
--- /dev/null
+++ 
b/modules/gce/src/test/java/org/apache/ignite/spi/discovery/tcp/ipfinder/gce/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 Google Cloud Storage IP finder internal tests.
+ */
+package org.apache.ignite.spi.discovery.tcp.ipfinder.gce;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fcb8d0d1/modules/gce/src/test/java/org/apache/ignite/testsuites/IgniteGCETestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/gce/src/test/java/org/apache/ignite/testsuites/IgniteGCETestSuite.java
 
b/modules/gce/src/test/java/org/apache/ignite/testsuites/IgniteGCETestSuite.java
new file mode 100644
index 0000000..ff66c20
--- /dev/null
+++ 
b/modules/gce/src/test/java/org/apache/ignite/testsuites/IgniteGCETestSuite.java
@@ -0,0 +1,71 @@
+/*
+ * 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.testsuites;
+
+import junit.framework.*;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.gce.*;
+
+/**
+ * Google Compute Engine integration tests.
+ */
+public class IgniteGCETestSuite extends TestSuite {
+    /**
+     * @return Test suite.
+     * @throws Exception Thrown in case of the failure.
+     */
+    public static TestSuite suite() throws Exception {
+        TestSuite suite = new TestSuite("Google Compute Engine Integration 
Test Suite");
+
+        suite.addTest(new 
TestSuite(TcpDiscoveryGoogleStorageIpFinderSelfTest.class));
+
+        return suite;
+    }
+
+    /**
+     * @return Service Account Id.
+     */
+    public static String getServiceAccountId() {
+        String id = System.getenv("test.gce.account.id");
+
+        assert id != null : "Environment variable 'test.gce.account.id' is not 
set";
+
+        return id;
+    }
+
+    /**
+     * @return Service Account p12 file path.
+     */
+    public static String getP12FilePath() {
+        String path = System.getenv("test.gce.p12.path");
+
+        assert path != null : "Environment variable 'test.gce.p12.path' is not 
set";
+
+        return path;
+    }
+
+    /**
+     * @return GCE project name.
+     */
+    public static String getProjectName() {
+        String name = System.getenv("test.gce.project.name");
+
+        assert name != null : "Environment variable 'test.gce.project.name' is 
not set";
+
+        return name;
+    }
+}

Reply via email to