{"action":"created","comment":{"url":"https://api.github.com/repos/grpc/grpc-java/pulls/comments/46626997","id":46626997,"diff_hunk":"@@ -0,0 +1,334 @@\n+/*\n+ * Copyright 2015, Google Inc. All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are\n+ * met:\n+ *\n+ *    * Redistributions of source code must retain the above copyright\n+ * notice, this list of conditions and the following disclaimer.\n+ *    * Redistributions in binary form must reproduce the above\n+ * copyright notice, this list of conditions and the following disclaimer\n+ * in the documentation and/or other materials provided with the\n+ * distribution.\n+ *\n+ *    * Neither the name of Google Inc. nor the names of its\n+ * contributors may be used to endorse or promote products derived from\n+ * this software without specific prior written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package io.grpc.testing.integration;\n+\n+import static org.junit.Assert.assertEquals;\n+import static org.junit.Assert.fail;\n+\n+import io.grpc.Context;\n+import io.grpc.Metadata;\n+import io.grpc.MethodDescriptor;\n+import io.grpc.ServerCall;\n+import io.grpc.ServerCallHandler;\n+import io.grpc.ServerInterceptor;\n+import io.grpc.ServerInterceptors;\n+import io.grpc.Status;\n+import io.grpc.StatusRuntimeException;\n+import io.grpc.inprocess.InProcessChannelBuilder;\n+import io.grpc.inprocess.InProcessServerBuilder;\n+import io.grpc.internal.ManagedChannelImpl;\n+import io.grpc.internal.ServerImpl;\n+import io.grpc.stub.StreamObserver;\n+\n+import org.junit.After;\n+import org.junit.Before;\n+import org.junit.Test;\n+import org.mockito.Mock;\n+import org.mockito.MockitoAnnotations;\n+\n+import java.io.IOException;\n+import java.util.concurrent.Executor;\n+import java.util.concurrent.Executors;\n+import java.util.concurrent.Semaphore;\n+import java.util.concurrent.TimeUnit;\n+import java.util.concurrent.atomic.AtomicInteger;\n+\n+/**\n+ * Integration test for various forms of cancellation & deadline propagation.\n+ */\n+public class CascadingTest {\n+\n+  @Mock\n+  TestServiceGrpc.TestService service;\n+  private ManagedChannelImpl channel;\n+  private ServerImpl server;\n+  private AtomicInteger depth;\n+  private int depthThreshold;\n+  private AtomicInteger observedCancellations;\n+  private AtomicInteger receivedCancellations;\n+  private TestServiceGrpc.TestServiceBlockingStub blockingStub;\n+  private TestServiceGrpc.TestServiceStub asyncStub;\n+\n+  @Before\n+  public void setUp() throws Exception {\n+    MockitoAnnotations.initMocks(this);\n+    channel = InProcessChannelBuilder.forName(\"channel\").build();\n+    depthThreshold = 0;\n+    depth = new AtomicInteger();\n+    observedCancellations = new AtomicInteger();\n+    receivedCancellations = new AtomicInteger();\n+    blockingStub = TestServiceGrpc.newBlockingStub(channel);\n+    asyncStub = TestServiceGrpc.newStub(channel);\n+  }\n+\n+  @After\n+  public void tearDown() {\n+    Context.ROOT.attach();\n+    channel.shutdownNow();\n+    server.shutdownNow();\n+  }\n+\n+  /**\n+   * Test {@link Context} expiration propagates from the first node in the call chain all the way\n+   * to the last.\n+   */\n+  @Test\n+  public void testCascadingCancellationViaOuterContextExpiration() throws Exception {\n+    startChainingServer();\n+    Context.current().withDeadlineAfter(150, TimeUnit.MILLISECONDS).attach();\n+    try {\n+      blockingStub.unaryCall(Messages.SimpleRequest.getDefaultInstance());\n+      fail(\"Expected cancellation\");\n+    } catch (StatusRuntimeException sre) {\n+      // Wait for the workers to finish\n+      Thread.sleep(100);\n+      Status status = Status.fromThrowable(sre);\n+      assertEquals(Status.Code.CANCELLED, status.getCode());\n+      // Count the outer cancellation\n+      observedCancellations.incrementAndGet();\n+\n+      assertEquals(observedCancellations.get(), depth.get());\n+      assertEquals(observedCancellations.get(), receivedCancellations.get());\n+      assertEquals(3, depth.get());\n+    }\n+  }\n+\n+  /**\n+   * Test that cancellation via method deadline propagates down the call.\n+   */\n+  @Test\n+  public void testCascadingCancellationViaMethodTimeout() throws Exception {\n+    startChainingServer();\n+    try {\n+      blockingStub.withDeadlineAfter(150, TimeUnit.MILLISECONDS)\n+          .unaryCall(Messages.SimpleRequest.getDefaultInstance());\n+      fail(\"Expected cancellation\");\n+    } catch (StatusRuntimeException sre) {\n+      // Wait for the workers to finish\n+      Thread.sleep(100);\n+      Status status = Status.fromThrowable(sre);\n+      // Outermost caller observes deadline exceeded, the descendant RPCs are cancelled so they\n+      // receive cancellation.\n+      assertEquals(Status.Code.DEADLINE_EXCEEDED, status.getCode());\n+      // Count the outermost failure as cancellation\n+      observedCancellations.incrementAndGet();\n+\n+      assertEquals(observedCancellations.get(), depth.get());\n+      assertEquals(observedCancellations.get(), receivedCancellations.get());\n+      assertEquals(3, depth.get());\n+    }\n+  }\n+\n+  /**\n+   * Test that when RPC cancellation propagates up a call chain, the cancellation of the parent\n+   * RPC triggers cancellation of all of its children.\n+   */\n+  @Test\n+  public void testCascadingCancellationViaLeafFailure() throws Exception {\n+    startCallTreeServer();\n+    try {\n+      // Use response size limit to control tree depth.\n+      blockingStub.unaryCall(Messages.SimpleRequest.newBuilder().setResponseSize(3).build());\n+      fail(\"Expected abort\");\n+    } catch (StatusRuntimeException sre) {\n+      // Wait for the workers to finish\n+      Thread.sleep(100);\n+      Status status = Status.fromThrowable(sre);\n+      // Outermost caller observes ABORTED propagating up from the failing leaf,\n+      // The descendant RPCs are cancelled so they receive CANCELLED.\n+      assertEquals(Status.Code.ABORTED, status.getCode());\n+      // All nodes (15) except one edge of the tree (4) will be cancelled.\n+      assertEquals(11, observedCancellations.get());\n+      assertEquals(11, receivedCancellations.get());\n+    }\n+  }\n+\n+  /**\n+   * Create a chain of client to server calls which can be cancelled top down.\n+   */\n+  private void startChainingServer() throws IOException {\n+    final Executor otherWork = Context.propagate(Executors.newCachedThreadPool());\n+    server = InProcessServerBuilder.forName(\"channel\").addService(\n+        ServerInterceptors.intercept(TestServiceGrpc.bindService(service),\n+            new ServerInterceptor() {\n+              @Override\n+              public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(\n+                  MethodDescriptor<ReqT, RespT> method,\n+                  final ServerCall<RespT> call,\n+                  Metadata headers,\n+                  ServerCallHandler<ReqT, RespT> next) {\n+                // Respond with the headers but nothing else.\n+                call.sendHeaders(new Metadata());\n+                call.request(1);\n+                return new ServerCall.Listener<ReqT>() {\n+                  @Override\n+                  public void onMessage(final ReqT message) {\n+                    try {\n+                      // Wait and then recurse.\n+                      if (depth.incrementAndGet() == depthThreshold) {\n+                        call.close(Status.ABORTED, new Metadata());\n+                        return;\n+                      }\n+                      Thread.sleep(50);\n+                    } catch (InterruptedException ie) {\n+                      throw new RuntimeException(ie);\n+                    }\n+\n+                    otherWork.execute(new Runnable() {","path":"interop-testing/src/test/java/io/grpc/testing/integration/CascadingTest.java","position":206,"original_position":206,"commit_id":"8e8359640b8998238adbdbfc045d7fa5ffbc4791","original_commit_id":"8e8359640b8998238adbdbfc045d7fa5ffbc4791","user":{"login":"ejona86","id":2811396,"avatar_url":"https://avatars.githubusercontent.com/u/2811396?v=3","gravatar_id":"","url":"https://api.github.com/users/ejona86","html_url":"https://github.com/ejona86","followers_url":"https://api.github.com/users/ejona86/followers","following_url":"https://api.github.com/users/ejona86/following{/other_user}","gists_url":"https://api.github.com/users/ejona86/gists{/gist_id}","starred_url":"https://api.github.com/users/ejona86/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ejona86/subscriptions","organizations_url":"https://api.github.com/users/ejona86/orgs","repos_url":"https://api.github.com/users/ejona86/repos","events_url":"https://api.github.com/users/ejona86/events{/privacy}","received_events_url":"https://api.github.com/users/ejona86/received_events","type":"User","site_admin":false},"body":"Why not use an async client?","created_at":"2015-12-03T23:04:54Z","updated_at":"2015-12-03T23:04:54Z","html_url":"https://github.com/grpc/grpc-java/pull/1248#discussion_r46626997","pull_request_url":"https://api.github.com/repos/grpc/grpc-java/pulls/1248","_links":{"self":{"href":"https://api.github.com/repos/grpc/grpc-java/pulls/comments/46626997"},"html":{"href":"https://github.com/grpc/grpc-java/pull/1248#discussion_r46626997"},"pull_request":{"href":"https://api.github.com/repos/grpc/grpc-java/pulls/1248"}}},"pull_request":{"url":"https://api.github.com/repos/grpc/grpc-java/pulls/1248","id":52603815,"html_url":"https://github.com/grpc/grpc-java/pull/1248","diff_url":"https://github.com/grpc/grpc-java/pull/1248.diff","patch_url":"https://github.com/grpc/grpc-java/pull/1248.patch","issue_url":"https://api.github.com/repos/grpc/grpc-java/issues/1248","number":1248,"state":"open","locked":false,"title":"Add cascading cancellation tests","user":{"login":"louiscryan","id":9046588,"avatar_url":"https://avatars.githubusercontent.com/u/9046588?v=3","gravatar_id":"","url":"https://api.github.com/users/louiscryan","html_url":"https://github.com/louiscryan","followers_url":"https://api.github.com/users/louiscryan/followers","following_url":"https://api.github.com/users/louiscryan/following{/other_user}","gists_url":"https://api.github.com/users/louiscryan/gists{/gist_id}","starred_url":"https://api.github.com/users/louiscryan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/louiscryan/subscriptions","organizations_url":"https://api.github.com/users/louiscryan/orgs","repos_url":"https://api.github.com/users/louiscryan/repos","events_url":"https://api.github.com/users/louiscryan/events{/privacy}","received_events_url":"https://api.github.com/users/louiscryan/received_events","type":"User","site_admin":false},"body":"Added some integration tests for cascading cancellation","created_at":"2015-12-03T22:38:42Z","updated_at":"2015-12-03T23:04:54Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fba1b71ee0d74fe640aabc47390f74d068dfa125","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/grpc/grpc-java/pulls/1248/commits","review_comments_url":"https://api.github.com/repos/grpc/grpc-java/pulls/1248/comments","review_comment_url":"https://api.github.com/repos/grpc/grpc-java/pulls/comments{/number}","comments_url":"https://api.github.com/repos/grpc/grpc-java/issues/1248/comments","statuses_url":"https://api.github.com/repos/grpc/grpc-java/statuses/8e8359640b8998238adbdbfc045d7fa5ffbc4791","head":{"label":"louiscryan:CascadingCancellationTests","ref":"CascadingCancellationTests","sha":"8e8359640b8998238adbdbfc045d7fa5ffbc4791","user":{"login":"louiscryan","id":9046588,"avatar_url":"https://avatars.githubusercontent.com/u/9046588?v=3","gravatar_id":"","url":"https://api.github.com/users/louiscryan","html_url":"https://github.com/louiscryan","followers_url":"https://api.github.com/users/louiscryan/followers","following_url":"https://api.github.com/users/louiscryan/following{/other_user}","gists_url":"https://api.github.com/users/louiscryan/gists{/gist_id}","starred_url":"https://api.github.com/users/louiscryan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/louiscryan/subscriptions","organizations_url":"https://api.github.com/users/louiscryan/orgs","repos_url":"https://api.github.com/users/louiscryan/repos","events_url":"https://api.github.com/users/louiscryan/events{/privacy}","received_events_url":"https://api.github.com/users/louiscryan/received_events","type":"User","site_admin":false},"repo":{"id":31382190,"name":"grpc-java","full_name":"louiscryan/grpc-java","owner":{"login":"louiscryan","id":9046588,"avatar_url":"https://avatars.githubusercontent.com/u/9046588?v=3","gravatar_id":"","url":"https://api.github.com/users/louiscryan","html_url":"https://github.com/louiscryan","followers_url":"https://api.github.com/users/louiscryan/followers","following_url":"https://api.github.com/users/louiscryan/following{/other_user}","gists_url":"https://api.github.com/users/louiscryan/gists{/gist_id}","starred_url":"https://api.github.com/users/louiscryan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/louiscryan/subscriptions","organizations_url":"https://api.github.com/users/louiscryan/orgs","repos_url":"https://api.github.com/users/louiscryan/repos","events_url":"https://api.github.com/users/louiscryan/events{/privacy}","received_events_url":"https://api.github.com/users/louiscryan/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/louiscryan/grpc-java","description":"The Java gRPC implementation. HTTP/2 based RPC","fork":true,"url":"https://api.github.com/repos/louiscryan/grpc-java","forks_url":"https://api.github.com/repos/louiscryan/grpc-java/forks","keys_url":"https://api.github.com/repos/louiscryan/grpc-java/keys{/key_id}","collaborators_url":"https://api.github.com/repos/louiscryan/grpc-java/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/louiscryan/grpc-java/teams","hooks_url":"https://api.github.com/repos/louiscryan/grpc-java/hooks","issue_events_url":"https://api.github.com/repos/louiscryan/grpc-java/issues/events{/number}","events_url":"https://api.github.com/repos/louiscryan/grpc-java/events","assignees_url":"https://api.github.com/repos/louiscryan/grpc-java/assignees{/user}","branches_url":"https://api.github.com/repos/louiscryan/grpc-java/branches{/branch}","tags_url":"https://api.github.com/repos/louiscryan/grpc-java/tags","blobs_url":"https://api.github.com/repos/louiscryan/grpc-java/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/louiscryan/grpc-java/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/louiscryan/grpc-java/git/refs{/sha}","trees_url":"https://api.github.com/repos/louiscryan/grpc-java/git/trees{/sha}","statuses_url":"https://api.github.com/repos/louiscryan/grpc-java/statuses/{sha}","languages_url":"https://api.github.com/repos/louiscryan/grpc-java/languages","stargazers_url":"https://api.github.com/repos/louiscryan/grpc-java/stargazers","contributors_url":"https://api.github.com/repos/louiscryan/grpc-java/contributors","subscribers_url":"https://api.github.com/repos/louiscryan/grpc-java/subscribers","subscription_url":"https://api.github.com/repos/louiscryan/grpc-java/subscription","commits_url":"https://api.github.com/repos/louiscryan/grpc-java/commits{/sha}","git_commits_url":"https://api.github.com/repos/louiscryan/grpc-java/git/commits{/sha}","comments_url":"https://api.github.com/repos/louiscryan/grpc-java/comments{/number}","issue_comment_url":"https://api.github.com/repos/louiscryan/grpc-java/issues/comments{/number}","contents_url":"https://api.github.com/repos/louiscryan/grpc-java/contents/{+path}","compare_url":"https://api.github.com/repos/louiscryan/grpc-java/compare/{base}...{head}","merges_url":"https://api.github.com/repos/louiscryan/grpc-java/merges","archive_url":"https://api.github.com/repos/louiscryan/grpc-java/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/louiscryan/grpc-java/downloads","issues_url":"https://api.github.com/repos/louiscryan/grpc-java/issues{/number}","pulls_url":"https://api.github.com/repos/louiscryan/grpc-java/pulls{/number}","milestones_url":"https://api.github.com/repos/louiscryan/grpc-java/milestones{/number}","notifications_url":"https://api.github.com/repos/louiscryan/grpc-java/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/louiscryan/grpc-java/labels{/name}","releases_url":"https://api.github.com/repos/louiscryan/grpc-java/releases{/id}","created_at":"2015-02-26T18:33:49Z","updated_at":"2015-05-01T20:01:16Z","pushed_at":"2015-12-03T22:34:46Z","git_url":"git://github.com/louiscryan/grpc-java.git","ssh_url":"git@github.com:louiscryan/grpc-java.git","clone_url":"https://github.com/louiscryan/grpc-java.git","svn_url":"https://github.com/louiscryan/grpc-java","homepage":"","size":4676,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"grpc:master","ref":"master","sha":"a1ed98fbaecb29ef84288df13ae08184a8ca0374","user":{"login":"grpc","id":7802525,"avatar_url":"https://avatars.githubusercontent.com/u/7802525?v=3","gravatar_id":"","url":"https://api.github.com/users/grpc","html_url":"https://github.com/grpc","followers_url":"https://api.github.com/users/grpc/followers","following_url":"https://api.github.com/users/grpc/following{/other_user}","gists_url":"https://api.github.com/users/grpc/gists{/gist_id}","starred_url":"https://api.github.com/users/grpc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grpc/subscriptions","organizations_url":"https://api.github.com/users/grpc/orgs","repos_url":"https://api.github.com/users/grpc/repos","events_url":"https://api.github.com/users/grpc/events{/privacy}","received_events_url":"https://api.github.com/users/grpc/received_events","type":"Organization","site_admin":false},"repo":{"id":27729926,"name":"grpc-java","full_name":"grpc/grpc-java","owner":{"login":"grpc","id":7802525,"avatar_url":"https://avatars.githubusercontent.com/u/7802525?v=3","gravatar_id":"","url":"https://api.github.com/users/grpc","html_url":"https://github.com/grpc","followers_url":"https://api.github.com/users/grpc/followers","following_url":"https://api.github.com/users/grpc/following{/other_user}","gists_url":"https://api.github.com/users/grpc/gists{/gist_id}","starred_url":"https://api.github.com/users/grpc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/grpc/subscriptions","organizations_url":"https://api.github.com/users/grpc/orgs","repos_url":"https://api.github.com/users/grpc/repos","events_url":"https://api.github.com/users/grpc/events{/privacy}","received_events_url":"https://api.github.com/users/grpc/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/grpc/grpc-java","description":"The Java gRPC implementation. HTTP/2 based RPC","fork":false,"url":"https://api.github.com/repos/grpc/grpc-java","forks_url":"https://api.github.com/repos/grpc/grpc-java/forks","keys_url":"https://api.github.com/repos/grpc/grpc-java/keys{/key_id}","collaborators_url":"https://api.github.com/repos/grpc/grpc-java/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/grpc/grpc-java/teams","hooks_url":"https://api.github.com/repos/grpc/grpc-java/hooks","issue_events_url":"https://api.github.com/repos/grpc/grpc-java/issues/events{/number}","events_url":"https://api.github.com/repos/grpc/grpc-java/events","assignees_url":"https://api.github.com/repos/grpc/grpc-java/assignees{/user}","branches_url":"https://api.github.com/repos/grpc/grpc-java/branches{/branch}","tags_url":"https://api.github.com/repos/grpc/grpc-java/tags","blobs_url":"https://api.github.com/repos/grpc/grpc-java/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/grpc/grpc-java/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/grpc/grpc-java/git/refs{/sha}","trees_url":"https://api.github.com/repos/grpc/grpc-java/git/trees{/sha}","statuses_url":"https://api.github.com/repos/grpc/grpc-java/statuses/{sha}","languages_url":"https://api.github.com/repos/grpc/grpc-java/languages","stargazers_url":"https://api.github.com/repos/grpc/grpc-java/stargazers","contributors_url":"https://api.github.com/repos/grpc/grpc-java/contributors","subscribers_url":"https://api.github.com/repos/grpc/grpc-java/subscribers","subscription_url":"https://api.github.com/repos/grpc/grpc-java/subscription","commits_url":"https://api.github.com/repos/grpc/grpc-java/commits{/sha}","git_commits_url":"https://api.github.com/repos/grpc/grpc-java/git/commits{/sha}","comments_url":"https://api.github.com/repos/grpc/grpc-java/comments{/number}","issue_comment_url":"https://api.github.com/repos/grpc/grpc-java/issues/comments{/number}","contents_url":"https://api.github.com/repos/grpc/grpc-java/contents/{+path}","compare_url":"https://api.github.com/repos/grpc/grpc-java/compare/{base}...{head}","merges_url":"https://api.github.com/repos/grpc/grpc-java/merges","archive_url":"https://api.github.com/repos/grpc/grpc-java/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/grpc/grpc-java/downloads","issues_url":"https://api.github.com/repos/grpc/grpc-java/issues{/number}","pulls_url":"https://api.github.com/repos/grpc/grpc-java/pulls{/number}","milestones_url":"https://api.github.com/repos/grpc/grpc-java/milestones{/number}","notifications_url":"https://api.github.com/repos/grpc/grpc-java/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/grpc/grpc-java/labels{/name}","releases_url":"https://api.github.com/repos/grpc/grpc-java/releases{/id}","created_at":"2014-12-08T19:00:00Z","updated_at":"2015-12-03T18:05:54Z","pushed_at":"2015-12-03T22:38:42Z","git_url":"git://github.com/grpc/grpc-java.git","ssh_url":"git@github.com:grpc/grpc-java.git","clone_url":"https://github.com/grpc/grpc-java.git","svn_url":"https://github.com/grpc/grpc-java","homepage":"","size":19120,"stargazers_count":1002,"watchers_count":1002,"language":"Java","has_issues":true,"has_downloads":false,"has_wiki":false,"has_pages":true,"forks_count":256,"mirror_url":null,"open_issues_count":107,"forks":256,"open_issues":107,"watchers":1002,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/grpc/grpc-java/pulls/1248"},"html":{"href":"https://github.com/grpc/grpc-java/pull/1248"},"issue":{"href":"https://api.github.com/repos/grpc/grpc-java/issues/1248"},"comments":{"href":"https://api.github.com/repos/grpc/grpc-java/issues/1248/comments"},"review_comments":{"href":"https://api.github.com/repos/grpc/grpc-java/pulls/1248/comments"},"review_comment":{"href":"https://api.github.com/repos/grpc/grpc-java/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/grpc/grpc-java/pulls/1248/commits"},"statuses":{"href":"https://api.github.com/repos/grpc/grpc-java/statuses/8e8359640b8998238adbdbfc045d7fa5ffbc4791"}}}}