gcp-io: add ApiSurfaceTest

Copied from SDK, but I manually recreated the whitelist.

Surely there are refactoring improvements to be had so that we can more easily
reuse ApiSurface across modules.


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

Branch: refs/heads/apex-runner
Commit: d6f3a02d07257ceb30f294fb845e1fed4100362b
Parents: bdd71c4
Author: Dan Halperin <dhalp...@google.com>
Authored: Mon Oct 24 20:08:20 2016 -0700
Committer: Dan Halperin <dhalp...@google.com>
Committed: Thu Nov 3 12:31:47 2016 -0700

----------------------------------------------------------------------
 .../apache/beam/sdk/io/gcp/ApiSurfaceTest.java  | 132 +++++++++++++++++++
 1 file changed, 132 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-beam/blob/d6f3a02d/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/ApiSurfaceTest.java
----------------------------------------------------------------------
diff --git 
a/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/ApiSurfaceTest.java
 
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/ApiSurfaceTest.java
new file mode 100644
index 0000000..1f7b292
--- /dev/null
+++ 
b/sdks/java/io/google-cloud-platform/src/test/java/org/apache/beam/sdk/io/gcp/ApiSurfaceTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.beam.sdk.io.gcp;
+
+import static org.hamcrest.Matchers.anyOf;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.fail;
+
+import com.google.cloud.bigtable.grpc.BigtableInstanceName;
+import com.google.cloud.bigtable.grpc.BigtableTableName;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.beam.sdk.util.ApiSurface;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for the API surface of the gcp-io module. Tests that our public API 
is conformant to a
+ * hard-coded policy.
+ */
+@RunWith(JUnit4.class)
+public class ApiSurfaceTest {
+
+  @Test
+  public void testOurApiSurface() throws Exception {
+    ApiSurface checkedApiSurface =
+        ApiSurface.ofPackage("org.apache.beam.sdk.io.gcp")
+            .pruningPattern("org[.]apache[.]beam[.].*Test.*")
+            .pruningPattern("org[.]apache[.]beam[.].*IT")
+            .pruningPattern("java[.]lang.*");
+
+    Map<Class<?>, List<Class<?>>> disallowedClasses = Maps.newHashMap();
+    for (Class<?> clazz : checkedApiSurface.getExposedClasses()) {
+      if (!classIsAllowed(clazz)) {
+        disallowedClasses.put(clazz, 
checkedApiSurface.getAnyExposurePath(clazz));
+      }
+    }
+
+    List<String> disallowedMessages = Lists.newArrayList();
+    for (Map.Entry<Class<?>, List<Class<?>>> entry : 
disallowedClasses.entrySet()) {
+      disallowedMessages.add(entry.getKey() + " exposed via:\n\t\t"
+      + Joiner.on("\n\t\t").join(entry.getValue()));
+    }
+    Collections.sort(disallowedMessages);
+
+    if (!disallowedMessages.isEmpty()) {
+      fail("The following disallowed classes appear in the public API surface 
of the SDK:\n\t"
+        + Joiner.on("\n\t").join(disallowedMessages));
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private static final Set<Matcher<? extends Class<?>>> ALLOWED_PACKAGES =
+      ImmutableSet.<Matcher<? extends Class<?>>>of(
+          inPackage("com.google.api.client.json"),
+          inPackage("com.google.api.client.util"),
+          inPackage("com.google.api.services.bigquery.model"),
+          inPackage("com.google.auth"),
+          inPackage("com.google.bigtable.v2"),
+          inPackage("com.google.cloud.bigtable.config"),
+          equalTo(BigtableInstanceName.class),
+          equalTo(BigtableTableName.class),
+          // 
https://github.com/GoogleCloudPlatform/cloud-bigtable-client/pull/1056
+          inPackage("com.google.common.collect"), // via Bigtable, PR above 
out to fix.
+          inPackage("com.google.datastore.v1"),
+          inPackage("com.google.protobuf"),
+          inPackage("com.google.type"),
+          inPackage("com.fasterxml.jackson.annotation"),
+          inPackage("io.grpc"),
+          inPackage("java"),
+          inPackage("javax"),
+          inPackage("org.apache.beam"),
+          inPackage("org.apache.commons.logging"), // via Bigtable
+          inPackage("org.joda.time"));
+
+  @SuppressWarnings({"rawtypes", "unchecked"})
+  private boolean classIsAllowed(Class<?> clazz) {
+    // Safe cast inexpressible in Java without rawtypes
+    return anyOf((Iterable) ALLOWED_PACKAGES).matches(clazz);
+  }
+
+  private static Matcher<Class<?>> inPackage(String packageName) {
+    return new ClassInPackage(packageName);
+  }
+
+  private static class ClassInPackage extends 
TypeSafeDiagnosingMatcher<Class<?>> {
+
+    private final String packageName;
+
+    public ClassInPackage(String packageName) {
+      this.packageName = packageName;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+      description.appendText("Class in package \"");
+      description.appendText(packageName);
+      description.appendText("\"");
+    }
+
+    @Override
+    protected boolean matchesSafely(Class<?> clazz, Description 
mismatchDescription) {
+      return clazz.getName().startsWith(packageName + ".");
+    }
+
+  }
+}

Reply via email to