diff options
Diffstat (limited to 'src/objective-c/tests')
27 files changed, 1323 insertions, 712 deletions
diff --git a/src/objective-c/tests/Connectivity/Base.lproj/Main.storyboard b/src/objective-c/tests/Connectivity/Base.lproj/Main.storyboard deleted file mode 100644 index 9a05b8635d..0000000000 --- a/src/objective-c/tests/Connectivity/Base.lproj/Main.storyboard +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11129.15" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> - <dependencies> - <deployment identifier="iOS"/> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11103.10"/> - </dependencies> - <scenes> - <!--View Controller--> - <scene sceneID="tne-QT-ifu"> - <objects> - <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"/> - <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> - </objects> - </scene> - </scenes> -</document> diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj b/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj index 3f26c98564..6a4c3519d6 100644 --- a/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp.xcodeproj/project.pbxproj @@ -3,90 +3,104 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 48; objects = { /* Begin PBXBuildFile section */ - 500A4E0AC9D489EB214D1ED4 /* libPods-ConnectivityTestingApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C2AF815D8242A2172891621D /* libPods-ConnectivityTestingApp.a */; }; - 63BFB9CC1D2478DD00E17927 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 63BFB9CB1D2478DD00E17927 /* main.m */; }; - 63BFB9D21D2478DD00E17927 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63BFB9D11D2478DD00E17927 /* ViewController.m */; }; - 63BFB9D51D2478DD00E17927 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63BFB9D31D2478DD00E17927 /* Main.storyboard */; }; + 5EC49F992043E46B00ED189A /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EC49F982043E46B00ED189A /* ViewController.m */; }; + 5EC49F9C2043E46B00ED189A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EC49F9A2043E46B00ED189A /* Main.storyboard */; }; + 5EC49F9E2043E46B00ED189A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5EC49F9D2043E46B00ED189A /* Assets.xcassets */; }; + 5EC49FA12043E46B00ED189A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EC49F9F2043E46B00ED189A /* LaunchScreen.storyboard */; }; + 5EC49FA42043E46B00ED189A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EC49FA32043E46B00ED189A /* main.m */; }; + DDCBF00DB326F4FA4706953C /* libPods-ConnectivityTestingApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EF1DD1BF13CC3E1BDA1A1089 /* libPods-ConnectivityTestingApp.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 63BFB9C71D2478DD00E17927 /* ConnectivityTestingApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ConnectivityTestingApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 63BFB9CB1D2478DD00E17927 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; }; - 63BFB9D11D2478DD00E17927 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = SOURCE_ROOT; }; - 63BFB9D41D2478DD00E17927 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; - 63BFB9DB1D2478DD00E17927 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; - BA96CBC1612BD2F70E66246C /* Pods-ConnectivityTestingApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.release.xcconfig"; sourceTree = "<group>"; }; - C2AF815D8242A2172891621D /* libPods-ConnectivityTestingApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ConnectivityTestingApp.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - FC9BD3AE427396EDB4CD13E3 /* Pods-ConnectivityTestingApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.debug.xcconfig"; sourceTree = "<group>"; }; + 5EC49F912043E46B00ED189A /* ConnectivityTestingApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ConnectivityTestingApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5EC49F982043E46B00ED189A /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; + 5EC49F9B2043E46B00ED189A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; + 5EC49F9D2043E46B00ED189A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; + 5EC49FA02043E46B00ED189A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; + 5EC49FA22043E46B00ED189A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; + 5EC49FA32043E46B00ED189A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; + 69B8F09A730364513700F23C /* Pods-ConnectivityTestingApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.release.xcconfig"; sourceTree = "<group>"; }; + A16A6C6AAAC10A09DFF329F2 /* Pods-ConnectivityTestingApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ConnectivityTestingApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp.debug.xcconfig"; sourceTree = "<group>"; }; + EF1DD1BF13CC3E1BDA1A1089 /* libPods-ConnectivityTestingApp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ConnectivityTestingApp.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 63BFB9C41D2478DD00E17927 /* Frameworks */ = { + 5EC49F8E2043E46B00ED189A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 500A4E0AC9D489EB214D1ED4 /* libPods-ConnectivityTestingApp.a in Frameworks */, + DDCBF00DB326F4FA4706953C /* libPods-ConnectivityTestingApp.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 16E6C67F2E48B42376DFFD2A /* Pods */ = { + 1AAFFD715A6EF1FEBF5AD796 /* Pods */ = { isa = PBXGroup; children = ( - FC9BD3AE427396EDB4CD13E3 /* Pods-ConnectivityTestingApp.debug.xcconfig */, - BA96CBC1612BD2F70E66246C /* Pods-ConnectivityTestingApp.release.xcconfig */, + A16A6C6AAAC10A09DFF329F2 /* Pods-ConnectivityTestingApp.debug.xcconfig */, + 69B8F09A730364513700F23C /* Pods-ConnectivityTestingApp.release.xcconfig */, ); name = Pods; sourceTree = "<group>"; }; - 48F8EC18C66D3416A41F76F5 /* Frameworks */ = { + 5EC49F882043E46B00ED189A = { isa = PBXGroup; children = ( - C2AF815D8242A2172891621D /* libPods-ConnectivityTestingApp.a */, + 5EC49F932043E46B00ED189A /* ConnectivityTestingApp */, + 5EC49F922043E46B00ED189A /* Products */, + 1AAFFD715A6EF1FEBF5AD796 /* Pods */, + 99E308FECF6991F75249AD00 /* Frameworks */, ); - name = Frameworks; sourceTree = "<group>"; }; - 63BFB9BE1D2478DD00E17927 = { + 5EC49F922043E46B00ED189A /* Products */ = { isa = PBXGroup; children = ( - 63BFB9D11D2478DD00E17927 /* ViewController.m */, - 63BFB9D31D2478DD00E17927 /* Main.storyboard */, - 63BFB9DB1D2478DD00E17927 /* Info.plist */, - 63BFB9CB1D2478DD00E17927 /* main.m */, - 63BFB9C81D2478DD00E17927 /* Products */, - 16E6C67F2E48B42376DFFD2A /* Pods */, - 48F8EC18C66D3416A41F76F5 /* Frameworks */, + 5EC49F912043E46B00ED189A /* ConnectivityTestingApp.app */, ); + name = Products; sourceTree = "<group>"; }; - 63BFB9C81D2478DD00E17927 /* Products */ = { + 5EC49F932043E46B00ED189A /* ConnectivityTestingApp */ = { isa = PBXGroup; children = ( - 63BFB9C71D2478DD00E17927 /* ConnectivityTestingApp.app */, + 5EC49F982043E46B00ED189A /* ViewController.m */, + 5EC49F9A2043E46B00ED189A /* Main.storyboard */, + 5EC49F9D2043E46B00ED189A /* Assets.xcassets */, + 5EC49F9F2043E46B00ED189A /* LaunchScreen.storyboard */, + 5EC49FA22043E46B00ED189A /* Info.plist */, + 5EC49FA32043E46B00ED189A /* main.m */, ); - name = Products; + path = ConnectivityTestingApp; + sourceTree = "<group>"; + }; + 99E308FECF6991F75249AD00 /* Frameworks */ = { + isa = PBXGroup; + children = ( + EF1DD1BF13CC3E1BDA1A1089 /* libPods-ConnectivityTestingApp.a */, + ); + name = Frameworks; sourceTree = "<group>"; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 63BFB9C61D2478DD00E17927 /* ConnectivityTestingApp */ = { + 5EC49F902043E46B00ED189A /* ConnectivityTestingApp */ = { isa = PBXNativeTarget; - buildConfigurationList = 63BFB9DE1D2478DD00E17927 /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */; + buildConfigurationList = 5EC49FA72043E46B00ED189A /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */; buildPhases = ( - 4DCA2703A0AA5DC1BD2751B8 /* [CP] Check Pods Manifest.lock */, - 63BFB9C31D2478DD00E17927 /* Sources */, - 63BFB9C41D2478DD00E17927 /* Frameworks */, - 63BFB9C51D2478DD00E17927 /* Resources */, - 8593A2388A8F7BF5A7E98D26 /* [CP] Embed Pods Frameworks */, - 5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */, + 7CABF198C569A04592862390 /* [CP] Check Pods Manifest.lock */, + 5EC49F8D2043E46B00ED189A /* Sources */, + 5EC49F8E2043E46B00ED189A /* Frameworks */, + 5EC49F8F2043E46B00ED189A /* Resources */, + 9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */, + 735516C793AF7394FBB83B7F /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -94,87 +108,93 @@ ); name = ConnectivityTestingApp; productName = ConnectivityTestingApp; - productReference = 63BFB9C71D2478DD00E17927 /* ConnectivityTestingApp.app */; + productReference = 5EC49F912043E46B00ED189A /* ConnectivityTestingApp.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 63BFB9BF1D2478DD00E17927 /* Project object */ = { + 5EC49F892043E46B00ED189A /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0800; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = gRPC; TargetAttributes = { - 63BFB9C61D2478DD00E17927 = { - CreatedOnToolsVersion = 8.0; - DevelopmentTeam = EQHXZ8M8AV; - DevelopmentTeamName = "Google, Inc."; - ProvisioningStyle = Automatic; + 5EC49F902043E46B00ED189A = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; }; }; }; - buildConfigurationList = 63BFB9C21D2478DD00E17927 /* Build configuration list for PBXProject "ConnectivityTestingApp" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + buildConfigurationList = 5EC49F8C2043E46B00ED189A /* Build configuration list for PBXProject "ConnectivityTestingApp" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); - mainGroup = 63BFB9BE1D2478DD00E17927; - productRefGroup = 63BFB9C81D2478DD00E17927 /* Products */; + mainGroup = 5EC49F882043E46B00ED189A; + productRefGroup = 5EC49F922043E46B00ED189A /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 63BFB9C61D2478DD00E17927 /* ConnectivityTestingApp */, + 5EC49F902043E46B00ED189A /* ConnectivityTestingApp */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 63BFB9C51D2478DD00E17927 /* Resources */ = { + 5EC49F8F2043E46B00ED189A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 63BFB9D51D2478DD00E17927 /* Main.storyboard in Resources */, + 5EC49FA12043E46B00ED189A /* LaunchScreen.storyboard in Resources */, + 5EC49F9E2043E46B00ED189A /* Assets.xcassets in Resources */, + 5EC49F9C2043E46B00ED189A /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 4DCA2703A0AA5DC1BD2751B8 /* [CP] Check Pods Manifest.lock */ = { + 735516C793AF7394FBB83B7F /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Copy Pods Resources"; outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 5347BF6C41E7888C1C05CD88 /* [CP] Copy Pods Resources */ = { + 7CABF198C569A04592862390 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Copy Pods Resources"; + name = "[CP] Check Pods Manifest.lock"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-ConnectivityTestingApp-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ConnectivityTestingApp/Pods-ConnectivityTestingApp-resources.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 8593A2388A8F7BF5A7E98D26 /* [CP] Embed Pods Frameworks */ = { + 9F67C72B6B6BAF2781078886 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -192,55 +212,72 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 63BFB9C31D2478DD00E17927 /* Sources */ = { + 5EC49F8D2043E46B00ED189A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 63BFB9D21D2478DD00E17927 /* ViewController.m in Sources */, - 63BFB9CC1D2478DD00E17927 /* main.m in Sources */, + 5EC49F992043E46B00ED189A /* ViewController.m in Sources */, + 5EC49FA42043E46B00ED189A /* main.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - 63BFB9D31D2478DD00E17927 /* Main.storyboard */ = { + 5EC49F9A2043E46B00ED189A /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( - 63BFB9D41D2478DD00E17927 /* Base */, + 5EC49F9B2043E46B00ED189A /* Base */, ); name = Main.storyboard; - path = .; - sourceTree = SOURCE_ROOT; + sourceTree = "<group>"; + }; + 5EC49F9F2043E46B00ED189A /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5EC49FA02043E46B00ED189A /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = "<group>"; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 63BFB9DC1D2478DD00E17927 /* Debug */ = { + 5EC49FA52043E46B00ED189A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; @@ -254,38 +291,48 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; - 63BFB9DD1D2478DD00E17927 /* Release */ = { + 5EC49FA62043E46B00ED189A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -293,61 +340,71 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; - 63BFB9DF1D2478DD00E17927 /* Debug */ = { + 5EC49FA82043E46B00ED189A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = FC9BD3AE427396EDB4CD13E3 /* Pods-ConnectivityTestingApp.debug.xcconfig */; + baseConfigurationReference = A16A6C6AAAC10A09DFF329F2 /* Pods-ConnectivityTestingApp.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.3; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = EQHXZ8M8AV; + INFOPLIST_FILE = ConnectivityTestingApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ConnectivityTestingApp; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "aa306b73-1a89-4299-8ead-c102fd059d96"; + PROVISIONING_PROFILE_SPECIFIER = "Google Development"; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ../../../..; }; name = Debug; }; - 63BFB9E01D2478DD00E17927 /* Release */ = { + 5EC49FA92043E46B00ED189A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BA96CBC1612BD2F70E66246C /* Pods-ConnectivityTestingApp.release.xcconfig */; + baseConfigurationReference = 69B8F09A730364513700F23C /* Pods-ConnectivityTestingApp.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - INFOPLIST_FILE = Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 9.3; + CODE_SIGN_STYLE = Manual; + DEVELOPMENT_TEAM = EQHXZ8M8AV; + INFOPLIST_FILE = ConnectivityTestingApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = io.grpc.ConnectivityTestingApp; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = "aa306b73-1a89-4299-8ead-c102fd059d96"; + PROVISIONING_PROFILE_SPECIFIER = "Google Development"; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = ../../../..; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 63BFB9C21D2478DD00E17927 /* Build configuration list for PBXProject "ConnectivityTestingApp" */ = { + 5EC49F8C2043E46B00ED189A /* Build configuration list for PBXProject "ConnectivityTestingApp" */ = { isa = XCConfigurationList; buildConfigurations = ( - 63BFB9DC1D2478DD00E17927 /* Debug */, - 63BFB9DD1D2478DD00E17927 /* Release */, + 5EC49FA52043E46B00ED189A /* Debug */, + 5EC49FA62043E46B00ED189A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 63BFB9DE1D2478DD00E17927 /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */ = { + 5EC49FA72043E46B00ED189A /* Build configuration list for PBXNativeTarget "ConnectivityTestingApp" */ = { isa = XCConfigurationList; buildConfigurations = ( - 63BFB9DF1D2478DD00E17927 /* Debug */, - 63BFB9E01D2478DD00E17927 /* Release */, + 5EC49FA82043E46B00ED189A /* Debug */, + 5EC49FA92043E46B00ED189A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; - rootObject = 63BFB9BF1D2478DD00E17927 /* Project object */; + rootObject = 5EC49F892043E46B00ED189A /* Project object */; } diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..1d060ed288 --- /dev/null +++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,93 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +}
\ No newline at end of file diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/LaunchScreen.storyboard b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..60a0921351 --- /dev/null +++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> + <device id="retina4_7" orientation="portrait"> + <adaptation id="fullscreen"/> + </device> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="EHf-IW-A2E"> + <objects> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="q3l-Ud-sIn"> + <rect key="frame" x="167" y="131" width="41" height="30"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <state key="normal" title="Unary"/> + </button> + <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RfU-eq-cee"> + <rect key="frame" x="152" y="220" width="70" height="30"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <state key="normal" title="Streaming"/> + </button> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="53" y="375"/> + </scene> + </scenes> +</document> diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/Main.storyboard b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..1b4e0d050c --- /dev/null +++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Base.lproj/Main.storyboard @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> + <device id="retina4_7" orientation="portrait"> + <adaptation id="fullscreen"/> + </device> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="tne-QT-ifu"> + <objects> + <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8QE-go-1ZJ"> + <rect key="frame" x="168" y="160" width="41" height="30"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <state key="normal" title="Unary"/> + <connections> + <action selector="tapUnary:" destination="BYZ-38-t0r" eventType="touchUpInside" id="OGf-25-OYx"/> + </connections> + </button> + <button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="p4l-br-UUo"> + <rect key="frame" x="153" y="229" width="70" height="30"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <state key="normal" title="Streaming"/> + <connections> + <action selector="tapStreaming:" destination="BYZ-38-t0r" eventType="touchUpInside" id="S3O-W8-Fed"/> + </connections> + </button> + </subviews> + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> + </objects> + </scene> + </scenes> +</document> diff --git a/src/objective-c/tests/Connectivity/Info.plist b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Info.plist index 8a9fb88701..16be3b6811 100644 --- a/src/objective-c/tests/Connectivity/Info.plist +++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/Info.plist @@ -3,7 +3,7 @@ <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> - <string>en</string> + <string>$(DEVELOPMENT_LANGUAGE)</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> @@ -16,14 +16,12 @@ <string>APPL</string> <key>CFBundleShortVersionString</key> <string>1.0</string> - <key>CFBundleSignature</key> - <string>????</string> <key>CFBundleVersion</key> <string>1</string> <key>LSRequiresIPhoneOS</key> <true/> <key>UILaunchStoryboardName</key> - <string>Main</string> + <string>LaunchScreen</string> <key>UIMainStoryboardFile</key> <string>Main</string> <key>UIRequiredDeviceCapabilities</key> @@ -36,5 +34,12 @@ <string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeRight</string> </array> + <key>UISupportedInterfaceOrientations~ipad</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationPortraitUpsideDown</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> </dict> </plist> diff --git a/src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m new file mode 100644 index 0000000000..88780e39f0 --- /dev/null +++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/ViewController.m @@ -0,0 +1,97 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * 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. + * + */ + +#import <UIKit/UIKit.h> + +#import <GRPCClient/GRPCCall.h> +#import <ProtoRPC/ProtoMethod.h> +#import <RxLibrary/GRXBufferedPipe.h> +#import <RxLibrary/GRXWriter+Immediate.h> +#import <RxLibrary/GRXWriter+Transformations.h> + +#import "src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h" + +NSString *host = @"grpc-test.sandbox.googleapis.com"; + +@interface ViewController : UIViewController +@end + +@implementation ViewController +- (void)viewDidLoad { + [super viewDidLoad]; + + [GRPCConnectivityMonitor registerObserver:self selector:@selector(reachabilityChanged:)]; +} + +- (void)reachabilityChanged:(NSNotification *)note { + NSLog(@"Reachability changed\n"); +} + +- (IBAction)tapUnary:(id)sender { + // Create a unary call + + // A trivial proto message to generate a response + char bytes[] = {0x10, 0x05, 0x1A, 0x07, 0x12, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}; + + GRPCProtoMethod *method = [[GRPCProtoMethod alloc] initWithPackage:@"grpc.testing" + service:@"TestService" + method:@"UnaryCall"]; + GRXWriter *loggingRequestWriter = [[GRXWriter + writerWithValue:[NSData dataWithBytes:bytes length:sizeof(bytes)]] map:^id(id value) { + NSLog(@"Sending request."); + return value; + }]; + GRPCCall *call = + [[GRPCCall alloc] initWithHost:host path:method.HTTPPath requestsWriter:loggingRequestWriter]; + + [call startWithWriteable:[GRXWriteable + writeableWithEventHandler:^(BOOL done, id value, NSError *error) { + if (!done) { + return; + } + NSLog(@"Unary call finished with error: %@", error); + }]]; +} + +- (IBAction)tapStreaming:(id)sender { + // Create a streaming call + + // A trivial proto message to generate a response + char bytes[] = {0x12, 0x02, 0x08, 0x02, 0x1A, 0x04, 0x12, 0x02, 0x00, 0x00}; + + GRPCProtoMethod *method = [[GRPCProtoMethod alloc] initWithPackage:@"grpc.testing" + service:@"TestService" + method:@"FullDuplexCall"]; + + GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init]; + + [requestsBuffer writeValue:[NSData dataWithBytes:bytes length:sizeof(bytes)]]; + + GRPCCall *call = + [[GRPCCall alloc] initWithHost:host path:method.HTTPPath requestsWriter:requestsBuffer]; + + [call startWithWriteable:[GRXWriteable + writeableWithEventHandler:^(BOOL done, id value, NSError *error) { + if (!done) { + return; + } + NSLog(@"Streaming call finished with error: %@", error); + }]]; +} + +@end diff --git a/src/objective-c/tests/Connectivity/main.m b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/main.m index 1642fdb2c6..010789e8ab 100644 --- a/src/objective-c/tests/Connectivity/main.m +++ b/src/objective-c/tests/Connectivity/ConnectivityTestingApp/main.m @@ -18,14 +18,14 @@ #import <UIKit/UIKit.h> -@interface AppDelegate : UIResponder <UIApplicationDelegate> -@property (strong, nonatomic) UIWindow *window; +@interface AppDelegate : UIResponder<UIApplicationDelegate> +@property(strong, nonatomic) UIWindow *window; @end @implementation AppDelegate @end -int main(int argc, char * argv[]) { +int main(int argc, char *argv[]) { @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass(AppDelegate.class)); + return UIApplicationMain(argc, argv, nil, NSStringFromClass(AppDelegate.class)); } } diff --git a/src/objective-c/tests/Connectivity/README.md b/src/objective-c/tests/Connectivity/README.md index 851cb9d1da..907821e800 100644 --- a/src/objective-c/tests/Connectivity/README.md +++ b/src/objective-c/tests/Connectivity/README.md @@ -2,14 +2,12 @@ This app can be used to manually test gRPC under changing network conditions. It makes RPCs in a loop, logging when the request is sent and the response is received. -To test on the simulator, run `pod install`, open the workspace created by Cocoapods, and run the app. -Once running, disable WiFi (or ethernet) _in your computer_, then enable it again after a while. Don't -bother with the simulator's WiFi or cell settings, as they have no effect: Simulator apps are just Mac -apps running within the simulator UI. +To test on the simulator, run `pod install`, open the workspace created by Cocoapods, and run the +app on an iOS device. Once running, tap a few times of each of the two buttons to make a few unary and streaming +calls. Then disable/enable different network interfaces (WiFi, cellular) on your device. -The expected result is to never see a "hanged" RPC: success or failure should happen almost immediately -after sending the request. Symptom of a hanged RPC is a log like the following being the last in your -console: +The expected behavior is that the pending streaming calls fails immediately with error UNAVAILABLE. +Moreover, when network comes back, new calls have the same behavior. ``` 2016-06-29 16:51:29.443 ConnectivityTestingApp[73129:3567949] Sending request. diff --git a/src/objective-c/tests/Connectivity/ViewController.m b/src/objective-c/tests/Connectivity/ViewController.m deleted file mode 100644 index e39f3be594..0000000000 --- a/src/objective-c/tests/Connectivity/ViewController.m +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * 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. - * - */ - -#import <UIKit/UIKit.h> - -#import <GRPCClient/GRPCCall.h> -#import <ProtoRPC/ProtoMethod.h> -#import <RxLibrary/GRXWriter+Immediate.h> -#import <RxLibrary/GRXWriter+Transformations.h> - -@interface ViewController : UIViewController -@end - -@implementation ViewController -- (void)viewDidLoad { - [super viewDidLoad]; - - NSString *host = @"grpc-test.sandbox.googleapis.com"; - - GRPCProtoMethod *method = [[GRPCProtoMethod alloc] initWithPackage:@"grpc.testing" - service:@"TestService" - method:@"StreamingOutputCall"]; - - __block void (^startCall)() = ^{ - GRXWriter *loggingRequestWriter = [[GRXWriter writerWithValue:[NSData data]] map:^id(id value) { - NSLog(@"Sending request."); - return value; - }]; - - GRPCCall *call = [[GRPCCall alloc] initWithHost:host - path:method.HTTPPath - requestsWriter:loggingRequestWriter]; - - [call startWithWriteable:[GRXWriteable writeableWithEventHandler:^(BOOL done, id value, - NSError *error) { - if (!done) { - return; - } - if (error) { - NSLog(@"Finished with error %@", error); - } else { - NSLog(@"Finished successfully."); - } - - dispatch_time_t oneSecond = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)); - dispatch_after(oneSecond, dispatch_get_main_queue(), startCall); - }]]; - }; - - startCall(); -} -@end diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm index 33ccdb5844..80fa0f4785 100644 --- a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm +++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm @@ -37,11 +37,11 @@ #include <grpc/support/log.h> #include "src/core/lib/channel/channel_args.h" -#include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/gpr/env.h" #include "src/core/lib/gpr/host_port.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gpr/tmpfile.h" +#include "src/core/lib/security/credentials/credentials.h" #include "test/core/end2end/data/ssl_test_data.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" @@ -58,7 +58,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( grpc_end2end_test_fixture f; int port = grpc_pick_unused_port_or_die(); fullstack_secure_fixture_data *ffd = - (fullstack_secure_fixture_data*)gpr_malloc(sizeof(fullstack_secure_fixture_data)); + (fullstack_secure_fixture_data *)gpr_malloc(sizeof(fullstack_secure_fixture_data)); memset(&f, 0, sizeof(f)); gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port); @@ -70,9 +70,8 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack( return f; } -static void process_auth_failure(void *state, grpc_auth_context *ctx, - const grpc_metadata *md, size_t md_count, - grpc_process_auth_metadata_done_cb cb, +static void process_auth_failure(void *state, grpc_auth_context *ctx, const grpc_metadata *md, + size_t md_count, grpc_process_auth_metadata_done_cb cb, void *user_data) { GPR_ASSERT(state == NULL); cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL); @@ -82,22 +81,26 @@ static void cronet_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, stream_engine *cronetEngine) { fullstack_secure_fixture_data *ffd = (fullstack_secure_fixture_data *)f->fixture_data; - f->client = grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr, - client_args, NULL); + grpc_arg arg; + arg.key = const_cast<char *>(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); + arg.type = GRPC_ARG_INTEGER; + arg.value.integer = 1; + client_args = grpc_channel_args_copy_and_add(client_args, &arg, 1); + f->client = grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr, client_args, NULL); + grpc_channel_args_destroy(client_args); GPR_ASSERT(f->client != NULL); } -static void chttp2_init_server_secure_fullstack( - grpc_end2end_test_fixture *f, grpc_channel_args *server_args, - grpc_server_credentials *server_creds) { +static void chttp2_init_server_secure_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *server_args, + grpc_server_credentials *server_creds) { fullstack_secure_fixture_data *ffd = (fullstack_secure_fixture_data *)f->fixture_data; if (f->server) { grpc_server_destroy(f->server); } f->server = grpc_server_create(server_args, NULL); grpc_server_register_completion_queue(f->server, f->cq, NULL); - GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr, - server_creds)); + GPR_ASSERT(grpc_server_add_secure_http2_port(f->server, ffd->localaddr, server_creds)); grpc_server_credentials_release(server_creds); grpc_server_start(f->server); } @@ -108,8 +111,8 @@ static void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { gpr_free(ffd); } -static void cronet_init_client_simple_ssl_secure_fullstack( - grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { +static void cronet_init_client_simple_ssl_secure_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *client_args) { grpc_core::ExecCtx exec_ctx; stream_engine *cronetEngine = [Cronet getGlobalEngine]; @@ -122,18 +125,16 @@ static int fail_server_auth_check(grpc_channel_args *server_args) { size_t i; if (server_args == NULL) return 0; for (i = 0; i < server_args->num_args; i++) { - if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) == - 0) { + if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) == 0) { return 1; } } return 0; } -static void chttp2_init_server_simple_ssl_secure_fullstack( - grpc_end2end_test_fixture *f, grpc_channel_args *server_args) { - grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, - test_server1_cert}; +static void chttp2_init_server_simple_ssl_secure_fullstack(grpc_end2end_test_fixture *f, + grpc_channel_args *server_args) { + grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL); if (fail_server_auth_check(server_args)) { @@ -147,12 +148,9 @@ static void chttp2_init_server_simple_ssl_secure_fullstack( static grpc_end2end_test_config configs[] = { {"chttp2/simple_ssl_fullstack", - FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION | - FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS, - chttp2_create_fixture_secure_fullstack, - cronet_init_client_simple_ssl_secure_fullstack, - chttp2_init_server_simple_ssl_secure_fullstack, - chttp2_tear_down_secure_fullstack}, + FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION | FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS, nullptr, + chttp2_create_fixture_secure_fullstack, cronet_init_client_simple_ssl_secure_fullstack, + chttp2_init_server_simple_ssl_secure_fullstack, chttp2_tear_down_secure_fullstack}, }; static char *roots_filename; @@ -186,9 +184,8 @@ static char *roots_filename; [Cronet setHttp2Enabled:YES]; [Cronet enableTestCertVerifierForTesting]; - NSURL *url = [[[NSFileManager defaultManager] - URLsForDirectory:NSDocumentDirectory - inDomains:NSUserDomainMask] lastObject]; + NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] lastObject]; NSLog(@"Documents directory: %@", url); [Cronet start]; [Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES]; diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m index 28414b8e39..a6dfb154a4 100644 --- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m +++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m @@ -42,8 +42,7 @@ static void drain_cq(grpc_completion_queue *cq) { grpc_event ev; do { - ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5), - NULL); + ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5), NULL); } while (ev.type != GRPC_QUEUE_SHUTDOWN); } @@ -64,9 +63,8 @@ static void drain_cq(grpc_completion_queue *cq) { [Cronet setHttp2Enabled:YES]; [Cronet setSslKeyLogFileName:@"Documents/key"]; [Cronet enableTestCertVerifierForTesting]; - NSURL *url = [[[NSFileManager defaultManager] - URLsForDirectory:NSDocumentDirectory - inDomains:NSUserDomainMask] lastObject]; + NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] lastObject]; NSLog(@"Documents directory: %@", url); [Cronet start]; [Cronet startNetLogToFile:@"Documents/cronet_netlog.json" logBytes:YES]; @@ -88,8 +86,8 @@ void init_ssl(void) { void cleanup_ssl(void) { EVP_cleanup(); } -int alpn_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, void *arg) { +int alpn_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) { // Always select "h2" as the ALPN protocol to be used *out = (const unsigned char *)"h2"; *outlen = 2; @@ -98,16 +96,14 @@ int alpn_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen, void init_ctx(SSL_CTX *ctx) { // Install server certificate - BIO *pem = BIO_new_mem_buf((void *)test_server1_cert, - (int)strlen(test_server1_cert)); + BIO *pem = BIO_new_mem_buf((void *)test_server1_cert, (int)strlen(test_server1_cert)); X509 *cert = PEM_read_bio_X509_AUX(pem, NULL, NULL, (char *)""); SSL_CTX_use_certificate(ctx, cert); X509_free(cert); BIO_free(pem); // Install server private key - pem = - BIO_new_mem_buf((void *)test_server1_key, (int)strlen(test_server1_key)); + pem = BIO_new_mem_buf((void *)test_server1_key, (int)strlen(test_server1_key)); EVP_PKEY *key = PEM_read_bio_PrivateKey(pem, NULL, NULL, (char *)""); SSL_CTX_use_PrivateKey(ctx, key); EVP_PKEY_free(key); @@ -126,12 +122,18 @@ unsigned int parse_h2_length(const char *field) { ((unsigned int)(unsigned char)(field[2])); } +grpc_channel_args *add_disable_client_authority_filter_args(grpc_channel_args *args) { + grpc_arg arg; + arg.key = const_cast<char *>(GRPC_ARG_DISABLE_CLIENT_AUTHORITY_FILTER); + arg.type = GRPC_ARG_INTEGER; + arg.value.integer = 1; + return grpc_channel_args_copy_and_add(args, &arg, 1); +} + - (void)testInternalError { grpc_call *c; - grpc_slice request_payload_slice = - grpc_slice_from_copied_string("hello world"); - grpc_byte_buffer *request_payload = - grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_slice request_payload_slice = grpc_slice_from_copied_string("hello world"); + grpc_byte_buffer *request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5); grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"), grpc_slice_from_static_string("val1"), @@ -147,8 +149,9 @@ unsigned int parse_h2_length(const char *field) { gpr_join_host_port(&addr, "127.0.0.1", port); grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); stream_engine *cronetEngine = [Cronet getGlobalEngine]; - grpc_channel *client = - grpc_cronet_secure_channel_create(cronetEngine, addr, NULL, NULL); + grpc_channel_args *client_args = add_disable_client_authority_filter_args(NULL); + grpc_channel *client = grpc_cronet_secure_channel_create(cronetEngine, addr, client_args, NULL); + grpc_channel_args_destroy(client_args); cq_verifier *cqv = cq_verifier_create(cq); grpc_op ops[6]; @@ -163,8 +166,7 @@ unsigned int parse_h2_length(const char *field) { grpc_slice details; c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, cq, - grpc_slice_from_static_string("/foo"), NULL, - deadline, NULL); + grpc_slice_from_static_string("/foo"), NULL, deadline, NULL); GPR_ASSERT(c); grpc_metadata_array_init(&initial_metadata_recv); @@ -221,16 +223,15 @@ unsigned int parse_h2_length(const char *field) { error = grpc_call_start_batch(c, ops, (size_t)(op - ops), (void *)1, NULL); GPR_ASSERT(GRPC_CALL_OK == error); - dispatch_async( - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - int s = accept(sl, NULL, NULL); - GPR_ASSERT(s >= 0); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + int s = accept(sl, NULL, NULL); + GPR_ASSERT(s >= 0); - // Close the connection after 1 second to trigger Cronet's on_failed() - sleep(1); - close(s); - close(sl); - }); + // Close the connection after 1 second to trigger Cronet's on_failed() + sleep(1); + close(s); + close(sl); + }); CQ_EXPECT_COMPLETION(cqv, (void *)1, 1); cq_verify(cqv); @@ -262,11 +263,11 @@ unsigned int parse_h2_length(const char *field) { arg.type = GRPC_ARG_INTEGER; arg.value.integer = useCoalescing ? 1 : 0; grpc_channel_args *args = grpc_channel_args_copy_and_add(NULL, &arg, 1); + args = add_disable_client_authority_filter_args(args); + grpc_call *c; - grpc_slice request_payload_slice = - grpc_slice_from_copied_string("hello world"); - grpc_byte_buffer *request_payload = - grpc_raw_byte_buffer_create(&request_payload_slice, 1); + grpc_slice request_payload_slice = grpc_slice_from_copied_string("hello world"); + grpc_byte_buffer *request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1); gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5); grpc_metadata meta_c[2] = {{grpc_slice_from_static_string("key1"), grpc_slice_from_static_string("val1"), @@ -282,8 +283,7 @@ unsigned int parse_h2_length(const char *field) { gpr_join_host_port(&addr, "127.0.0.1", port); grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); stream_engine *cronetEngine = [Cronet getGlobalEngine]; - grpc_channel *client = - grpc_cronet_secure_channel_create(cronetEngine, addr, args, NULL); + grpc_channel *client = grpc_cronet_secure_channel_create(cronetEngine, addr, args, NULL); cq_verifier *cqv = cq_verifier_create(cq); grpc_op ops[6]; @@ -298,8 +298,7 @@ unsigned int parse_h2_length(const char *field) { grpc_slice details; c = grpc_channel_create_call(client, NULL, GRPC_PROPAGATE_DEFAULTS, cq, - grpc_slice_from_static_string("/foo"), NULL, - deadline, NULL); + grpc_slice_from_static_string("/foo"), NULL, deadline, NULL); GPR_ASSERT(c); grpc_metadata_array_init(&initial_metadata_recv); @@ -307,8 +306,7 @@ unsigned int parse_h2_length(const char *field) { grpc_metadata_array_init(&request_metadata_recv); grpc_call_details_init(&call_details); - __weak XCTestExpectation *expectation = - [self expectationWithDescription:@"Coalescing"]; + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Coalescing"]; int sl = socket(AF_INET, SOCK_STREAM, 0); GPR_ASSERT(sl >= 0); @@ -320,61 +318,60 @@ unsigned int parse_h2_length(const char *field) { GPR_ASSERT(0 == bind(sl, (struct sockaddr *)&s_addr, sizeof(s_addr))); GPR_ASSERT(0 == listen(sl, 5)); - dispatch_async( - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - int s = accept(sl, NULL, NULL); - GPR_ASSERT(s >= 0); - struct timeval tv; - tv.tv_sec = 2; - tv.tv_usec = 0; - setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - - // Make an TLS endpoint to receive Cronet's transmission - SSL_CTX *ctx = SSL_CTX_new(TLSv1_2_server_method()); - init_ctx(ctx); - SSL *ssl = SSL_new(ctx); - SSL_set_fd(ssl, s); - SSL_accept(ssl); - - const char magic[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; - - char buf[4096]; - long len; - BOOL coalesced = NO; - while ((len = SSL_read(ssl, buf, sizeof(buf))) > 0) { - gpr_log(GPR_DEBUG, "Read len: %ld", len); - - // Analyze the HTTP/2 frames in the same TLS PDU to identify if - // coalescing is successful - unsigned int p = 0; - while (p < len) { - if (len - p >= 24 && 0 == memcmp(&buf[p], magic, 24)) { - p += 24; - continue; - } - - if (buf[p + 3] == 0 && // Type is DATA - parse_h2_length(&buf[p]) == 0x10 && // Length is correct - (buf[p + 4] & 1) != 0 && // EOS bit is set - 0 == memcmp("hello world", &buf[p + 14], - 11)) { // Message is correct - coalesced = YES; - break; - } - p += (parse_h2_length(&buf[p]) + 9); - } - if (coalesced) { - break; - } + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + int s = accept(sl, NULL, NULL); + GPR_ASSERT(s >= 0); + struct timeval tv; + tv.tv_sec = 2; + tv.tv_usec = 0; + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + + // Make an TLS endpoint to receive Cronet's transmission + SSL_CTX *ctx = SSL_CTX_new(TLSv1_2_server_method()); + init_ctx(ctx); + SSL *ssl = SSL_new(ctx); + SSL_set_fd(ssl, s); + SSL_accept(ssl); + + const char magic[] = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"; + + char buf[4096]; + long len; + BOOL coalesced = NO; + while ((len = SSL_read(ssl, buf, sizeof(buf))) > 0) { + gpr_log(GPR_DEBUG, "Read len: %ld", len); + + // Analyze the HTTP/2 frames in the same TLS PDU to identify if + // coalescing is successful + unsigned int p = 0; + while (p < len) { + if (len - p >= 24 && 0 == memcmp(&buf[p], magic, 24)) { + p += 24; + continue; } - XCTAssert(coalesced == useCoalescing); - SSL_free(ssl); - SSL_CTX_free(ctx); - close(s); - close(sl); - [expectation fulfill]; - }); + if (buf[p + 3] == 0 && // Type is DATA + parse_h2_length(&buf[p]) == 0x10 && // Length is correct + (buf[p + 4] & 1) != 0 && // EOS bit is set + 0 == memcmp("hello world", &buf[p + 14], + 11)) { // Message is correct + coalesced = YES; + break; + } + p += (parse_h2_length(&buf[p]) + 9); + } + if (coalesced) { + break; + } + } + + XCTAssert(coalesced == useCoalescing); + SSL_free(ssl); + SSL_CTX_free(ctx); + close(s); + close(sl); + [expectation fulfill]; + }); memset(ops, 0, sizeof(ops)); op = ops; diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m index 3bab7f6671..5cd0231db7 100644 --- a/src/objective-c/tests/GRPCClientTests.m +++ b/src/objective-c/tests/GRPCClientTests.m @@ -20,25 +20,27 @@ #import <XCTest/XCTest.h> #import <grpc/grpc.h> -#import <GRPCClient/GRPCCall.h> #import <GRPCClient/GRPCCall+ChannelArg.h> #import <GRPCClient/GRPCCall+OAuth2.h> #import <GRPCClient/GRPCCall+Tests.h> +#import <GRPCClient/GRPCCall.h> #import <GRPCClient/internal_testing/GRPCCall+InternalTests.h> #import <ProtoRPC/ProtoMethod.h> #import <RemoteTest/Messages.pbobjc.h> +#import <RxLibrary/GRXBufferedPipe.h> #import <RxLibrary/GRXWriteable.h> #import <RxLibrary/GRXWriter+Immediate.h> -#import <RxLibrary/GRXBufferedPipe.h> + +#include <netinet/in.h> #import "version.h" #define TEST_TIMEOUT 16 -static NSString * const kHostAddress = @"localhost:5050"; -static NSString * const kPackage = @"grpc.testing"; -static NSString * const kService = @"TestService"; -static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com"; +static NSString *const kHostAddress = @"localhost:5050"; +static NSString *const kPackage = @"grpc.testing"; +static NSString *const kService = @"TestService"; +static NSString *const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com"; static GRPCProtoMethod *kInexistentMethod; static GRPCProtoMethod *kEmptyCallMethod; @@ -47,15 +49,17 @@ static GRPCProtoMethod *kFullDuplexCallMethod; /** Observer class for testing that responseMetadata is KVO-compliant */ @interface PassthroughObserver : NSObject -- (instancetype) initWithCallback:(void (^)(NSString*, id, NSDictionary*))callback +- (instancetype)initWithCallback:(void (^)(NSString *, id, NSDictionary *))callback NS_DESIGNATED_INITIALIZER; -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change context:(void *)context; @end @implementation PassthroughObserver { - void (^_callback)(NSString*, id, NSDictionary*); + void (^_callback)(NSString *, id, NSDictionary *); } - (instancetype)init { @@ -82,7 +86,7 @@ static GRPCProtoMethod *kFullDuplexCallMethod; @end -# pragma mark Tests +#pragma mark Tests /** * A few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall) rather than @@ -106,18 +110,14 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [GRPCCall useInsecureConnectionsForHost:kHostAddress]; // This method isn't implemented by the remote server. - kInexistentMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage - service:kService - method:@"Inexistent"]; - kEmptyCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage - service:kService - method:@"EmptyCall"]; - kUnaryCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage - service:kService - method:@"UnaryCall"]; - kFullDuplexCallMethod = [[GRPCProtoMethod alloc] initWithPackage:kPackage - service:kService - method:@"FullDuplexCall"]; + kInexistentMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"Inexistent"]; + kEmptyCallMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"EmptyCall"]; + kUnaryCallMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"UnaryCall"]; + kFullDuplexCallMethod = + [[GRPCProtoMethod alloc] initWithPackage:kPackage service:kService method:@"FullDuplexCall"]; } - (void)testConnectionToRemoteServer { @@ -127,13 +127,15 @@ static GRPCProtoMethod *kFullDuplexCallMethod; path:kInexistentMethod.HTTPPath requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTFail(@"Received unexpected response: %@", value); - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNotNil(errorOrNil, @"Finished without error!"); - XCTAssertEqual(errorOrNil.code, 12, @"Finished with unexpected error: %@", errorOrNil); - [expectation fulfill]; - }]; + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTFail(@"Received unexpected response: %@", value); + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNotNil(errorOrNil, @"Finished without error!"); + XCTAssertEqual(errorOrNil.code, 12, @"Finished with unexpected error: %@", errorOrNil); + [expectation fulfill]; + }]; [call startWithWriteable:responsesWriteable]; @@ -141,21 +143,24 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } - (void)testEmptyRPC { - __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; + __weak XCTestExpectation *response = + [self expectationWithDescription:@"Empty response received."]; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress path:kEmptyCallMethod.HTTPPath requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - [completion fulfill]; - }]; + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTAssertNotNil(value, @"nil value received as response."); + XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); + [response fulfill]; + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); + [completion fulfill]; + }]; [call startWithWriteable:responsesWriteable]; @@ -176,18 +181,20 @@ static GRPCProtoMethod *kFullDuplexCallMethod; path:kUnaryCallMethod.HTTPPath requestsWriter:requestsWriter]; - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - XCTAssertGreaterThan(value.length, 0, @"Empty response received."); - RMTSimpleResponse *responseProto = [RMTSimpleResponse parseFromData:value error:NULL]; - // We expect empty strings, not nil: - XCTAssertNotNil(responseProto.username, @"Response's username is nil."); - XCTAssertNotNil(responseProto.oauthScope, @"Response's OAuth scope is nil."); - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - [completion fulfill]; - }]; + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTAssertNotNil(value, @"nil value received as response."); + XCTAssertGreaterThan(value.length, 0, @"Empty response received."); + RMTSimpleResponse *responseProto = [RMTSimpleResponse parseFromData:value error:NULL]; + // We expect empty strings, not nil: + XCTAssertNotNil(responseProto.username, @"Response's username is nil."); + XCTAssertNotNil(responseProto.oauthScope, @"Response's OAuth scope is nil."); + [response fulfill]; + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); + [completion fulfill]; + }]; [call startWithWriteable:responsesWriteable]; @@ -208,20 +215,22 @@ static GRPCProtoMethod *kFullDuplexCallMethod; call.oauth2AccessToken = @"bogusToken"; - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTFail(@"Received unexpected response: %@", value); - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNotNil(errorOrNil, @"Finished without error!"); - XCTAssertEqual(errorOrNil.code, 16, @"Finished with unexpected error: %@", errorOrNil); - XCTAssertEqualObjects(call.responseHeaders, errorOrNil.userInfo[kGRPCHeadersKey], - @"Headers in the NSError object and call object differ."); - XCTAssertEqualObjects(call.responseTrailers, errorOrNil.userInfo[kGRPCTrailersKey], - @"Trailers in the NSError object and call object differ."); - NSString *challengeHeader = call.oauth2ChallengeHeader; - XCTAssertGreaterThan(challengeHeader.length, 0, - @"No challenge in response headers %@", call.responseHeaders); - [expectation fulfill]; - }]; + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTFail(@"Received unexpected response: %@", value); + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNotNil(errorOrNil, @"Finished without error!"); + XCTAssertEqual(errorOrNil.code, 16, @"Finished with unexpected error: %@", errorOrNil); + XCTAssertEqualObjects(call.responseHeaders, errorOrNil.userInfo[kGRPCHeadersKey], + @"Headers in the NSError object and call object differ."); + XCTAssertEqualObjects(call.responseTrailers, errorOrNil.userInfo[kGRPCTrailersKey], + @"Trailers in the NSError object and call object differ."); + NSString *challengeHeader = call.oauth2ChallengeHeader; + XCTAssertGreaterThan(challengeHeader.length, 0, @"No challenge in response headers %@", + call.responseHeaders); + [expectation fulfill]; + }]; [call startWithWriteable:responsesWriteable]; @@ -229,38 +238,43 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } - (void)testResponseMetadataKVO { - __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; + __weak XCTestExpectation *response = + [self expectationWithDescription:@"Empty response received."]; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; __weak XCTestExpectation *metadata = [self expectationWithDescription:@"Metadata changed."]; - + GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress path:kEmptyCallMethod.HTTPPath requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; - - PassthroughObserver *observer = [[PassthroughObserver alloc] initWithCallback:^(NSString *keypath, id object, NSDictionary * change) { - if ([keypath isEqual: @"responseHeaders"]) { - [metadata fulfill]; - } - }]; - + + PassthroughObserver *observer = [[PassthroughObserver alloc] + initWithCallback:^(NSString *keypath, id object, NSDictionary *change) { + if ([keypath isEqual:@"responseHeaders"]) { + [metadata fulfill]; + } + }]; + [call addObserver:observer forKeyPath:@"responseHeaders" options:0 context:NULL]; - - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - [completion fulfill]; - }]; - + + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTAssertNotNil(value, @"nil value received as response."); + XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); + [response fulfill]; + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); + [completion fulfill]; + }]; + [call startWithWriteable:responsesWriteable]; - + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } - (void)testUserAgentPrefix { - __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; + __weak XCTestExpectation *response = + [self expectationWithDescription:@"Empty response received."]; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress @@ -270,46 +284,45 @@ static GRPCProtoMethod *kFullDuplexCallMethod; // user-agent value, which we confirm. call.requestHeaders[@"x-grpc-test-echo-useragent"] = @""; - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); - - NSString *userAgent = call.responseHeaders[@"x-grpc-test-echo-useragent"]; - NSError *error = nil; - - // Test the regex is correct - NSString *expectedUserAgent = @"Foo grpc-objc/"; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:@" grpc-c/"]; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "]; - expectedUserAgent = - [expectedUserAgent stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]]; - expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"]; - XCTAssertEqualObjects(userAgent, expectedUserAgent); - - // Change in format of user-agent field in a direction that does not match the regex will likely - // cause problem for certain gRPC users. For details, refer to internal doc https://goo.gl/c2diBc - NSRegularExpression *regex = - [NSRegularExpression regularExpressionWithPattern:@" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" - options:0 - error:&error]; - NSString *customUserAgent = - [regex stringByReplacingMatchesInString:userAgent - options:0 - range:NSMakeRange(0, [userAgent length]) - withTemplate:@""]; - XCTAssertEqualObjects(customUserAgent, @"Foo"); - - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - [completion fulfill]; - }]; + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTAssertNotNil(value, @"nil value received as response."); + XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); + + NSString *userAgent = call.responseHeaders[@"x-grpc-test-echo-useragent"]; + NSError *error = nil; + + // Test the regex is correct + NSString *expectedUserAgent = @"Foo grpc-objc/"; + expectedUserAgent = [expectedUserAgent stringByAppendingString:GRPC_OBJC_VERSION_STRING]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@" grpc-c/"]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:GRPC_C_VERSION_STRING]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@" (ios; chttp2; "]; + expectedUserAgent = [expectedUserAgent + stringByAppendingString:[NSString stringWithUTF8String:grpc_g_stands_for()]]; + expectedUserAgent = [expectedUserAgent stringByAppendingString:@")"]; + XCTAssertEqualObjects(userAgent, expectedUserAgent); + + // Change in format of user-agent field in a direction that does not match the regex will + // likely cause problem for certain gRPC users. For details, refer to internal doc + // https://goo.gl/c2diBc + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern:@" grpc-[a-zA-Z0-9]+(-[a-zA-Z0-9]+)?/[^ ,]+( \\([^)]*\\))?" + options:0 + error:&error]; + NSString *customUserAgent = + [regex stringByReplacingMatchesInString:userAgent + options:0 + range:NSMakeRange(0, [userAgent length]) + withTemplate:@""]; + XCTAssertEqualObjects(customUserAgent, @"Foo"); + + [response fulfill]; + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); + [completion fulfill]; + }]; [call startWithWriteable:responsesWriteable]; @@ -317,7 +330,8 @@ static GRPCProtoMethod *kFullDuplexCallMethod; } - (void)testTrailers { - __weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."]; + __weak XCTestExpectation *response = + [self expectationWithDescription:@"Empty response received."]; __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress @@ -325,21 +339,22 @@ static GRPCProtoMethod *kFullDuplexCallMethod; requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; // Setting this special key in the header will cause the interop server to echo back the // trailer data. - const unsigned char raw_bytes[] = {1,2,3,4}; + const unsigned char raw_bytes[] = {1, 2, 3, 4}; NSData *trailer_data = [NSData dataWithBytes:raw_bytes length:sizeof(raw_bytes)]; call.requestHeaders[@"x-grpc-test-echo-trailing-bin"] = trailer_data; - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - XCTAssertEqualObjects((NSData *)call.responseTrailers[@"x-grpc-test-echo-trailing-bin"], - trailer_data, - @"Did not receive expected trailer"); - [completion fulfill]; - }]; + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTAssertNotNil(value, @"nil value received as response."); + XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value); + [response fulfill]; + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); + XCTAssertEqualObjects((NSData *)call.responseTrailers[@"x-grpc-test-echo-trailing-bin"], + trailer_data, @"Did not receive expected trailer"); + [completion fulfill]; + }]; [call startWithWriteable:responsesWriteable]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; @@ -349,15 +364,12 @@ static GRPCProtoMethod *kFullDuplexCallMethod; - (void)testExceptions { // Try to set parameters to nil for GRPCCall. This should cause an exception @try { - (void)[[GRPCCall alloc] initWithHost:nil - path:nil - requestsWriter:nil]; + (void)[[GRPCCall alloc] initWithHost:nil path:nil requestsWriter:nil]; XCTFail(@"Did not receive an exception when parameters are nil"); - } @catch(NSException *theException) { + } @catch (NSException *theException) { NSLog(@"Received exception as expected: %@", theException.name); } - // Set state to Finished by force GRXWriter *requestsWriter = [GRXWriter emptyWriter]; [requestsWriter finishWithError:nil]; @@ -366,10 +378,9 @@ static GRPCProtoMethod *kFullDuplexCallMethod; path:kUnaryCallMethod.HTTPPath requestsWriter:requestsWriter]; XCTFail(@"Did not receive an exception when GRXWriter has incorrect state."); - } @catch(NSException *theException) { + } @catch (NSException *theException) { NSLog(@"Received exception as expected: %@", theException.name); } - } - (void)testIdempotentProtoRPC { @@ -385,20 +396,24 @@ static GRPCProtoMethod *kFullDuplexCallMethod; GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress path:kUnaryCallMethod.HTTPPath requestsWriter:requestsWriter]; - [GRPCCall setCallSafety:GRPCCallSafetyIdempotentRequest host:kHostAddress path:kUnaryCallMethod.HTTPPath]; - - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssertNotNil(value, @"nil value received as response."); - XCTAssertGreaterThan(value.length, 0, @"Empty response received."); - RMTSimpleResponse *responseProto = [RMTSimpleResponse parseFromData:value error:NULL]; - // We expect empty strings, not nil: - XCTAssertNotNil(responseProto.username, @"Response's username is nil."); - XCTAssertNotNil(responseProto.oauthScope, @"Response's OAuth scope is nil."); - [response fulfill]; - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); - [completion fulfill]; - }]; + [GRPCCall setCallSafety:GRPCCallSafetyIdempotentRequest + host:kHostAddress + path:kUnaryCallMethod.HTTPPath]; + + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTAssertNotNil(value, @"nil value received as response."); + XCTAssertGreaterThan(value.length, 0, @"Empty response received."); + RMTSimpleResponse *responseProto = [RMTSimpleResponse parseFromData:value error:NULL]; + // We expect empty strings, not nil: + XCTAssertNotNil(responseProto.username, @"Response's username is nil."); + XCTAssertNotNil(responseProto.oauthScope, @"Response's OAuth scope is nil."); + [response fulfill]; + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil); + [completion fulfill]; + }]; [call startWithWriteable:responsesWriteable]; @@ -410,10 +425,12 @@ static GRPCProtoMethod *kFullDuplexCallMethod; RMTSimpleRequest *request = [RMTSimpleRequest message]; request.responseSize = kPayloadSize; - __weak XCTestExpectation *expectation1 = [self expectationWithDescription:@"AlternateDispatchQueue1"]; + __weak XCTestExpectation *expectation1 = + [self expectationWithDescription:@"AlternateDispatchQueue1"]; // Use default (main) dispatch queue - NSString *main_queue_label = [NSString stringWithUTF8String:dispatch_queue_get_label(dispatch_get_main_queue())]; + NSString *main_queue_label = + [NSString stringWithUTF8String:dispatch_queue_get_label(dispatch_get_main_queue())]; GRXWriter *requestsWriter1 = [GRXWriter writerWithValue:[request data]]; @@ -421,20 +438,24 @@ static GRPCProtoMethod *kFullDuplexCallMethod; path:kUnaryCallMethod.HTTPPath requestsWriter:requestsWriter1]; - id<GRXWriteable> responsesWriteable1 = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - NSString *label = [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)]; - XCTAssert([label isEqualToString:main_queue_label]); + id<GRXWriteable> responsesWriteable1 = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + NSString *label = + [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)]; + XCTAssert([label isEqualToString:main_queue_label]); - [expectation1 fulfill]; - } completionHandler:^(NSError *errorOrNil) { - }]; + [expectation1 fulfill]; + } + completionHandler:^(NSError *errorOrNil){ + }]; [call1 startWithWriteable:responsesWriteable1]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; // Use a custom queue - __weak XCTestExpectation *expectation2 = [self expectationWithDescription:@"AlternateDispatchQueue2"]; + __weak XCTestExpectation *expectation2 = + [self expectationWithDescription:@"AlternateDispatchQueue2"]; NSString *queue_label = @"test.queue1"; dispatch_queue_t queue = dispatch_queue_create([queue_label UTF8String], DISPATCH_QUEUE_SERIAL); @@ -447,13 +468,16 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [call2 setResponseDispatchQueue:queue]; - id<GRXWriteable> responsesWriteable2 = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - NSString *label = [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)]; - XCTAssert([label isEqualToString:queue_label]); + id<GRXWriteable> responsesWriteable2 = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + NSString *label = + [NSString stringWithUTF8String:dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)]; + XCTAssert([label isEqualToString:queue_label]); - [expectation2 fulfill]; - } completionHandler:^(NSError *errorOrNil) { - }]; + [expectation2 fulfill]; + } + completionHandler:^(NSError *errorOrNil){ + }]; [call2 startWithWriteable:responsesWriteable2]; @@ -468,13 +492,16 @@ static GRPCProtoMethod *kFullDuplexCallMethod; path:kFullDuplexCallMethod.HTTPPath requestsWriter:pipe]; - id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { - XCTAssert(0, @"Failure: response received; Expect: no response received."); - } completionHandler:^(NSError *errorOrNil) { - XCTAssertNotNil(errorOrNil, @"Failure: no error received; Expect: receive deadline exceeded."); - XCTAssertEqual(errorOrNil.code, GRPCErrorCodeDeadlineExceeded); - [completion fulfill]; - }]; + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + XCTAssert(0, @"Failure: response received; Expect: no response received."); + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNotNil(errorOrNil, + @"Failure: no error received; Expect: receive deadline exceeded."); + XCTAssertEqual(errorOrNil.code, GRPCErrorCodeDeadlineExceeded); + [completion fulfill]; + }]; call.timeout = 0.001; [call startWithWriteable:responsesWriteable]; @@ -482,4 +509,42 @@ static GRPCProtoMethod *kFullDuplexCallMethod; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +- (int)findFreePort { + struct sockaddr_in addr; + unsigned int addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + int fd = socket(AF_INET, SOCK_STREAM, 0); + XCTAssertEqual(bind(fd, (struct sockaddr *)&addr, sizeof(addr)), 0); + XCTAssertEqual(getsockname(fd, (struct sockaddr *)&addr, &addr_len), 0); + XCTAssertEqual(addr_len, sizeof(addr)); + close(fd); + return addr.sin_port; +} + +- (void)testErrorCode { + int port = [self findFreePort]; + NSString *const kDummyAddress = [NSString stringWithFormat:@"localhost:%d", port]; + __weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."]; + + GRPCCall *call = [[GRPCCall alloc] initWithHost:kDummyAddress + path:kEmptyCallMethod.HTTPPath + requestsWriter:[GRXWriter writerWithValue:[NSData data]]]; + + id<GRXWriteable> responsesWriteable = + [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) { + // Should not reach here + XCTAssert(NO); + } + completionHandler:^(NSError *errorOrNil) { + XCTAssertNotNil(errorOrNil, @"Finished with no error"); + XCTAssertEqual(errorOrNil.code, GRPC_STATUS_UNAVAILABLE); + [completion fulfill]; + }]; + + [call startWithWriteable:responsesWriteable]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + @end diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m index dfa874adab..1e1da2dd66 100644 --- a/src/objective-c/tests/InteropTests.m +++ b/src/objective-c/tests/InteropTests.m @@ -22,17 +22,17 @@ #import <Cronet/Cronet.h> #import <GRPCClient/GRPCCall+ChannelArg.h> +#import <GRPCClient/GRPCCall+Cronet.h> #import <GRPCClient/GRPCCall+Tests.h> #import <GRPCClient/internal_testing/GRPCCall+InternalTests.h> -#import <GRPCClient/GRPCCall+Cronet.h> #import <ProtoRPC/ProtoRPC.h> #import <RemoteTest/Messages.pbobjc.h> #import <RemoteTest/Test.pbobjc.h> #import <RemoteTest/Test.pbrpc.h> #import <RxLibrary/GRXBufferedPipe.h> #import <RxLibrary/GRXWriter+Immediate.h> -#import <grpc/support/log.h> #import <grpc/grpc.h> +#import <grpc/support/log.h> #define TEST_TIMEOUT 32 @@ -61,7 +61,7 @@ @implementation RMTStreamingOutputCallResponse (Constructors) + (instancetype)messageWithPayloadSize:(NSNumber *)payloadSize { - RMTStreamingOutputCallResponse * response = [self message]; + RMTStreamingOutputCallResponse *response = [self message]; response.payload.type = RMTPayloadType_Compressable; response.payload.body = [NSMutableData dataWithLength:payloadSize.unsignedIntegerValue]; return response; @@ -113,14 +113,15 @@ BOOL isRemoteInteropTest(NSString *host) { GPBEmpty *request = [GPBEmpty message]; - [_service emptyCallWithRequest:request handler:^(GPBEmpty *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); + [_service emptyCallWithRequest:request + handler:^(GPBEmpty *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); - id expectedResponse = [GPBEmpty message]; - XCTAssertEqualObjects(response, expectedResponse); + id expectedResponse = [GPBEmpty message]; + XCTAssertEqualObjects(response, expectedResponse); - [expectation fulfill]; - }]; + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -134,16 +135,17 @@ BOOL isRemoteInteropTest(NSString *host) { request.responseSize = 314159; request.payload.body = [NSMutableData dataWithLength:271828]; - [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); - RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; - expectedResponse.payload.type = RMTPayloadType_Compressable; - expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; - XCTAssertEqualObjects(response, expectedResponse); + RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; + expectedResponse.payload.type = RMTPayloadType_Compressable; + expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; + XCTAssertEqualObjects(response, expectedResponse); - [expectation fulfill]; - }]; + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -158,29 +160,30 @@ BOOL isRemoteInteropTest(NSString *host) { request.payload.body = [NSMutableData dataWithLength:10]; [GRPCCall enableOpBatchLog:YES]; - [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - - RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; - expectedResponse.payload.type = RMTPayloadType_Compressable; - expectedResponse.payload.body = [NSMutableData dataWithLength:10]; - XCTAssertEqualObjects(response, expectedResponse); - - // The test is a success if there is a batch of exactly 3 ops (SEND_INITIAL_METADATA, - // SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT). Without packet coalescing each batch of ops contains - // only one op. - NSArray *opBatches = [GRPCCall obtainAndCleanOpBatchLog]; - const NSInteger kExpectedOpBatchSize = 3; - for (NSObject *o in opBatches) { - if ([o isKindOfClass:[NSArray class]]) { - NSArray *batch = (NSArray *)o; - if ([batch count] == kExpectedOpBatchSize) { - [expectation fulfill]; - break; - } - } - } - }]; + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + + RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; + expectedResponse.payload.type = RMTPayloadType_Compressable; + expectedResponse.payload.body = [NSMutableData dataWithLength:10]; + XCTAssertEqualObjects(response, expectedResponse); + + // The test is a success if there is a batch of exactly 3 ops + // (SEND_INITIAL_METADATA, SEND_MESSAGE, SEND_CLOSE_FROM_CLIENT). Without + // packet coalescing each batch of ops contains only one op. + NSArray *opBatches = [GRPCCall obtainAndCleanOpBatchLog]; + const NSInteger kExpectedOpBatchSize = 3; + for (NSObject *o in opBatches) { + if ([o isKindOfClass:[NSArray class]]) { + NSArray *batch = (NSArray *)o; + if ([batch count] == kExpectedOpBatchSize) { + [expectation fulfill]; + break; + } + } + } + }]; [self waitForExpectationsWithTimeout:16 handler:nil]; [GRPCCall enableOpBatchLog:NO]; @@ -191,14 +194,15 @@ BOOL isRemoteInteropTest(NSString *host) { __weak XCTestExpectation *expectation = [self expectationWithDescription:@"MaxResponseSize"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; - const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead; // 4MB - encoding overhead + const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead; // 4MB - encoding overhead request.responseSize = kPayloadSize; - [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssertEqual(response.payload.body.length, kPayloadSize); - [expectation fulfill]; - }]; + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertEqual(response.payload.body.length, kPayloadSize); + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -208,18 +212,23 @@ BOOL isRemoteInteropTest(NSString *host) { __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ResponseOverMaxSize"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; - const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead + 1; // 1B over max size + const int32_t kPayloadSize = 4 * 1024 * 1024 - self.encodingOverhead + 1; // 1B over max size request.responseSize = kPayloadSize; - [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { - // TODO(jcanizales): Catch the error and rethrow it with an actionable message: - // - Use +[GRPCCall setResponseSizeLimit:forHost:] to set a higher limit. - // - If you're developing the server, consider using response streaming, or let clients filter - // responses by setting a google.protobuf.FieldMask in the request: - // https://github.com/google/protobuf/blob/master/src/google/protobuf/field_mask.proto - XCTAssertEqualObjects(error.localizedDescription, @"Received message larger than max (4194305 vs. 4194304)"); - [expectation fulfill]; - }]; + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + // TODO(jcanizales): Catch the error and rethrow it with an actionable + // message: + // - Use +[GRPCCall setResponseSizeLimit:forHost:] to set a higher limit. + // - If you're developing the server, consider using response streaming, + // or let clients filter + // responses by setting a google.protobuf.FieldMask in the request: + // https://github.com/google/protobuf/blob/master/src/google/protobuf/field_mask.proto + XCTAssertEqualObjects( + error.localizedDescription, + @"Received message larger than max (4194305 vs. 4194304)"); + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -230,16 +239,17 @@ BOOL isRemoteInteropTest(NSString *host) { [self expectationWithDescription:@"HigherResponseSizeLimit"]; RMTSimpleRequest *request = [RMTSimpleRequest message]; - const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB + const size_t kPayloadSize = 5 * 1024 * 1024; // 5MB request.responseSize = kPayloadSize; [GRPCCall setResponseSizeLimit:6 * 1024 * 1024 forHost:self.class.host]; - [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssertEqual(response.payload.body.length, kPayloadSize); - [expectation fulfill]; - }]; + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertEqual(response.payload.body.length, kPayloadSize); + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -260,19 +270,21 @@ BOOL isRemoteInteropTest(NSString *host) { RMTStreamingInputCallRequest *request4 = [RMTStreamingInputCallRequest message]; request4.payload.body = [NSMutableData dataWithLength:45904]; - GRXWriter *writer = [GRXWriter writerWithContainer:@[request1, request2, request3, request4]]; + GRXWriter *writer = [GRXWriter writerWithContainer:@[ request1, request2, request3, request4 ]]; [_service streamingInputCallWithRequestsWriter:writer handler:^(RMTStreamingInputCallResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertNil( + error, @"Finished with unexpected error: %@", error); - RMTStreamingInputCallResponse *expectedResponse = [RMTStreamingInputCallResponse message]; - expectedResponse.aggregatedPayloadSize = 74922; - XCTAssertEqualObjects(response, expectedResponse); + RMTStreamingInputCallResponse *expectedResponse = + [RMTStreamingInputCallResponse message]; + expectedResponse.aggregatedPayloadSize = 74922; + XCTAssertEqualObjects(response, expectedResponse); - [expectation fulfill]; - }]; + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -281,7 +293,7 @@ BOOL isRemoteInteropTest(NSString *host) { XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"ServerStreaming"]; - NSArray *expectedSizes = @[@31415, @9, @2653, @58979]; + NSArray *expectedSizes = @[ @31415, @9, @2653, @58979 ]; RMTStreamingOutputCallRequest *request = [RMTStreamingOutputCallRequest message]; for (NSNumber *size in expectedSizes) { @@ -291,25 +303,27 @@ BOOL isRemoteInteropTest(NSString *host) { } __block int index = 0; - [_service streamingOutputCallWithRequest:request - eventHandler:^(BOOL done, - RMTStreamingOutputCallResponse *response, - NSError *error){ - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssertTrue(done || response, @"Event handler called without an event."); - - if (response) { - XCTAssertLessThan(index, 4, @"More than 4 responses received."); - id expected = [RMTStreamingOutputCallResponse messageWithPayloadSize:expectedSizes[index]]; - XCTAssertEqualObjects(response, expected); - index += 1; - } - - if (done) { - XCTAssertEqual(index, 4, @"Received %i responses instead of 4.", index); - [expectation fulfill]; - } - }]; + [_service + streamingOutputCallWithRequest:request + eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response, + NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertTrue(done || response, + @"Event handler called without an event."); + + if (response) { + XCTAssertLessThan(index, 4, @"More than 4 responses received."); + id expected = [RMTStreamingOutputCallResponse + messageWithPayloadSize:expectedSizes[index]]; + XCTAssertEqualObjects(response, expected); + index += 1; + } + + if (done) { + XCTAssertEqual(index, 4, @"Received %i responses instead of 4.", index); + [expectation fulfill]; + } + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -318,8 +332,8 @@ BOOL isRemoteInteropTest(NSString *host) { XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"PingPong"]; - NSArray *requests = @[@27182, @8, @1828, @45904]; - NSArray *responses = @[@31415, @9, @2653, @58979]; + NSArray *requests = @[ @27182, @8, @1828, @45904 ]; + NSArray *responses = @[ @31415, @9, @2653, @58979 ]; GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init]; @@ -330,31 +344,34 @@ BOOL isRemoteInteropTest(NSString *host) { [requestsBuffer writeValue:request]; [_service fullDuplexCallWithRequestsWriter:requestsBuffer - eventHandler:^(BOOL done, - RMTStreamingOutputCallResponse *response, + eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssertTrue(done || response, @"Event handler called without an event."); - - if (response) { - XCTAssertLessThan(index, 4, @"More than 4 responses received."); - id expected = [RMTStreamingOutputCallResponse messageWithPayloadSize:responses[index]]; - XCTAssertEqualObjects(response, expected); - index += 1; - if (index < 4) { - id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] - requestedResponseSize:responses[index]]; - [requestsBuffer writeValue:request]; - } else { - [requestsBuffer writesFinishedWithError:nil]; - } - } - - if (done) { - XCTAssertEqual(index, 4, @"Received %i responses instead of 4.", index); - [expectation fulfill]; - } - }]; + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertTrue(done || response, + @"Event handler called without an event."); + + if (response) { + XCTAssertLessThan(index, 4, @"More than 4 responses received."); + id expected = [RMTStreamingOutputCallResponse + messageWithPayloadSize:responses[index]]; + XCTAssertEqualObjects(response, expected); + index += 1; + if (index < 4) { + id request = [RMTStreamingOutputCallRequest + messageWithPayloadSize:requests[index] + requestedResponseSize:responses[index]]; + [requestsBuffer writeValue:request]; + } else { + [requestsBuffer writesFinishedWithError:nil]; + } + } + + if (done) { + XCTAssertEqual(index, 4, @"Received %i responses instead of 4.", + index); + [expectation fulfill]; + } + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -362,13 +379,12 @@ BOOL isRemoteInteropTest(NSString *host) { XCTAssertNotNil(self.class.host); __weak XCTestExpectation *expectation = [self expectationWithDescription:@"EmptyStream"]; [_service fullDuplexCallWithRequestsWriter:[GRXWriter emptyWriter] - eventHandler:^(BOOL done, - RMTStreamingOutputCallResponse *response, + eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssert(done, @"Unexpected response: %@", response); - [expectation fulfill]; - }]; + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssert(done, @"Unexpected response: %@", response); + [expectation fulfill]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -379,13 +395,13 @@ BOOL isRemoteInteropTest(NSString *host) { // A buffered pipe to which we never write any value acts as a writer that just hangs. GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init]; - GRPCProtoCall *call = - [_service RPCToStreamingInputCallWithRequestsWriter:requestsBuffer - handler:^(RMTStreamingInputCallResponse *response, - NSError *error) { - XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); - [expectation fulfill]; - }]; + GRPCProtoCall *call = [_service + RPCToStreamingInputCallWithRequestsWriter:requestsBuffer + handler:^(RMTStreamingInputCallResponse *response, + NSError *error) { + XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); + [expectation fulfill]; + }]; XCTAssertEqual(call.state, GRXWriterStateNotStarted); [call start]; @@ -399,35 +415,36 @@ BOOL isRemoteInteropTest(NSString *host) { - (void)testCancelAfterFirstResponseRPC { XCTAssertNotNil(self.class.host); - __weak XCTestExpectation *expectation = [self expectationWithDescription:@"CancelAfterFirstResponse"]; + __weak XCTestExpectation *expectation = + [self expectationWithDescription:@"CancelAfterFirstResponse"]; // A buffered pipe to which we write a single value but never close GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init]; __block BOOL receivedResponse = NO; - id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 - requestedResponseSize:@31415]; + id request = + [RMTStreamingOutputCallRequest messageWithPayloadSize:@21782 requestedResponseSize:@31415]; [requestsBuffer writeValue:request]; - __block GRPCProtoCall *call = - [_service RPCToFullDuplexCallWithRequestsWriter:requestsBuffer - eventHandler:^(BOOL done, - RMTStreamingOutputCallResponse *response, - NSError *error) { - if (receivedResponse) { - XCTAssert(done, @"Unexpected extra response %@", response); - XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); - [expectation fulfill]; - } else { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); - XCTAssertFalse(done, @"Finished without response"); - XCTAssertNotNil(response); - receivedResponse = YES; - [call cancel]; - } - }]; + __block GRPCProtoCall *call = [_service + RPCToFullDuplexCallWithRequestsWriter:requestsBuffer + eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response, + NSError *error) { + if (receivedResponse) { + XCTAssert(done, @"Unexpected extra response %@", response); + XCTAssertEqual(error.code, GRPC_STATUS_CANCELLED); + [expectation fulfill]; + } else { + XCTAssertNil(error, @"Finished with unexpected error: %@", + error); + XCTAssertFalse(done, @"Finished without response"); + XCTAssertNotNil(response); + receivedResponse = YES; + [call cancel]; + } + }]; [call start]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -439,19 +456,25 @@ BOOL isRemoteInteropTest(NSString *host) { GPBEmpty *request = [GPBEmpty message]; - [_service emptyCallWithRequest:request handler:^(GPBEmpty *response, NSError *error) { - XCTAssertNil(error, @"First RPC finished with unexpected error: %@", error); + [_service + emptyCallWithRequest:request + handler:^(GPBEmpty *response, NSError *error) { + XCTAssertNil(error, @"First RPC finished with unexpected error: %@", error); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - [GRPCCall closeOpenConnections]; + [GRPCCall closeOpenConnections]; #pragma clang diagnostic pop - [_service emptyCallWithRequest:request handler:^(GPBEmpty *response, NSError *error) { - XCTAssertNil(error, @"Second RPC finished with unexpected error: %@", error); - [expectation fulfill]; - }]; - }]; + [_service + emptyCallWithRequest:request + handler:^(GPBEmpty *response, NSError *error) { + XCTAssertNil( + error, @"Second RPC finished with unexpected error: %@", + error); + [expectation fulfill]; + }]; + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } @@ -472,18 +495,62 @@ BOOL isRemoteInteropTest(NSString *host) { request.expectCompressed.value = YES; [GRPCCall setDefaultCompressMethod:GRPCCompressGzip forhost:self.class.host]; - [_service unaryCallWithRequest:request handler:^(RMTSimpleResponse *response, NSError *error) { - XCTAssertNil(error, @"Finished with unexpected error: %@", error); + [_service unaryCallWithRequest:request + handler:^(RMTSimpleResponse *response, NSError *error) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + + RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; + expectedResponse.payload.type = RMTPayloadType_Compressable; + expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; + XCTAssertEqualObjects(response, expectedResponse); + + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; +} + +#ifndef GRPC_COMPILE_WITH_CRONET +- (void)testKeepalive { + XCTAssertNotNil(self.class.host); + __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Keepalive"]; + + [GRPCCall setKeepaliveWithInterval:1500 timeout:0 forHost:self.class.host]; + + NSArray *requests = @[ @27182, @8 ]; + NSArray *responses = @[ @31415, @9 ]; - RMTSimpleResponse *expectedResponse = [RMTSimpleResponse message]; - expectedResponse.payload.type = RMTPayloadType_Compressable; - expectedResponse.payload.body = [NSMutableData dataWithLength:314159]; - XCTAssertEqualObjects(response, expectedResponse); + GRXBufferedPipe *requestsBuffer = [[GRXBufferedPipe alloc] init]; - [expectation fulfill]; - }]; + __block int index = 0; + + id request = [RMTStreamingOutputCallRequest messageWithPayloadSize:requests[index] + requestedResponseSize:responses[index]]; + [requestsBuffer writeValue:request]; + + [_service + fullDuplexCallWithRequestsWriter:requestsBuffer + eventHandler:^(BOOL done, RMTStreamingOutputCallResponse *response, + NSError *error) { + if (index == 0) { + XCTAssertNil(error, @"Finished with unexpected error: %@", error); + XCTAssertTrue(response, @"Event handler called without an event."); + XCTAssertFalse(done); + index++; + } else { + // Keepalive should kick after 1s elapsed and fails the call. + XCTAssertNotNil(error); + XCTAssertEqual(error.code, GRPC_STATUS_INTERNAL); + XCTAssertEqualObjects( + error.localizedDescription, @"keepalive watchdog timeout", + @"Unexpected failure that is not keepalive watchdog timeout."); + XCTAssertTrue(done); + [expectation fulfill]; + } + }]; [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; } +#endif @end diff --git a/src/objective-c/tests/InteropTestsLocalCleartext.m b/src/objective-c/tests/InteropTestsLocalCleartext.m index aba9868211..d49e875bd0 100644 --- a/src/objective-c/tests/InteropTestsLocalCleartext.m +++ b/src/objective-c/tests/InteropTestsLocalCleartext.m @@ -25,7 +25,7 @@ // 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); +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. @@ -42,7 +42,7 @@ static int32_t kLocalInteropServerOverhead = 10; } - (int32_t)encodingOverhead { - return kLocalInteropServerOverhead; // bytes + return kLocalInteropServerOverhead; // bytes } - (void)setUp { diff --git a/src/objective-c/tests/InteropTestsLocalSSL.m b/src/objective-c/tests/InteropTestsLocalSSL.m index 06176cc588..a8c4dc7dfd 100644 --- a/src/objective-c/tests/InteropTestsLocalSSL.m +++ b/src/objective-c/tests/InteropTestsLocalSSL.m @@ -24,7 +24,7 @@ // 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); +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. @@ -41,7 +41,7 @@ static int32_t kLocalInteropServerOverhead = 10; } - (int32_t)encodingOverhead { - return kLocalInteropServerOverhead; // bytes + return kLocalInteropServerOverhead; // bytes } - (void)setUp { @@ -49,8 +49,8 @@ static int32_t kLocalInteropServerOverhead = 10; // Register test server certificates and name. NSBundle *bundle = [NSBundle bundleForClass:self.class]; - NSString *certsPath = [bundle pathForResource:@"TestCertificates.bundle/test-certificates" - ofType:@"pem"]; + NSString *certsPath = + [bundle pathForResource:@"TestCertificates.bundle/test-certificates" ofType:@"pem"]; [GRPCCall useTestCertsPath:certsPath testName:@"foo.test.google.fr" forHost:kLocalSSLHost]; } @@ -60,7 +60,7 @@ static int32_t kLocalInteropServerOverhead = 10; @try { [GRPCCall useTestCertsPath:nil testName:nil forHost:nil]; XCTFail(@"Did not receive an exception when parameters are nil"); - } @catch(NSException *theException) { + } @catch (NSException *theException) { NSLog(@"Received exception as expected: %@", theException.name); } } diff --git a/src/objective-c/tests/InteropTestsRemote.m b/src/objective-c/tests/InteropTestsRemote.m index f8133e8689..e5738aac73 100644 --- a/src/objective-c/tests/InteropTestsRemote.m +++ b/src/objective-c/tests/InteropTestsRemote.m @@ -25,7 +25,7 @@ // 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); +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. @@ -42,7 +42,7 @@ static int32_t kRemoteInteropServerOverhead = 12; } - (int32_t)encodingOverhead { - return kRemoteInteropServerOverhead; // bytes + return kRemoteInteropServerOverhead; // bytes } @end diff --git a/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m index d4eb5223fc..25041ae5eb 100644 --- a/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m +++ b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m @@ -28,8 +28,7 @@ // 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); - +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. @@ -46,7 +45,7 @@ static int32_t kRemoteInteropServerOverhead = 12; } - (int32_t)encodingOverhead { - return kRemoteInteropServerOverhead; // bytes + return kRemoteInteropServerOverhead; // bytes } @end diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile index 9e9db1fe6c..b6e389715a 100644 --- a/src/objective-c/tests/Podfile +++ b/src/objective-c/tests/Podfile @@ -8,7 +8,6 @@ GRPC_LOCAL_SRC = '../../..' # Install the dependencies in the main target plus all test targets. %w( - Tests AllTests RxLibraryUnitTests InteropTestsRemote @@ -27,8 +26,8 @@ GRPC_LOCAL_SRC = '../../..' pod 'gRPC', :path => GRPC_LOCAL_SRC pod 'gRPC-Core', :path => GRPC_LOCAL_SRC pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC - pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC - pod 'RemoteTest', :path => "RemoteTestClient" + pod 'gRPC-ProtoRPC', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true + pod 'RemoteTest', :path => "RemoteTestClient", :inhibit_warnings => true if target_name == 'InteropTestsRemoteWithCronet' pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC diff --git a/src/objective-c/tests/RxLibraryUnitTests.m b/src/objective-c/tests/RxLibraryUnitTests.m index aa178f8d45..ecd914c9b5 100644 --- a/src/objective-c/tests/RxLibraryUnitTests.m +++ b/src/objective-c/tests/RxLibraryUnitTests.m @@ -30,10 +30,10 @@ // // TODO(jcanizales): Move this to a test util library, and add tests for it. @interface CapturingSingleValueHandler : NSObject -@property (nonatomic, readonly) void (^block)(id value, NSError *errorOrNil); -@property (nonatomic, readonly) NSUInteger timesCalled; -@property (nonatomic, readonly) id value; -@property (nonatomic, readonly) NSError *errorOrNil; +@property(nonatomic, readonly) void (^block)(id value, NSError *errorOrNil); +@property(nonatomic, readonly) NSUInteger timesCalled; +@property(nonatomic, readonly) id value; +@property(nonatomic, readonly) NSError *errorOrNil; + (instancetype)handler; @end @@ -149,10 +149,11 @@ __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; // Given: CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; - id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { - handler.block(value, errorOrNil); - [expectation fulfill]; - }]; + id<GRXWriteable> writeable = + [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { + handler.block(value, errorOrNil); + [expectation fulfill]; + }]; id anyValue = @7; @@ -167,17 +168,17 @@ XCTAssertEqual(handler.timesCalled, 1); XCTAssertEqualObjects(handler.value, anyValue); XCTAssertEqualObjects(handler.errorOrNil, nil); - } - (void)testBufferedPipePropagatesError { __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; // Given: CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; - id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { - handler.block(value, errorOrNil); - [expectation fulfill]; - }]; + id<GRXWriteable> writeable = + [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { + handler.block(value, errorOrNil); + [expectation fulfill]; + }]; NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil]; // If: @@ -196,10 +197,11 @@ __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; // Given: CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; - id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { - handler.block(value, errorOrNil); - [expectation fulfill]; - }]; + id<GRXWriteable> writeable = + [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { + handler.block(value, errorOrNil); + [expectation fulfill]; + }]; id anyValue = @7; // If: @@ -220,8 +222,9 @@ #define WRITE_ROUNDS (1000) - (void)testBufferedPipeResumeWhenDealloc { id anyValue = @7; - id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { - }]; + id<GRXWriteable> writeable = + [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil){ + }]; // Release after alloc; GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj index 9a6cb0e7d7..e0f220eaee 100644 --- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj +++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj @@ -743,11 +743,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-CronetUnitTests/Pods-CronetUnitTests-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -845,11 +845,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -863,11 +863,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -935,11 +935,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -986,11 +986,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-AllTests/Pods-AllTests-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1037,11 +1037,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1091,11 +1091,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1124,11 +1124,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1142,11 +1142,11 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-resources.sh", - $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, + "${PODS_CONFIGURATION_BUILD_DIR}/gRPC/gRPCCertificates.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1539,6 +1539,18 @@ INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.3; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "\"${PODS_CONFIGURATION_BUILD_DIR}/BoringSSL\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/RemoteTest\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core-072e2d32\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-ProtoRPC\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-RxLibrary\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/nanopb\"", + "\"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-Core\"", + ); PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests; PRODUCT_NAME = "$(TARGET_NAME)"; USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\""; diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme index a1da2e0c97..e62edd397a 100644 --- a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" shouldUseLaunchSchemeArgsEnv = "YES"> <Testables> <TestableReference @@ -55,6 +56,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme new file mode 100644 index 0000000000..0a597e756e --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Asan.xcscheme @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0920" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + enableAddressSanitizer = "YES" + enableASanStackUseAfterReturn = "YES" + language = "" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4" + BuildableName = "CoreCronetEnd2EndTests.xctest" + BlueprintName = "CoreCronetEnd2EndTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme new file mode 100644 index 0000000000..5fe60b9692 --- /dev/null +++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests_Tsan.xcscheme @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "0920" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + enableThreadSanitizer = "YES" + language = "" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + <TestableReference + skipped = "NO"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4" + BuildableName = "CoreCronetEnd2EndTests.xctest" + BlueprintName = "CoreCronetEnd2EndTests" + ReferencedContainer = "container:Tests.xcodeproj"> + </BuildableReference> + </TestableReference> + </Testables> + <AdditionalOptions> + </AdditionalOptions> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + language = "" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <AdditionalOptions> + </AdditionalOptions> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/src/objective-c/tests/analyze_link_map.py b/src/objective-c/tests/analyze_link_map.py new file mode 100755 index 0000000000..48e3441087 --- /dev/null +++ b/src/objective-c/tests/analyze_link_map.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# Copyright 2018 gRPC authors. +# +# 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. + +# This script analyzes link map file generated by Xcode. It calculates and +# prints out the sizes of each dependent library and the total sizes of the +# symbols. +# The script takes one parameter, which is the path to the link map file. + +import sys +import re + +table_tag = {} +state = "start" + +table_stats_symbol = {} +table_stats_dead = {} +section_total_size = 0 +symbol_total_size = 0 + + +file_import = sys.argv[1] +lines = list(open(file_import)) +for line in lines: + line_stripped = line[:-1] + if "# Object files:" == line_stripped: + state = "object" + continue + elif "# Sections:" == line_stripped: + state = "section" + continue + elif "# Symbols:" == line_stripped: + state = "symbol" + continue + elif "# Dead Stripped Symbols:" == line_stripped: + state = "dead" + continue + + if state == "object": + segs = re.search('(\[ *[0-9]*\]) (.*)', line_stripped) + table_tag[segs.group(1)] = segs.group(2) + + if state == "section": + if len(line_stripped) == 0 or line_stripped[0] == '#': + continue + segs = re.search('^(.+?)\s+(.+?)\s+.*', line_stripped) + section_total_size += int(segs.group(2), 16) + + if state == "symbol": + if len(line_stripped) == 0 or line_stripped[0] == '#': + continue + segs = re.search('^.+?\s+(.+?)\s+(\[.+?\]).*', line_stripped) + target = table_tag[segs.group(2)] + target_stripped = re.search('^(.*?)(\(.+?\))?$', target).group(1) + size = int(segs.group(1), 16) + if not target_stripped in table_stats_symbol: + table_stats_symbol[target_stripped] = 0 + table_stats_symbol[target_stripped] += size + +print("Sections total size: %d" % section_total_size) + +for target in table_stats_symbol: + print(target) + print(table_stats_symbol[target]) + symbol_total_size += table_stats_symbol[target] + +print("Symbols total size: %d" % symbol_total_size) diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh index cec34787cf..2fe2326207 100755 --- a/src/objective-c/tests/run_tests.sh +++ b/src/objective-c/tests/run_tests.sh @@ -92,6 +92,26 @@ xcodebuild \ echo "TIME: $(date)" xcodebuild \ -workspace Tests.xcworkspace \ + -scheme CoreCronetEnd2EndTests_Asan \ + -destination name="iPhone 6" \ + test \ + | egrep -v "$XCODEBUILD_FILTER" \ + | egrep -v '^$' \ + | egrep -v "(GPBDictionary|GPBArray)" - + +echo "TIME: $(date)" +xcodebuild \ + -workspace Tests.xcworkspace \ + -scheme CoreCronetEnd2EndTests_Tsan \ + -destination name="iPhone 6" \ + test \ + | egrep -v "$XCODEBUILD_FILTER" \ + | egrep -v '^$' \ + | egrep -v "(GPBDictionary|GPBArray)" - + +echo "TIME: $(date)" +xcodebuild \ + -workspace Tests.xcworkspace \ -scheme CronetUnitTests \ -destination name="iPhone 6" \ test \ diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h index 6f6cd25007..e9637099d9 100644 --- a/src/objective-c/tests/version.h +++ b/src/objective-c/tests/version.h @@ -22,6 +22,5 @@ // instead. This file can be regenerated from the template by running // `tools/buildgen/generate_projects.sh`. - -#define GRPC_OBJC_VERSION_STRING @"1.11.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.13.0-dev" #define GRPC_C_VERSION_STRING @"6.0.0-dev" |