Merge pull request #10609 from makdharma/xcodebuild_cmdline

add cmdline arg for ObjC interop tests. Add objc to interop_tests.py
diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m
index 94cdf85..cdcdd8a 100644
--- a/src/objective-c/tests/InteropTestsLocalCleartext.m
+++ b/src/objective-c/tests/InteropTestsLocalCleartext.m
@@ -36,7 +36,11 @@
 
 #import "InteropTests.h"
 
-static NSString * const kLocalCleartextHost = @"localhost:5050";
+// The server address is derived from preprocessor macro, which is
+// in turn derived from environment variable of the same name.
+#define NSStringize_helper(x) #x
+#define NSStringize(x) @NSStringize_helper(x)
+static NSString * const kLocalCleartextHost = NSStringize(HOST_PORT_LOCAL);
 
 // The Protocol Buffers encoding overhead of local interop server. Acquired
 // by experiment. Adjust this when server's proto file changes.
diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m
index 3c78b65..45e62d2 100644
--- a/src/objective-c/tests/InteropTestsLocalSSL.m
+++ b/src/objective-c/tests/InteropTestsLocalSSL.m
@@ -35,8 +35,11 @@
 #import <GRPCClient/internal_testing/GRPCCall+InternalTests.h>
 
 #import "InteropTests.h"
-
-static NSString * const kLocalSSLHost = @"localhost:5051";
+// The server address is derived from preprocessor macro, which is
+// in turn derived from environment variable of the same name.
+#define NSStringize_helper(x) #x
+#define NSStringize(x) @NSStringize_helper(x)
+static NSString * const kLocalSSLHost = NSStringize(HOST_PORT_LOCALSSL);
 
 // The Protocol Buffers encoding overhead of local interop server. Acquired
 // by experiment. Adjust this when server's proto file changes.
diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m
index ff11933..5260fe4 100644
--- a/src/objective-c/tests/InteropTestsRemote.m
+++ b/src/objective-c/tests/InteropTestsRemote.m
@@ -36,7 +36,11 @@
 
 #import "InteropTests.h"
 
-static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
+// The server address is derived from preprocessor macro, which is
+// in turn derived from environment variable of the same name.
+#define NSStringize_helper(x) #x
+#define NSStringize(x) @NSStringize_helper(x)
+static NSString * const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
 
 // The Protocol Buffers encoding overhead of remote interop server. Acquired
 // by experiment. Adjust this when server's proto file changes.
diff --git a/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
index 9edfbc2..a7f190d 100644
--- a/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
+++ b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
@@ -39,7 +39,12 @@
 
 #import "InteropTests.h"
 
-static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
+// The server address is derived from preprocessor macro, which is
+// in turn derived from environment variable of the same name.
+#define NSStringize_helper(x) #x
+#define NSStringize(x) @NSStringize_helper(x)
+static NSString * const kRemoteSSLHost = NSStringize(HOST_PORT_REMOTE);
+
 
 // The Protocol Buffers encoding overhead of remote interop server. Acquired
 // by experiment. Adjust this when server's proto file changes.
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index 97de723..b01d5ff 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -1282,6 +1282,9 @@
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"$(inherited)",
+					"HOST_PORT_LOCALSSL=$(HOST_PORT_LOCALSSL)",
+					"HOST_PORT_LOCAL=$(HOST_PORT_LOCAL)",
+					"HOST_PORT_REMOTE=$(HOST_PORT_REMOTE)",
 				);
 				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
 				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
@@ -1565,6 +1568,7 @@
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"$(inherited)",
+					"HOST_PORT_REMOTE=$(HOST_PORT_REMOTE)",
 				);
 				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
 				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
index 0e82bca..2432209 100755
--- a/src/objective-c/tests/run_tests.sh
+++ b/src/objective-c/tests/run_tests.sh
@@ -59,6 +59,9 @@
     -workspace Tests.xcworkspace \
     -scheme AllTests \
     -destination name="iPhone 6" \
+    HOST_PORT_LOCALSSL=localhost:5051 \
+    HOST_PORT_LOCAL=localhost:5050 \
+    HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
     test | xcpretty
 
 echo "TIME:  $(date)"
@@ -84,4 +87,5 @@
     -workspace Tests.xcworkspace \
     -scheme InteropTestsRemoteWithCronet \
     -destination name="iPhone 6" \
+    HOST_PORT_REMOTE=grpc-test.sandbox.googleapis.com \
     test | xcpretty
diff --git a/tools/jenkins/run_interop_objc.sh b/tools/jenkins/run_interop_objc.sh
new file mode 100755
index 0000000..29f9ac9
--- /dev/null
+++ b/tools/jenkins/run_interop_objc.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+# Copyright 2017, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# This script is invoked by Jenkins and runs interop test suite.
+set -ex
+
+export LANG=en_US.UTF-8
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../..
+
+tools/run_tests/run_interop_tests.py -l objc -s all --use_docker -t -j 1 $@ || true
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index d2bf529..44e93eb 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -371,6 +371,39 @@
   def __str__(self):
     return 'php7'
 
+class ObjcLanguage:
+
+  def __init__(self):
+    self.client_cwd = 'src/objective-c/tests'
+    self.safename = str(self)
+
+  def client_cmd(self, args):
+    # from args, extract the server port and craft xcodebuild command out of it
+    for arg in args:
+      port = re.search('--server_port=(\d+)', arg)
+      if port:
+        portnum = port.group(1)
+        cmdline = 'pod install && xcodebuild -workspace Tests.xcworkspace -scheme InteropTestsLocalSSL -destination name="iPhone 6" HOST_PORT_LOCALSSL=localhost:%s test'%portnum
+        return [cmdline]
+
+  def cloud_to_prod_env(self):
+    return {}
+
+  def global_env(self):
+    return {}
+
+  def unimplemented_test_cases(self):
+    # ObjC test runs all cases with the same command. It ignores the testcase
+    # cmdline argument. Here we return all but one test cases as unimplemented,
+    # and depend upon ObjC test's behavior that it runs all cases even when
+    # we tell it to run just one.
+    return _TEST_CASES[1:] + _SKIP_COMPRESSION + _SKIP_DATA_FRAME_PADDING
+
+  def unimplemented_test_cases_server(self):
+    return _SKIP_COMPRESSION
+
+  def __str__(self):
+    return 'objc'
 
 class RubyLanguage:
 
@@ -402,7 +435,6 @@
   def __str__(self):
     return 'ruby'
 
-
 class PythonLanguage:
 
   def __init__(self):
@@ -460,6 +492,7 @@
     'node' : NodeLanguage(),
     'php' :  PHPLanguage(),
     'php7' :  PHP7Language(),
+    'objc' : ObjcLanguage(),
     'ruby' : RubyLanguage(),
     'python' : PythonLanguage(),
 }
@@ -667,7 +700,8 @@
     cwd = language.client_cwd
 
   environ = language.global_env()
-  if docker_image:
+  if docker_image and language.safename != 'objc':
+    # we can't run client in docker for objc.
     container_name = dockerjob.random_name('interop_client_%s' % language.safename)
     cmdline = docker_run_cmdline(cmdline,
                                  image=docker_image,
@@ -820,7 +854,7 @@
                   choices=['all'] + sorted(_LANGUAGES),
                   nargs='+',
                   default=['all'],
-                  help='Clients to run.')
+                  help='Clients to run. Objc client can be only run on OSX.')
 argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
 argp.add_argument('--cloud_to_prod',
                   default=False,
@@ -913,9 +947,13 @@
   print('Running interop servers is only supported with --use_docker option enabled.')
   sys.exit(1)
 
+
+# we want to include everything but objc in 'all'
+# because objc won't run on non-mac platforms
+all_but_objc = set(six.iterkeys(_LANGUAGES)) - set(['objc'])
 languages = set(_LANGUAGES[l]
                 for l in itertools.chain.from_iterable(
-                    six.iterkeys(_LANGUAGES) if x == 'all' else [x]
+                    all_but_objc if x == 'all' else [x]
                     for x in args.language))
 
 languages_http2_clients_for_http2_server_interop = set()
@@ -942,6 +980,9 @@
 
   build_jobs = []
   for l in languages_to_build:
+    if str(l) == 'objc':
+      # we don't need to build a docker image for objc
+      continue
     job = build_interop_image_jobspec(l)
     docker_images[str(l)] = job.tag
     build_jobs.append(job)