You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beam.apache.org by mw...@apache.org on 2020/03/30 10:17:27 UTC

[beam] branch BEAM-9147-videointelligence created (now d1c23bf7)

This is an automated email from the ASF dual-hosted git repository.

mwalenia pushed a change to branch BEAM-9147-videointelligence
in repository https://gitbox.apache.org/repos/asf/beam.git.


      at d1c23bf7 [BEAM-9147] Add documentation of VideoIntelligence transforms

This branch includes the following new commits:

     new a7f55e6  [BEAM-9147] Add VideoIntelligence transform
     new 4d383b7  [BEAM-9147] Add Video Intelligence integration test
     new d1c23bf7 [BEAM-9147] Add documentation of VideoIntelligence transforms

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[beam] 03/03: [BEAM-9147] Add documentation of VideoIntelligence transforms

Posted by mw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mwalenia pushed a commit to branch BEAM-9147-videointelligence
in repository https://gitbox.apache.org/repos/asf/beam.git

commit d1c23bf7b654d2561ae977fd43122559811af7b2
Author: Michal Walenia <mi...@polidea.com>
AuthorDate: Mon Mar 30 12:12:20 2020 +0200

    [BEAM-9147] Add documentation of VideoIntelligence transforms
---
 build.gradle                                       |  3 +-
 .../beam/sdk/extensions/ml/AnnotateVideo.java      | 16 +++++++
 .../beam/sdk/extensions/ml/VideoIntelligence.java  | 56 ++++++++++++++++++++++
 3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 2a5d541..021ba5b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -107,7 +107,8 @@ rat {
     "learning/katas/*/IO/**/*.txt",
 
     // Mockito extensions
-    "sdks/java/io/amazon-web-services2/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker"
+    "sdks/java/io/amazon-web-services2/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker",
+    "sdks/java/extensions/ml/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker"
   ]
 
   // Add .gitignore excludes to the Apache Rat exclusion list. We re-create the behavior
diff --git a/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/AnnotateVideo.java b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/AnnotateVideo.java
index edb5c04..6e7de6f 100644
--- a/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/AnnotateVideo.java
+++ b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/AnnotateVideo.java
@@ -27,6 +27,12 @@ import java.util.concurrent.ExecutionException;
 import org.apache.beam.sdk.transforms.DoFn;
 import org.apache.beam.sdk.values.PCollectionView;
 
+/**
+ * Base class for Video Intelligence transform.
+ *
+ * @param <T> Class of input data being passed in - either ByteString - video data encoded into
+ *     String or String - a GCS URI of the video to be annotated
+ */
 public abstract class AnnotateVideo<T> extends DoFn<T, List<VideoAnnotationResults>> {
 
   protected final PCollectionView<Map<T, VideoContext>> contextSideInput;
@@ -54,6 +60,15 @@ public abstract class AnnotateVideo<T> extends DoFn<T, List<VideoAnnotationResul
     videoIntelligenceServiceClient.close();
   }
 
+  /**
+   * Call the Video Intelligence Cloud AI service and return annotation results
+   *
+   * @param elementURI This or elementContents is required. GCS address of video to be annotated
+   * @param elementContents this or elementURI is required. Hex-encoded contents of video to be
+   *     annotated
+   * @param videoContext Optional context for video annotation.
+   * @return
+   */
   List<VideoAnnotationResults> getVideoAnnotationResults(
       String elementURI, ByteString elementContents, VideoContext videoContext)
       throws InterruptedException, ExecutionException {
@@ -75,6 +90,7 @@ public abstract class AnnotateVideo<T> extends DoFn<T, List<VideoAnnotationResul
     return annotateVideoAsync.get().getAnnotationResultsList();
   }
 
+  /** Process element implementation required. */
   @ProcessElement
   public abstract void processElement(ProcessContext context)
       throws ExecutionException, InterruptedException;
diff --git a/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/VideoIntelligence.java b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/VideoIntelligence.java
index 4b01de0..267f65b 100644
--- a/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/VideoIntelligence.java
+++ b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/VideoIntelligence.java
@@ -25,27 +25,67 @@ import java.util.concurrent.ExecutionException;
 import org.apache.beam.sdk.values.KV;
 import org.apache.beam.sdk.values.PCollectionView;
 
+/**
+ * Factory class for AnnotateVideo subclasses. allows integration with Google Cloud AI -
+ * VideoIntelligence service. Converts GCS URIs of videos or ByteStrings with video contents into
+ * Lists of VideoAnnotationResults.
+ *
+ * <p>Adding a side input of Maps of elements to VideoContext objects is allowed, so is using KVs of
+ * element and VideoContext as input.
+ *
+ * <p>Service account with proper permissions is required to use these transforms.
+ */
 public class VideoIntelligence {
 
+  /**
+   * Annotates videos from GCS URIs.
+   *
+   * @param featureList List of features to be annotated
+   * @param contextSideInput Optional side input with map of contexts to URIs
+   * @return DoFn performing the necessary operations
+   */
   public static AnnotateVideoFromURI annotateFromURI(
       List<Feature> featureList, PCollectionView<Map<String, VideoContext>> contextSideInput) {
     return new AnnotateVideoFromURI(contextSideInput, featureList);
   }
 
+  /**
+   * Annotates videos from ByteStrings of their contents.
+   *
+   * @param featureList List of features to be annotated
+   * @param contextSideInput Optional side input with map of contexts to ByteStrings
+   * @return DoFn performing the necessary operations
+   */
   public static AnnotateVideoFromBytes annotateFromBytes(
       PCollectionView<Map<ByteString, VideoContext>> contextSideInput, List<Feature> featureList) {
     return new AnnotateVideoFromBytes(contextSideInput, featureList);
   }
 
+  /**
+   * Annotates videos from key-value pairs of GCS URI and VideoContext
+   *
+   * @param featureList List of features to be annotated
+   * @return DoFn performing the necessary operations
+   */
   public static AnnotateVideoURIWithContext annotateFromUriWithContext(List<Feature> featureList) {
     return new AnnotateVideoURIWithContext(featureList);
   }
 
+  /**
+   * Annotates videos from key-value pairs of ByteStrings and VideoContext
+   *
+   * @param featureList List of features to be annotated
+   * @return DoFn performing the necessary operations
+   */
   public static AnnotateVideoBytesWithContext annotateFromBytesWithContext(
       List<Feature> featureList) {
     return new AnnotateVideoBytesWithContext(featureList);
   }
 
+  /**
+   * Implementation of AnnotateVideo accepting Strings as contents of input PCollection. Annotates
+   * videos found on GCS based on URIs from input PCollection
+   */
   public static class AnnotateVideoFromURI extends AnnotateVideo<String> {
 
     public AnnotateVideoFromURI(
@@ -53,6 +93,7 @@ public class VideoIntelligence {
       super(contextSideInput, featureList);
     }
 
+    /** ProcessElement implementation. */
     @Override
     public void processElement(ProcessContext context)
         throws ExecutionException, InterruptedException {
@@ -67,6 +108,10 @@ public class VideoIntelligence {
     }
   }
 
+  /**
+   * Implementation of AnnotateVideo accepting ByteStrings as contents of input PCollection. Videos
+   * decoded from the ByteStrings are annotated.
+   */
   public static class AnnotateVideoFromBytes extends AnnotateVideo<ByteString> {
 
     public AnnotateVideoFromBytes(
@@ -75,6 +120,7 @@ public class VideoIntelligence {
       super(contextSideInput, featureList);
     }
 
+    /** Implementation of ProcessElement */
     @Override
     public void processElement(ProcessContext context)
         throws ExecutionException, InterruptedException {
@@ -89,12 +135,17 @@ public class VideoIntelligence {
     }
   }
 
+  /**
+   * Implementation of AnnotateVideo accepting KVs as contents of input PCollection. Keys are the
+   * GCS URIs, values - VideoContext objects.
+   */
   public static class AnnotateVideoURIWithContext extends AnnotateVideo<KV<String, VideoContext>> {
 
     public AnnotateVideoURIWithContext(List<Feature> featureList) {
       super(featureList);
     }
 
+    /** ProcessElement implementation */
     @Override
     public void processElement(ProcessContext context)
         throws ExecutionException, InterruptedException {
@@ -106,6 +157,10 @@ public class VideoIntelligence {
     }
   }
 
+  /**
+   * Implementation of AnnotateVideo accepting KVs as contents of input PCollection. Keys are the
+   * ByteString encoded video contents, values - VideoContext objects.
+   */
   public static class AnnotateVideoBytesWithContext
       extends AnnotateVideo<KV<ByteString, VideoContext>> {
 
@@ -113,6 +168,7 @@ public class VideoIntelligence {
       super(featureList);
     }
 
+    /** ProcessElement implementation */
     @Override
     public void processElement(ProcessContext context)
         throws ExecutionException, InterruptedException {


[beam] 01/03: [BEAM-9147] Add VideoIntelligence transform

Posted by mw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mwalenia pushed a commit to branch BEAM-9147-videointelligence
in repository https://gitbox.apache.org/repos/asf/beam.git

commit a7f55e60c1cfe39112331dd4e2b34bc522a2c77a
Author: Michal Walenia <mi...@polidea.com>
AuthorDate: Tue Mar 24 15:41:31 2020 +0100

    [BEAM-9147] Add VideoIntelligence transform
---
 sdks/java/extensions/ml/build.gradle               |  34 ++++++
 .../beam/sdk/extensions/ml/AnnotateVideo.java      |  81 +++++++++++++
 .../beam/sdk/extensions/ml/VideoIntelligence.java  | 126 +++++++++++++++++++++
 .../beam/sdk/extensions/ml/AnnotateVideoTest.java  |  73 ++++++++++++
 .../org.mockito.plugins.MockMaker                  |   1 +
 settings.gradle                                    |   3 +
 6 files changed, 318 insertions(+)

diff --git a/sdks/java/extensions/ml/build.gradle b/sdks/java/extensions/ml/build.gradle
new file mode 100644
index 0000000..482decc
--- /dev/null
+++ b/sdks/java/extensions/ml/build.gradle
@@ -0,0 +1,34 @@
+/*
+ *
+ *  * 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.
+ *
+ */
+
+plugins { id 'org.apache.beam.module' }
+applyJavaNature(automaticModuleName: 'org.apache.beam.sdk.extensions.protobuf')
+
+description = 'Apache Beam :: SDKs :: Java :: Extensions :: ML'
+
+dependencies {
+    compile project(path: ":sdks:java:core", configuration: "shadow")
+    compile project(":sdks:java:expansion-service")
+    testCompile project(path: ':sdks:java:core', configuration: 'shadowTest')
+    compile 'com.google.cloud:google-cloud-video-intelligence:1.2.0'
+    testCompile library.java.mockito_core
+    testCompile 'com.google.cloud:google-cloud-video-intelligence:1.2.0'
+    testCompile library.java.junit
+}
diff --git a/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/AnnotateVideo.java b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/AnnotateVideo.java
new file mode 100644
index 0000000..edb5c04
--- /dev/null
+++ b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/AnnotateVideo.java
@@ -0,0 +1,81 @@
+/*
+ * 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.extensions.ml;
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.videointelligence.v1.*;
+import com.google.protobuf.ByteString;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import org.apache.beam.sdk.transforms.DoFn;
+import org.apache.beam.sdk.values.PCollectionView;
+
+public abstract class AnnotateVideo<T> extends DoFn<T, List<VideoAnnotationResults>> {
+
+  protected final PCollectionView<Map<T, VideoContext>> contextSideInput;
+  protected final List<Feature> featureList;
+  VideoIntelligenceServiceClient videoIntelligenceServiceClient;
+
+  public AnnotateVideo(
+      PCollectionView<Map<T, VideoContext>> contextSideInput, List<Feature> featureList) {
+    this.contextSideInput = contextSideInput;
+    this.featureList = featureList;
+  }
+
+  public AnnotateVideo(List<Feature> featureList) {
+    contextSideInput = null;
+    this.featureList = featureList;
+  }
+
+  @StartBundle
+  public void startBundle() throws IOException {
+    videoIntelligenceServiceClient = VideoIntelligenceServiceClient.create();
+  }
+
+  @Teardown
+  public void teardown() {
+    videoIntelligenceServiceClient.close();
+  }
+
+  List<VideoAnnotationResults> getVideoAnnotationResults(
+      String elementURI, ByteString elementContents, VideoContext videoContext)
+      throws InterruptedException, ExecutionException {
+    AnnotateVideoRequest.Builder requestBuilder =
+        AnnotateVideoRequest.newBuilder().addAllFeatures(featureList);
+    if (elementURI != null) {
+      requestBuilder.setInputUri(elementURI);
+    } else if (elementContents != null) {
+      requestBuilder.setInputContent(elementContents);
+    } else {
+      throw new IllegalArgumentException("Either elementURI or elementContents should be non-null");
+    }
+    if (videoContext != null) {
+      requestBuilder.setVideoContext(videoContext);
+    }
+    AnnotateVideoRequest annotateVideoRequest = requestBuilder.build();
+    OperationFuture<AnnotateVideoResponse, AnnotateVideoProgress> annotateVideoAsync =
+        videoIntelligenceServiceClient.annotateVideoAsync(annotateVideoRequest);
+    return annotateVideoAsync.get().getAnnotationResultsList();
+  }
+
+  @ProcessElement
+  public abstract void processElement(ProcessContext context)
+      throws ExecutionException, InterruptedException;
+}
diff --git a/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/VideoIntelligence.java b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/VideoIntelligence.java
new file mode 100644
index 0000000..4b01de0
--- /dev/null
+++ b/sdks/java/extensions/ml/src/main/java/org/apache/beam/sdk/extensions/ml/VideoIntelligence.java
@@ -0,0 +1,126 @@
+/*
+ * 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.extensions.ml;
+
+import com.google.cloud.videointelligence.v1.*;
+import com.google.protobuf.ByteString;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import org.apache.beam.sdk.values.KV;
+import org.apache.beam.sdk.values.PCollectionView;
+
+public class VideoIntelligence {
+
+  public static AnnotateVideoFromURI annotateFromURI(
+      List<Feature> featureList, PCollectionView<Map<String, VideoContext>> contextSideInput) {
+    return new AnnotateVideoFromURI(contextSideInput, featureList);
+  }
+
+  public static AnnotateVideoFromBytes annotateFromBytes(
+      PCollectionView<Map<ByteString, VideoContext>> contextSideInput, List<Feature> featureList) {
+    return new AnnotateVideoFromBytes(contextSideInput, featureList);
+  }
+
+  public static AnnotateVideoURIWithContext annotateFromUriWithContext(List<Feature> featureList) {
+    return new AnnotateVideoURIWithContext(featureList);
+  }
+
+  public static AnnotateVideoBytesWithContext annotateFromBytesWithContext(
+      List<Feature> featureList) {
+    return new AnnotateVideoBytesWithContext(featureList);
+  }
+
+  public static class AnnotateVideoFromURI extends AnnotateVideo<String> {
+
+    public AnnotateVideoFromURI(
+        PCollectionView<Map<String, VideoContext>> contextSideInput, List<Feature> featureList) {
+      super(contextSideInput, featureList);
+    }
+
+    @Override
+    public void processElement(ProcessContext context)
+        throws ExecutionException, InterruptedException {
+      String elementURI = context.element();
+      VideoContext videoContext = null;
+      if (contextSideInput != null) {
+        videoContext = context.sideInput(contextSideInput).get(elementURI);
+      }
+      List<VideoAnnotationResults> annotationResultsList =
+          getVideoAnnotationResults(elementURI, null, videoContext);
+      context.output(annotationResultsList);
+    }
+  }
+
+  public static class AnnotateVideoFromBytes extends AnnotateVideo<ByteString> {
+
+    public AnnotateVideoFromBytes(
+        PCollectionView<Map<ByteString, VideoContext>> contextSideInput,
+        List<Feature> featureList) {
+      super(contextSideInput, featureList);
+    }
+
+    @Override
+    public void processElement(ProcessContext context)
+        throws ExecutionException, InterruptedException {
+      ByteString element = context.element();
+      VideoContext videoContext = null;
+      if (contextSideInput != null) {
+        videoContext = context.sideInput(contextSideInput).get(element);
+      }
+      List<VideoAnnotationResults> videoAnnotationResults =
+          getVideoAnnotationResults(null, element, videoContext);
+      context.output(videoAnnotationResults);
+    }
+  }
+
+  public static class AnnotateVideoURIWithContext extends AnnotateVideo<KV<String, VideoContext>> {
+
+    public AnnotateVideoURIWithContext(List<Feature> featureList) {
+      super(featureList);
+    }
+
+    @Override
+    public void processElement(ProcessContext context)
+        throws ExecutionException, InterruptedException {
+      String elementURI = context.element().getKey();
+      VideoContext videoContext = context.element().getValue();
+      List<VideoAnnotationResults> videoAnnotationResults =
+          getVideoAnnotationResults(elementURI, null, videoContext);
+      context.output(videoAnnotationResults);
+    }
+  }
+
+  public static class AnnotateVideoBytesWithContext
+      extends AnnotateVideo<KV<ByteString, VideoContext>> {
+
+    public AnnotateVideoBytesWithContext(List<Feature> featureList) {
+      super(featureList);
+    }
+
+    @Override
+    public void processElement(ProcessContext context)
+        throws ExecutionException, InterruptedException {
+      ByteString element = context.element().getKey();
+      VideoContext videoContext = context.element().getValue();
+      List<VideoAnnotationResults> videoAnnotationResults =
+          getVideoAnnotationResults(null, element, videoContext);
+      context.output(videoAnnotationResults);
+    }
+  }
+}
diff --git a/sdks/java/extensions/ml/src/test/java/org/apache/beam/sdk/extensions/ml/AnnotateVideoTest.java b/sdks/java/extensions/ml/src/test/java/org/apache/beam/sdk/extensions/ml/AnnotateVideoTest.java
new file mode 100644
index 0000000..57400e4
--- /dev/null
+++ b/sdks/java/extensions/ml/src/test/java/org/apache/beam/sdk/extensions/ml/AnnotateVideoTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.extensions.ml;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import com.google.api.gax.longrunning.OperationFuture;
+import com.google.cloud.videointelligence.v1.AnnotateVideoProgress;
+import com.google.cloud.videointelligence.v1.AnnotateVideoResponse;
+import com.google.cloud.videointelligence.v1.Feature;
+import com.google.cloud.videointelligence.v1.VideoAnnotationResults;
+import com.google.cloud.videointelligence.v1.VideoIntelligenceServiceClient;
+import com.google.protobuf.ByteString;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AnnotateVideoTest {
+
+  private static final String TEST_URI = "fake_uri";
+  private static final ByteString TEST_BYTES = ByteString.copyFromUtf8("12345");
+
+  @Mock private VideoIntelligenceServiceClient serviceClient;
+  @Mock private OperationFuture<AnnotateVideoResponse, AnnotateVideoProgress> future;
+  @Mock private AnnotateVideoResponse response;
+
+  @Test
+  public void shouldReturnAListOfAnnotations() throws ExecutionException, InterruptedException {
+    when(response.getAnnotationResultsList())
+        .thenReturn(Collections.singletonList(VideoAnnotationResults.newBuilder().build()));
+    when(future.get()).thenReturn(response);
+    when(serviceClient.annotateVideoAsync(any())).thenReturn(future);
+    VideoIntelligence.AnnotateVideoFromBytes annotateVideoFromBytes =
+        VideoIntelligence.annotateFromBytes(
+            null, Collections.singletonList(Feature.LABEL_DETECTION));
+
+    annotateVideoFromBytes.videoIntelligenceServiceClient = serviceClient;
+    List<VideoAnnotationResults> videoAnnotationResults =
+        annotateVideoFromBytes.getVideoAnnotationResults(TEST_URI, null, null);
+    assertEquals(1, videoAnnotationResults.size());
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void shouldThrowErrorWhenBothInputTypesNull()
+      throws ExecutionException, InterruptedException {
+    VideoIntelligence.AnnotateVideoFromBytes annotateVideoFromBytes =
+        VideoIntelligence.annotateFromBytes(
+            null, Collections.singletonList(Feature.LABEL_DETECTION));
+    annotateVideoFromBytes.getVideoAnnotationResults(null, null, null);
+  }
+}
diff --git a/sdks/java/extensions/ml/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/sdks/java/extensions/ml/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 0000000..1f0955d
--- /dev/null
+++ b/sdks/java/extensions/ml/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
diff --git a/settings.gradle b/settings.gradle
index a25f357..b7c832a 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -165,3 +165,6 @@ include "beam-test-infra-metrics"
 project(":beam-test-infra-metrics").dir = file(".test-infra/metrics")
 include "beam-test-tools"
 project(":beam-test-tools").dir = file(".test-infra/tools")
+include 'sdks:java:extensions:ml'
+findProject(':sdks:java:extensions:ml')?.name = 'ml'
+


[beam] 02/03: [BEAM-9147] Add Video Intelligence integration test

Posted by mw...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

mwalenia pushed a commit to branch BEAM-9147-videointelligence
in repository https://gitbox.apache.org/repos/asf/beam.git

commit 4d383b78d847755006e193d5481d09ccd1e7d0d0
Author: Michal Walenia <mi...@polidea.com>
AuthorDate: Fri Mar 27 15:43:29 2020 +0100

    [BEAM-9147] Add Video Intelligence integration test
---
 sdks/java/extensions/ml/build.gradle               |  6 ++
 .../sdk/extensions/ml/VideoIntelligenceIT.java     | 79 ++++++++++++++++++++++
 2 files changed, 85 insertions(+)

diff --git a/sdks/java/extensions/ml/build.gradle b/sdks/java/extensions/ml/build.gradle
index 482decc..274c074 100644
--- a/sdks/java/extensions/ml/build.gradle
+++ b/sdks/java/extensions/ml/build.gradle
@@ -31,4 +31,10 @@ dependencies {
     testCompile library.java.mockito_core
     testCompile 'com.google.cloud:google-cloud-video-intelligence:1.2.0'
     testCompile library.java.junit
+    testRuntimeOnly project(path: ":runners:direct-java", configuration: "shadow")
+    testRuntimeOnly project(":runners:google-cloud-dataflow-java")
+}
+
+project.test {
+    include "**/**IT.class"
 }
diff --git a/sdks/java/extensions/ml/src/test/java/org/apache/beam/sdk/extensions/ml/VideoIntelligenceIT.java b/sdks/java/extensions/ml/src/test/java/org/apache/beam/sdk/extensions/ml/VideoIntelligenceIT.java
new file mode 100644
index 0000000..3ff18ce
--- /dev/null
+++ b/sdks/java/extensions/ml/src/test/java/org/apache/beam/sdk/extensions/ml/VideoIntelligenceIT.java
@@ -0,0 +1,79 @@
+/*
+ * 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.extensions.ml;
+
+import static org.apache.beam.sdk.extensions.ml.VideoIntelligence.annotateFromURI;
+import static org.junit.Assert.assertEquals;
+
+import com.google.cloud.videointelligence.v1.Feature;
+import com.google.cloud.videointelligence.v1.VideoAnnotationResults;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.beam.sdk.testing.PAssert;
+import org.apache.beam.sdk.testing.TestPipeline;
+import org.apache.beam.sdk.transforms.Create;
+import org.apache.beam.sdk.transforms.ParDo;
+import org.apache.beam.sdk.transforms.SerializableFunction;
+import org.apache.beam.sdk.values.PCollection;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class VideoIntelligenceIT {
+  @Rule public TestPipeline testPipeline = TestPipeline.create();
+  private static final String VIDEO_URI =
+      "gs://apache-beam-samples/advanced_analytics/video/gbikes_dinosaur.mp4";
+  private List<Feature> featureList = Collections.singletonList(Feature.LABEL_DETECTION);
+
+  @Test
+  public void annotateVideoFromURINoContext() {
+    PCollection<List<VideoAnnotationResults>> annotationResults =
+        testPipeline
+            .apply(Create.of(VIDEO_URI))
+            .apply("Annotate video", ParDo.of(annotateFromURI(featureList, null)));
+    PAssert.that(annotationResults).satisfies(new VerifyVideoAnnotationResult());
+    testPipeline.run().waitUntilFinish();
+  }
+
+  private static class VerifyVideoAnnotationResult
+      implements SerializableFunction<Iterable<List<VideoAnnotationResults>>, Void> {
+
+    @Override
+    public Void apply(Iterable<List<VideoAnnotationResults>> input) {
+      List<Boolean> labelEvaluations = new ArrayList<>();
+      input.forEach(
+          videoAnnotationResults ->
+              labelEvaluations.add(
+                  videoAnnotationResults.stream()
+                      .anyMatch(
+                          result ->
+                              result.getSegmentLabelAnnotationsList().stream()
+                                  .anyMatch(
+                                      labelAnnotation ->
+                                          labelAnnotation
+                                              .getEntity()
+                                              .getDescription()
+                                              .equals("dinosaur")))));
+      assertEquals(Boolean.TRUE, labelEvaluations.contains(Boolean.TRUE));
+      return null;
+    }
+  }
+}