diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Category/NSURLRequest+HTTPBodyTesting.h b/PrebidMobileTests/FetchingLogictests/Shared/Category/NSURLRequest+HTTPBodyTesting.h new file mode 100644 index 000000000..65b9ae16c --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Category/NSURLRequest+HTTPBodyTesting.h @@ -0,0 +1,31 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 + +// This category is only useful when NSURLSession is present + +@interface NSURLRequest (HTTPBodyTesting) +/** + * Unfortunately, when sending POST requests (with a body) using NSURLSession, + * by the time the request arrives at OHHTTPStubs, the HTTPBody of the + * NSURLRequest has been reset to nil. + * + * You can use this method to retrieve the HTTPBody for testing and use it to + * conditionally stub your requests. + */ +- (NSData *)PBHTTPStubs_HTTPBody; + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Category/NSURLRequest+HTTPBodyTesting.m b/PrebidMobileTests/FetchingLogictests/Shared/Category/NSURLRequest+HTTPBodyTesting.m new file mode 100644 index 000000000..27f82a4ec --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Category/NSURLRequest+HTTPBodyTesting.m @@ -0,0 +1,70 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 "NSURLRequest+HTTPBodyTesting.h" + +#import "NSObject+Swizzling.h" + +#pragma mark - NSURLRequest+CustomHTTPBody + +NSString * const PBHTTPStubs_HTTPBodyKey = @"HTTPBody"; + +@implementation NSURLRequest (HTTPBodyTesting) + +- (NSData*)PBHTTPStubs_HTTPBody +{ + return [NSURLProtocol propertyForKey:PBHTTPStubs_HTTPBodyKey inRequest:self]; +} + +@end + +//////////////////////////////////////////////////////////////////////////////// +#pragma mark - NSMutableURLRequest+HTTPBodyTesting + +typedef void(*PBHHTTPStubsSetterIMP)(id, SEL, id); +static PBHHTTPStubsSetterIMP orig_setHTTPBody; + +static void PBHTTPStubs_setHTTPBody(id self, SEL _cmd, NSData* HTTPBody) +{ + // store the http body via NSURLProtocol + if (HTTPBody) { + [NSURLProtocol setProperty:HTTPBody forKey:PBHTTPStubs_HTTPBodyKey inRequest:self]; + } else { + // unfortunately resetting does not work properly as the NSURLSession also uses this to reset the property + } + + orig_setHTTPBody(self, _cmd, HTTPBody); +} + +/** + * Swizzles setHTTPBody: in order to maintain a copy of the http body for later + * reference and calls the original implementation. + * + * @warning Should not be used in production, testing only. + */ +@interface NSMutableURLRequest (HTTPBodyTesting) @end + +@implementation NSMutableURLRequest (HTTPBodyTesting) + ++ (void)load +{ + orig_setHTTPBody = (PBHHTTPStubsSetterIMP)PBHTTPStubsReplaceMethod(@selector(setHTTPBody:), + (IMP)PBHTTPStubs_setHTTPBody, + [NSMutableURLRequest class], + NO); +} + + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/PBTestGlobal.h b/PrebidMobileTests/FetchingLogictests/Shared/PBTestGlobal.h new file mode 100644 index 000000000..8958e1012 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/PBTestGlobal.h @@ -0,0 +1,50 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 + + + +#pragma mark - Constants. + +extern NSString * const kFauxMediationAdapterClassDoesNotExist; +extern NSString * const OK_RESULT_CB_URL; + + + +#pragma mark - Simple diagnostics for tests. + +#define TESTTRACE() NSLog(@" TEST TRACE %s", __PRETTY_FUNCTION__) +#define TESTTRACEM(format, ...) NSLog(@" TEST TRACE %s -- %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:format, ##__VA_ARGS__]) + +#define TESTTRACEJSON(jsonString) \ + { \ + NSData *objectData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; \ + NSError *error; \ + NSDictionary *json = [NSJSONSerialization JSONObjectWithData: objectData \ + options: NSJSONReadingMutableContainers \ + error: &error]; \ + TESTTRACEM(@"\n\t%@=%@", @ #jsonString, json); \ + } + + + + +#pragma mark - PBTestGlobal + +@interface PBTestGlobal : NSObject + //EMPTY +@end + diff --git a/PrebidMobileTests/FetchingLogictests/Shared/PBTestGlobal.m b/PrebidMobileTests/FetchingLogictests/Shared/PBTestGlobal.m new file mode 100644 index 000000000..de6608495 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/PBTestGlobal.m @@ -0,0 +1,31 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 "PBTestGlobal.h" + + + +#pragma mark - Constants. + +NSString * const kFauxMediationAdapterClassDoesNotExist = @"FauxMediationAdapterClassDoesNotExist"; + +NSString * const OK_RESULT_CB_URL = @"http://MOCK__result"; + + + +@implementation PBTestGlobal + //EMPTY +@end + diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAd.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAd.json new file mode 100644 index 000000000..8f3d138f3 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAd.json @@ -0,0 +1,52 @@ +{ + "id": "6710145726530182423", + "impid": "PrebidMobile", + "price": 0.05, + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"img\":{\"type\":1,\"url\":\"https:\/\/vcdn.adnxs.com\/p\/creative-image\/be\/53\/27\/49\/be532749-1ede-4655-91c9-3d6d07081fb6.png\",\"w\":40,\"h\":40,\"ext\":{\"appnexus\":{\"prevent_crop\":0}}}},{\"id\":2,\"img\":{\"type\":3,\"url\":\"https:\/\/vcdn.adnxs.com\/p\/creative-image\/7e\/71\/90\/27\/7e719027-80ef-4664-9b6d-a763da4cea4e.png\",\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"prevent_crop\":0}}}},{\"title\":{\"text\":\"This is an RTB ad\"}},{\"id\":3,\"data\":{\"type\":1,\"value\":\"AppNexus\"}},{\"id\":4,\"data\":{\"type\":2,\"value\":\"The industry is trending native. Just see this ad as an example. Contact AppNexus for more!\"}},{\"id\":5,\"data\":{\"type\":12,\"value\":\"More\"}}],\"link\":{\"url\":\"https:\/\/sin3-ib.adnxs.com\/click?mpmZmZmZqT-amZmZmZmpPwAAAAAAAOA_mpmZmZmZqT-amZmZmZmpPzTiAd9tv5s1qkBWN3HQUUmaML5fAAAAAHu99gBuJwAAbicAAAIAAACRL6wJ-MwcAAAAAABVU0QAVVNEAAEAAQDILwAAAAABAgMCAAAAAMYAlSbJqwAAAAA.\/bcr=AAAAAAAA8D8=\/pp=${AUCTION_PRICE}\/cnd=%21XBNcTAi4reMWEJHfsE0Y-JlzIAQoADGamZmZmZmpPzoJU0lOMzo1NDIwQL0pSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA.\/cca=MTAwOTQjU0lOMzo1NDIw\/bn=89159\/clickenc=http%3A%2F%2Fappnexus.com\"},\"jstracker\":\"\\u003cscript type=\\\"text\/javascript\\\" async=\\\"true\\\" src=\\\"https:\/\/cdn.adnxs.com\/v\/app\/201\/trk.js#app;vk=appnexus.com-omid;tv=app-native-23hs;dom_id=%native_dom_id%;st=2;d=1x1;vc=iab;vid_ccr=1;tag_id=16170363;cb=https%3A%2F%2Fsin3-ib.adnxs.com%2Fvevent%3Fan_audit%3D0%26e%3DwqT_3QLKCsBKBQAAAwDWAAUBCJrh-P0FELTEh_jd7e_NNRiqgdm6k470qEkqNgmamZmZmZmpPxGaAQgQmak_GQAFAQjgPyERGwApEQkAMQUauADgPzD7-toHOO5OQO5OSAJQkd-wTVj4mXNgAGjI34wBeMe4BYABAYoBA1VTRJIBAQbwRpgBAaABAagBAbABALgBAsABA8gBAtABANgBAOABAPABAIoCPHVmKCdhJywgMzM5MzUyMCwgMTYwNjI5OTgwMik7dWYoJ3InARQYMjI3OTMxMwELGR_w9ZIC4QMhZGxFN1JRaTRyZU1XRUpIZnNFMFlBQ0Q0bVhNd0FEZ0FRQVJJN2s1US1fcmFCMWdBWU5JR2FBQndESGlzQTRBQkRJZ0JyQU9RQVFDWUFRQ2dBUUdvQVFPd0FRQzVBWFdyRFd5YW1ha193UUYxcXcxc21wbXBQOGtCV2d3dGlyU085VF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJ1Z01KVTBsT016bzFOREl3NEFPOUtZZ0VBSkFFQUpnRUFjRUVBQUFBQQVqCERKQgUICQEYMkFRQThRUQkNAQEcSWdGckNxcEIRExRQQV9zUVUBGgkBCE1FRgkJAQEEREoVKAxBQUEwLigABE5rLigAuGdCWWduOEFYaV9mRUQtQVh3ajg4QmdnWURWVk5FaUFZQWtBWUJtQVlBb1FhYW1aBQIscFA2Z0dBYklHSkFrAV8JAQBCKSAFAQRCawUHBQEAQx0YRExnR0NnLi6aAokBIVhCTmNUQTblASwtSmx6SUFRb0FER2EFaxhabXBQem9KLkUBEFFMMHBTPQUAVREMDEFBQVcdDABZHQwAYR0MAGMdDPBhZUFBLtgCAOACyqhNgAMAiAMBkAMAmAMUoAMBqgMAwAPgqAHIAwDSAzAIEBIkZDlhOGZkMDktMDExMy00NmEzLThkZjMtYzFhMWVlYzJiZWVlGAEiBGRwaWTSAyoIChIkZDmKMwD0DgEA2AMA4AMA6AMC-AMAgAQAkgQJL29wZW5ydGIymAQAogQPMjIzLjIyNi4xNDguMjM5qAS2TrIEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEDzEwMDk0I1NJTjM6NTQyMNoEAggB4AQA8ASR37BNggUgb3JnLnByZWJpZC5tb2JpbGUucHJlYmlkamF2YWRlbW-IBQGYBQCgBf___________wGqBSQ0NjU0OTNhYS0wYTNjLTRjYTQtOTE1Zi1mMmM5ZjEzNzc5NDHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AUB-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8D_QBtYz2gYWChAABREZAVwQABgA4AYM8gYCCACABwGIBwCgB0G6Bw8BSAAYCf4w6Q1AAMgHx7gF0gcNCRE6AThA2gcGCAAQABgA4AcA6gcCCAA.%26s%3Dc3ae5f12da6cbacd1d7150499062dec2bf608365;ts=1606299802;cet=0;cecb=\\\"\\u003e\\u003c\/script\\u003e\",\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"https:\/\/sin3-ib.adnxs.com\/it?an_audit=0\\u0026e=wqT_3QLKCsBKBQAAAwDWAAUBCJrh-P0FELTEh_jd7e_NNRiqgdm6k470qEkqNgmamZmZmZmpPxGaAQgQmak_GQAFAQjgPyERGwApEQkAMQUauADgPzD7-toHOO5OQO5OSAJQkd-wTVj4mXNgAGjI34wBeMe4BYABAYoBA1VTRJIBAQbwRpgBAaABAagBAbABALgBAsABA8gBAtABANgBAOABAPABAIoCPHVmKCdhJywgMzM5MzUyMCwgMTYwNjI5OTgwMik7dWYoJ3InARQYMjI3OTMxMwELGR_w9ZIC4QMhZGxFN1JRaTRyZU1XRUpIZnNFMFlBQ0Q0bVhNd0FEZ0FRQVJJN2s1US1fcmFCMWdBWU5JR2FBQndESGlzQTRBQkRJZ0JyQU9RQVFDWUFRQ2dBUUdvQVFPd0FRQzVBWFdyRFd5YW1ha193UUYxcXcxc21wbXBQOGtCV2d3dGlyU085VF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJ1Z01KVTBsT016bzFOREl3NEFPOUtZZ0VBSkFFQUpnRUFjRUVBQUFBQQVqCERKQgUICQEYMkFRQThRUQkNAQEcSWdGckNxcEIRExRQQV9zUVUBGgkBCE1FRgkJAQEEREoVKAxBQUEwLigABE5rLigAuGdCWWduOEFYaV9mRUQtQVh3ajg4QmdnWURWVk5FaUFZQWtBWUJtQVlBb1FhYW1aBQIscFA2Z0dBYklHSkFrAV8JAQBCKSAFAQRCawUHBQEAQx0YRExnR0NnLi6aAokBIVhCTmNUQTblASwtSmx6SUFRb0FER2EFaxhabXBQem9KLkUBEFFMMHBTPQUAVREMDEFBQVcdDABZHQwAYR0MAGMdDPBhZUFBLtgCAOACyqhNgAMAiAMBkAMAmAMUoAMBqgMAwAPgqAHIAwDSAzAIEBIkZDlhOGZkMDktMDExMy00NmEzLThkZjMtYzFhMWVlYzJiZWVlGAEiBGRwaWTSAyoIChIkZDmKMwD0DgEA2AMA4AMA6AMC-AMAgAQAkgQJL29wZW5ydGIymAQAogQPMjIzLjIyNi4xNDguMjM5qAS2TrIEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEDzEwMDk0I1NJTjM6NTQyMNoEAggB4AQA8ASR37BNggUgb3JnLnByZWJpZC5tb2JpbGUucHJlYmlkamF2YWRlbW-IBQGYBQCgBf___________wGqBSQ0NjU0OTNhYS0wYTNjLTRjYTQtOTE1Zi1mMmM5ZjEzNzc5NDHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AUB-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8D_QBtYz2gYWChAABREZAVwQABgA4AYM8gYCCACABwGIBwCgB0G6Bw8BSAAYCf4w6Q1AAMgHx7gF0gcNCRE6AThA2gcGCAAQABgA4AcA6gcCCAA.\\u0026s=c3ae5f12da6cbacd1d7150499062dec2bf608365\\u0026pp=${AUCTION_PRICE}\"}]}", + "adid": "162279313", + "adomain": [ + "appnexus.com" + ], + "iurl": "https:\/\/sin3-ib.adnxs.com\/cr?id=162279313", + "cid": "10094", + "crid": "162279313", + "ext": { + "prebid": { + "cache": { + "key": "", + "url": "", + "bids": { + "url": "prebid.sin3.adnxs.com\/pbc\/v1\/cache?uuid=dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "cacheId": "dfad62f2-8ed5-4cf8-a597-f702147b7c98" + } + }, + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_cache_host": "prebid.sin3.adnxs.com", + "hb_cache_host_appnex": "prebid.sin3.adnxs.com", + "hb_cache_id": "dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "hb_cache_id_appnexus": "dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "hb_cache_path": "\/pbc\/v1\/cache", + "hb_cache_path_appnex": "\/pbc\/v1\/cache", + "hb_env": "mobile-app", + "hb_env_appnexus": "mobile-app", + "hb_pb": "0.00", + "hb_pb_appnexus": "0.00" + }, + "type": "native", + "video": { + "duration": 0, + "primary_category": "" + } + }, + "bidder": { + "appnexus": { + "brand_id": 1, + "auction_id": 3862891584014115380, + "bidder_id": 2, + "bid_ad_type": 3 + } + } + } +} diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAdInvalidResponse.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAdInvalidResponse.json new file mode 100644 index 000000000..1f3690aee --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAdInvalidResponse.json @@ -0,0 +1,69 @@ +{ + "id": "465493aa-0a3c-4ca4-915f-f2c9f1377941", + "seatbid": [ + { + "bid": [ + { + "id": "6710145726530182423", + "impid": "PrebidMobile", + "price": 0.05, + "adm": "Invalid", + "adid": "162279313", + "adomain": [ + "appnexus.com" + ], + "iurl": "https:\/\/sin3-ib.adnxs.com\/cr?id=162279313", + "cid": "10094", + "crid": "162279313", + "ext": { + "prebid": { + "cache": { + "key": "", + "url": "", + "bids": { + "url": "prebid.sin3.adnxs.com\/pbc\/v1\/cache?uuid=dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "cacheId": "dfad62f2-8ed5-4cf8-a597-f702147b7c98" + } + }, + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_cache_host": "prebid.sin3.adnxs.com", + "hb_cache_host_appnex": "prebid.sin3.adnxs.com", + "hb_cache_id": "dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "hb_cache_id_appnexus": "dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "hb_cache_path": "\/pbc\/v1\/cache", + "hb_cache_path_appnex": "\/pbc\/v1\/cache", + "hb_env": "mobile-app", + "hb_env_appnexus": "mobile-app", + "hb_pb": "0.00", + "hb_pb_appnexus": "0.00" + }, + "type": "native", + "video": { + "duration": 0, + "primary_category": "" + } + }, + "bidder": { + "appnexus": { + "brand_id": 1, + "auction_id": 3862891584014115380, + "bidder_id": 2, + "bid_ad_type": 3 + } + } + } + } + ], + "seat": "appnexus" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "appnexus": 32 + }, + "tmaxrequest": 500 + } +} diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAdResponse.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAdResponse.json new file mode 100644 index 000000000..101549d7f --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/NativeAdResponse.json @@ -0,0 +1,70 @@ +{ + "id": "465493aa-0a3c-4ca4-915f-f2c9f1377941", + "seatbid": [ + { + "bid": [ + { + "exp": 100, + "id": "6710145726530182423", + "impid": "PrebidMobile", + "price": 0.05, + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"img\":{\"type\":1,\"url\":\"https:\/\/vcdn.adnxs.com\/p\/creative-image\/be\/53\/27\/49\/be532749-1ede-4655-91c9-3d6d07081fb6.png\",\"w\":40,\"h\":40,\"ext\":{\"appnexus\":{\"prevent_crop\":0}}}},{\"id\":2,\"img\":{\"type\":3,\"url\":\"https:\/\/vcdn.adnxs.com\/p\/creative-image\/7e\/71\/90\/27\/7e719027-80ef-4664-9b6d-a763da4cea4e.png\",\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"prevent_crop\":0}}}},{\"title\":{\"text\":\"This is an RTB ad\"}},{\"id\":3,\"data\":{\"type\":1,\"value\":\"AppNexus\"}},{\"id\":4,\"data\":{\"type\":2,\"value\":\"The industry is trending native. Just see this ad as an example. Contact AppNexus for more!\"}},{\"id\":5,\"data\":{\"type\":12,\"value\":\"More\"}}],\"link\":{\"url\":\"https:\/\/sin3-ib.adnxs.com\/click?mpmZmZmZqT-amZmZmZmpPwAAAAAAAOA_mpmZmZmZqT-amZmZmZmpPzTiAd9tv5s1qkBWN3HQUUmaML5fAAAAAHu99gBuJwAAbicAAAIAAACRL6wJ-MwcAAAAAABVU0QAVVNEAAEAAQDILwAAAAABAgMCAAAAAMYAlSbJqwAAAAA.\/bcr=AAAAAAAA8D8=\/pp=${AUCTION_PRICE}\/cnd=%21XBNcTAi4reMWEJHfsE0Y-JlzIAQoADGamZmZmZmpPzoJU0lOMzo1NDIwQL0pSQAAAAAAAPA_UQAAAAAAAAAAWQAAAAAAAAAAYQAAAAAAAAAAaQAAAAAAAAAAcQAAAAAAAAAAeAA.\/cca=MTAwOTQjU0lOMzo1NDIw\/bn=89159\/clickenc=http%3A%2F%2Fappnexus.com\"},\"jstracker\":\"\\u003cscript type=\\\"text\/javascript\\\" async=\\\"true\\\" src=\\\"https:\/\/cdn.adnxs.com\/v\/app\/201\/trk.js#app;vk=appnexus.com-omid;tv=app-native-23hs;dom_id=%native_dom_id%;st=2;d=1x1;vc=iab;vid_ccr=1;tag_id=16170363;cb=https%3A%2F%2Fsin3-ib.adnxs.com%2Fvevent%3Fan_audit%3D0%26e%3DwqT_3QLKCsBKBQAAAwDWAAUBCJrh-P0FELTEh_jd7e_NNRiqgdm6k470qEkqNgmamZmZmZmpPxGaAQgQmak_GQAFAQjgPyERGwApEQkAMQUauADgPzD7-toHOO5OQO5OSAJQkd-wTVj4mXNgAGjI34wBeMe4BYABAYoBA1VTRJIBAQbwRpgBAaABAagBAbABALgBAsABA8gBAtABANgBAOABAPABAIoCPHVmKCdhJywgMzM5MzUyMCwgMTYwNjI5OTgwMik7dWYoJ3InARQYMjI3OTMxMwELGR_w9ZIC4QMhZGxFN1JRaTRyZU1XRUpIZnNFMFlBQ0Q0bVhNd0FEZ0FRQVJJN2s1US1fcmFCMWdBWU5JR2FBQndESGlzQTRBQkRJZ0JyQU9RQVFDWUFRQ2dBUUdvQVFPd0FRQzVBWFdyRFd5YW1ha193UUYxcXcxc21wbXBQOGtCV2d3dGlyU085VF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJ1Z01KVTBsT016bzFOREl3NEFPOUtZZ0VBSkFFQUpnRUFjRUVBQUFBQQVqCERKQgUICQEYMkFRQThRUQkNAQEcSWdGckNxcEIRExRQQV9zUVUBGgkBCE1FRgkJAQEEREoVKAxBQUEwLigABE5rLigAuGdCWWduOEFYaV9mRUQtQVh3ajg4QmdnWURWVk5FaUFZQWtBWUJtQVlBb1FhYW1aBQIscFA2Z0dBYklHSkFrAV8JAQBCKSAFAQRCawUHBQEAQx0YRExnR0NnLi6aAokBIVhCTmNUQTblASwtSmx6SUFRb0FER2EFaxhabXBQem9KLkUBEFFMMHBTPQUAVREMDEFBQVcdDABZHQwAYR0MAGMdDPBhZUFBLtgCAOACyqhNgAMAiAMBkAMAmAMUoAMBqgMAwAPgqAHIAwDSAzAIEBIkZDlhOGZkMDktMDExMy00NmEzLThkZjMtYzFhMWVlYzJiZWVlGAEiBGRwaWTSAyoIChIkZDmKMwD0DgEA2AMA4AMA6AMC-AMAgAQAkgQJL29wZW5ydGIymAQAogQPMjIzLjIyNi4xNDguMjM5qAS2TrIEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEDzEwMDk0I1NJTjM6NTQyMNoEAggB4AQA8ASR37BNggUgb3JnLnByZWJpZC5tb2JpbGUucHJlYmlkamF2YWRlbW-IBQGYBQCgBf___________wGqBSQ0NjU0OTNhYS0wYTNjLTRjYTQtOTE1Zi1mMmM5ZjEzNzc5NDHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AUB-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8D_QBtYz2gYWChAABREZAVwQABgA4AYM8gYCCACABwGIBwCgB0G6Bw8BSAAYCf4w6Q1AAMgHx7gF0gcNCRE6AThA2gcGCAAQABgA4AcA6gcCCAA.%26s%3Dc3ae5f12da6cbacd1d7150499062dec2bf608365;ts=1606299802;cet=0;cecb=\\\"\\u003e\\u003c\/script\\u003e\",\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"https:\/\/sin3-ib.adnxs.com\/it?an_audit=0\\u0026e=wqT_3QLKCsBKBQAAAwDWAAUBCJrh-P0FELTEh_jd7e_NNRiqgdm6k470qEkqNgmamZmZmZmpPxGaAQgQmak_GQAFAQjgPyERGwApEQkAMQUauADgPzD7-toHOO5OQO5OSAJQkd-wTVj4mXNgAGjI34wBeMe4BYABAYoBA1VTRJIBAQbwRpgBAaABAagBAbABALgBAsABA8gBAtABANgBAOABAPABAIoCPHVmKCdhJywgMzM5MzUyMCwgMTYwNjI5OTgwMik7dWYoJ3InARQYMjI3OTMxMwELGR_w9ZIC4QMhZGxFN1JRaTRyZU1XRUpIZnNFMFlBQ0Q0bVhNd0FEZ0FRQVJJN2s1US1fcmFCMWdBWU5JR2FBQndESGlzQTRBQkRJZ0JyQU9RQVFDWUFRQ2dBUUdvQVFPd0FRQzVBWFdyRFd5YW1ha193UUYxcXcxc21wbXBQOGtCV2d3dGlyU085VF9aQVFBQUFBQUFBUEFfNEFFQTlRRUFBQUFBbUFJQW9BSUF0UUlBQUFBQXZRSUFBQUFBNEFJQTZBSUEtQUlBZ0FNQm1BTUJ1Z01KVTBsT016bzFOREl3NEFPOUtZZ0VBSkFFQUpnRUFjRUVBQUFBQQVqCERKQgUICQEYMkFRQThRUQkNAQEcSWdGckNxcEIRExRQQV9zUVUBGgkBCE1FRgkJAQEEREoVKAxBQUEwLigABE5rLigAuGdCWWduOEFYaV9mRUQtQVh3ajg4QmdnWURWVk5FaUFZQWtBWUJtQVlBb1FhYW1aBQIscFA2Z0dBYklHSkFrAV8JAQBCKSAFAQRCawUHBQEAQx0YRExnR0NnLi6aAokBIVhCTmNUQTblASwtSmx6SUFRb0FER2EFaxhabXBQem9KLkUBEFFMMHBTPQUAVREMDEFBQVcdDABZHQwAYR0MAGMdDPBhZUFBLtgCAOACyqhNgAMAiAMBkAMAmAMUoAMBqgMAwAPgqAHIAwDSAzAIEBIkZDlhOGZkMDktMDExMy00NmEzLThkZjMtYzFhMWVlYzJiZWVlGAEiBGRwaWTSAyoIChIkZDmKMwD0DgEA2AMA4AMA6AMC-AMAgAQAkgQJL29wZW5ydGIymAQAogQPMjIzLjIyNi4xNDguMjM5qAS2TrIEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEDzEwMDk0I1NJTjM6NTQyMNoEAggB4AQA8ASR37BNggUgb3JnLnByZWJpZC5tb2JpbGUucHJlYmlkamF2YWRlbW-IBQGYBQCgBf___________wGqBSQ0NjU0OTNhYS0wYTNjLTRjYTQtOTE1Zi1mMmM5ZjEzNzc5NDHABQDJBQAAAAAAAPA_0gUJCQAAAAAAAAAA2AUB4AUB8AUB-gUECAAQAJAGAZgGALgGAMEGAAAAAAAA8D_QBtYz2gYWChAABREZAVwQABgA4AYM8gYCCACABwGIBwCgB0G6Bw8BSAAYCf4w6Q1AAMgHx7gF0gcNCRE6AThA2gcGCAAQABgA4AcA6gcCCAA.\\u0026s=c3ae5f12da6cbacd1d7150499062dec2bf608365\\u0026pp=${AUCTION_PRICE}\"}]}", + "adid": "162279313", + "adomain": [ + "appnexus.com" + ], + "iurl": "https:\/\/sin3-ib.adnxs.com\/cr?id=162279313", + "cid": "10094", + "crid": "162279313", + "ext": { + "prebid": { + "cache": { + "key": "", + "url": "", + "bids": { + "url": "prebid.sin3.adnxs.com\/pbc\/v1\/cache?uuid=dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "cacheId": "dfad62f2-8ed5-4cf8-a597-f702147b7c98" + } + }, + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_cache_host": "prebid.sin3.adnxs.com", + "hb_cache_host_appnex": "prebid.sin3.adnxs.com", + "hb_cache_id": "dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "hb_cache_id_appnexus": "dfad62f2-8ed5-4cf8-a597-f702147b7c98", + "hb_cache_path": "\/pbc\/v1\/cache", + "hb_cache_path_appnex": "\/pbc\/v1\/cache", + "hb_env": "mobile-app", + "hb_env_appnexus": "mobile-app", + "hb_pb": "0.00", + "hb_pb_appnexus": "0.00" + }, + "type": "native", + "video": { + "duration": 0, + "primary_category": "" + } + }, + "bidder": { + "appnexus": { + "brand_id": 1, + "auction_id": 3862891584014115380, + "bidder_id": 2, + "bid_ad_type": 3 + } + } + } + } + ], + "seat": "appnexus" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "appnexus": 32 + }, + "tmaxrequest": 500 + } +} diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/PrebidServerOneBidFromAppNexusOneBidFromRubicon.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/PrebidServerOneBidFromAppNexusOneBidFromRubicon.json new file mode 100644 index 000000000..31a4853df --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/PrebidServerOneBidFromAppNexusOneBidFromRubicon.json @@ -0,0 +1,96 @@ +{ + "id": "3dc76667-a500-4e01-a43b-368e36d6c7cc", + "seatbid": [ + { + "bid": [ + { + "id": "4761106207662573395", + "impid": "Banner_300x250", + "price": 0.5, + "adm": "", + "adid": "822732502", + "adomain": [ + "gilt.com" + ], + "iurl": "https://nym1-ib.adnxs.com/cr?id=822732502", + "cid": "903", + "crid": "822732502", + "cat": [ + "IAB22", + "IAB22-4" + ], + "w": 300, + "h": 250, + "ext": { + "prebid": { + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_cache_id": "7008d51d-af2a-4357-acea-1cb672ac2189", + "hb_cache_id_appnexus": "7008d51d-af2a-4357-acea-1cb672ac2189", + "hb_env": "mobile-app", + "hb_env_appnexus": "mobile-app", + "hb_pb": "0.50", + "hb_pb_appnexus": "0.50", + "hb_size": "300x250", + "hb_size_appnexus": "300x250" + }, + "type": "banner" + }, + "bidder": { + "appnexus": { + "brand_id": 1665, + "auction_id": 2672683681442768515, + "bidder_id": 52, + "bid_ad_type": 0 + } + } + } + } + ], + "seat": "appnexus" + } + ], + "ext": { + "responsetimemillis": { + "appnexus": 41 + }, + "tmaxrequest": 500 + } +} diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseIncorrectFormat.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseIncorrectFormat.json new file mode 100644 index 000000000..0bda6bc83 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseIncorrectFormat.json @@ -0,0 +1 @@ +Invalid request: pq: invalid input syntax for uuid: "123df0" diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidAccountId.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidAccountId.json new file mode 100644 index 000000000..b2cf0f5c9 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidAccountId.json @@ -0,0 +1 @@ +Invalid request: Stored Request with ID="6ace8c7d-88c0-4623-8117-75bc3f0a2e45" not found. diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidConfigId.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidConfigId.json new file mode 100644 index 000000000..a531fa8bf --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidConfigId.json @@ -0,0 +1 @@ +Invalid request: Stored Imp with ID="6ace8c7d-88c0-4623-8117-75bc3f0a2123" not found. diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidNoTopCacheId.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidNoTopCacheId.json new file mode 100644 index 000000000..32ad2ad57 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseInvalidNoTopCacheId.json @@ -0,0 +1,95 @@ +{ + "id": "3dc76667-a500-4e01-a43b-368e36d6c7cc", + "seatbid": [ + { + "bid": [ + { + "id": "5805621923512124230", + "impid": "Banner_300x250", + "price": 0.5, + "adm": "", + "adid": "113276871", + "adomain": [ + "appnexus.com" + ], + "iurl": "https://nym1-ib.adnxs.com/cr?id=113276871", + "cid": "9325", + "crid": "113276871", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_creative_loadtype": "html", + "hb_env": "mobile-app", + "hb_env_appnexus": "mobile-app", + "hb_pb": "0.50", + "hb_pb_appnexus": "0.50", + "hb_size": "300x250", + "hb_size_appnexus": "300x250" + }, + "type": "banner" + }, + "bidder": { + "appnexus": { + "brand_id": 1, + "auction_id": 7888349588523321000, + "bidder_id": 2, + "bid_ad_type": 0 + } + } + } + } + ], + "seat": "appnexus" + } + ], + "ext": { + "responsetimemillis": { + "appnexus": 213 + }, + "tmaxrequest": 500 + } +} diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseRubiconPBM.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseRubiconPBM.json new file mode 100644 index 000000000..3db0d7688 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseRubiconPBM.json @@ -0,0 +1,67 @@ +{ + "id": "914092c6-e619-4d75-9bde-4c7dbff99c42", + "seatbid": [ + { + "bid": [ + { + "id": "0", + "impid": "Banner_300x250", + "price": 1.230000, + "adm": "", + "crid": "4458534", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "targeting": { + "hb_env": "mobile-app", + "hb_cache_hostpath": "https://prebid-cache-europe.rubiconproject.com/cache", + "hb_size_rubicon": "300x250", + "hb_cache_id": "a2f41588-4727-425c-9ef0-3b382debef1e", + "hb_cache_path_rubicon": "/cache", + "hb_cache_host_rubicon": "prebid-cache-europe.rubiconproject.com", + "hb_pb": "1.20", + "hb_pb_rubicon": "1.20", + "hb_cache_id_rubicon": "a2f41588-4727-425c-9ef0-3b382debef1e", + "hb_cache_path": "/cache", + "hb_size": "300x250", + "hb_cache_hostpath_rubicon": "https://prebid-cache-europe.rubiconproject.com/cache", + "hb_env_rubicon": "mobile-app", + "hb_bidder": "rubicon", + "hb_bidder_rubicon": "rubicon", + "hb_cache_host": "prebid-cache-europe.rubiconproject.com" + }, + "cache": { + "bids": { + "url": "https://prebid-cache-europe.rubiconproject.com/cache?uuid=a2f41588-4727-425c-9ef0-3b382debef1e", + "cacheId": "a2f41588-4727-425c-9ef0-3b382debef1e" + } + } + }, + "bidder": { + "rp": { + "targeting": [{ + "key": "rpfl_1001", + "values": ["15_tier0100"] + }], + "mime": "text/html", + "size_id": 15 + } + } + } + } + ], + "seat": "rubicon", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "cache": 6, + "appnexus": 108, + "rubicon": 10 + }, + "tmaxrequest": 2000 + } +} \ No newline at end of file diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseValidTwoBidsOnTheSameSeat.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseValidTwoBidsOnTheSameSeat.json new file mode 100644 index 000000000..071d35fbc --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseValidTwoBidsOnTheSameSeat.json @@ -0,0 +1,100 @@ +{ + "id": "3dc76667-a500-4e01-a43b-368e36d6c7cc", + "seatbid": [ + { + "bid": [ + { + "id": "2194228411441933100", + "impid": "Banner_300x250", + "price": 0.086657, + "adm": "", + "adid": "134452896", + "adomain": [ + "justfab.com" + ], + "iurl": "https://lax1-ib.adnxs.com/cr?id=134452896", + "cid": "1088", + "crid": "134452896", + "cat": [ + "IAB18", + "IAB18-5", + "IAB18-3" + ], + "w": 300, + "h": 250, + "ext": { + "prebid": { + "targeting": { + "hb_bidder": "appnexus", + "hb_bidder_appnexus": "appnexus", + "hb_cache_id": "fdc4a3b1-ecdd-4c0a-b043-7ed66dca0553", + "hb_cache_id_appnexus": "fdc4a3b1-ecdd-4c0a-b043-7ed66dca0553", + "hb_env": "mobile-app", + "hb_env_appnexus": "mobile-app", + "hb_pb": "0.08", + "hb_pb_appnexus": "0.08", + "hb_size": "300x250", + "hb_size_appnexus": "300x250" + }, + "type": "banner" + }, + "bidder": { + "appnexus": { + "brand_id": 5569, + "auction_id": 2436078676556218526, + "bidder_id": 82, + "bid_ad_type": 0 + } + } + } + }, + { + "id": "1420991606454718656", + "impid": "Banner_300x250", + "price": 0.018341, + "adm": "", + "adid": "112019423", + "adomain": [ + "inspirato.com" + ], + "iurl": "https://lax1-ib.adnxs.com/cr?id=112019423", + "cid": "406", + "crid": "112019423", + "cat": [ + "IAB20-7", + "IAB20-1", + "IAB20-9", + "IAB20-6", + "IAB20", + "IAB20-17", + "IAB20-12" + ], + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + }, + "bidder": { + "appnexus": { + "brand_id": 9562, + "auction_id": 2436078676556218526, + "bidder_id": 2, + "bid_ad_type": 0 + } + } + } + } + ], + "seat": "appnexus" + } + ], + "ext": { + "responsetimemillis": { + "appnexus": 117, + "pubmatic": 13, + "rubicon": 128 + }, + "tmaxrequest": 500 + } +} \ No newline at end of file diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseinvalidSize.json b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseinvalidSize.json new file mode 100644 index 000000000..581070216 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Responses/responseinvalidSize.json @@ -0,0 +1 @@ +Invalid request: Request imp[0].banner.format[0] must define non-zero "h" and "w" properties. diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubURLProtocol.h b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubURLProtocol.h new file mode 100644 index 000000000..7f2787a67 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubURLProtocol.h @@ -0,0 +1,23 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 + +extern NSString *const kPBHTTPStubURLProtocolRequestDidLoadNotification; +extern NSString *const kPBHTTPStubURLProtocolRequest; + +@interface PBHTTPStubURLProtocol : NSURLProtocol + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubURLProtocol.m b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubURLProtocol.m new file mode 100644 index 000000000..84e86a89b --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubURLProtocol.m @@ -0,0 +1,119 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 "PBHTTPStubURLProtocol.h" +#import "PBHTTPStubbingManager.h" + +#import "PBTestGlobal.h" + + + +static NSString *const kPBTestHTTPStubURLProtocolExceptionKey = @"kPBTestHTTPStubURLProtocolExceptionKey"; +NSString *const kPBHTTPStubURLProtocolRequestDidLoadNotification = @"kPBHTTPStubURLProtocolRequestDidLoadNotification"; +NSString *const kPBHTTPStubURLProtocolRequest = @"kPBHTTPStubURLProtocolRequest"; + + + +@implementation PBHTTPStubURLProtocol + ++ (BOOL)canInitWithRequest:(NSURLRequest *)request +{ + BOOL broadcastRequests = [PBHTTPStubbingManager sharedStubbingManager].broadcastRequests; + + if (broadcastRequests && request) { + [[NSNotificationCenter defaultCenter] postNotificationName:kPBHTTPStubURLProtocolRequestDidLoadNotification + object:nil + userInfo:@{kPBHTTPStubURLProtocolRequest:request}]; + } + + BOOL isHttpOrHttps = [request.URL.scheme isEqualToString:@"http"] || [request.URL.scheme isEqualToString:@"https"]; + if (!isHttpOrHttps) { + return NO; + } + + BOOL ignoreUnstubbedRequests = [PBHTTPStubbingManager sharedStubbingManager].ignoreUnstubbedRequests; + if (ignoreUnstubbedRequests) { + PBURLConnectionStub *stub = [[PBHTTPStubbingManager sharedStubbingManager] stubForURLString:request.URL.absoluteString]; + return (stub != nil); + } else { + return YES; + } +} + ++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { + return request; +} + ++ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { + return NO; +} + +- (void)startLoading { + id client = self.client; + PBURLConnectionStub *stub = [self stubForRequest]; + + if (stub) { + NSURLResponse *response = [self buildResponseForRequestUsingStub:stub]; + [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + + NSData *responseData = [self buildDataForRequestUsingStub:stub]; + [client URLProtocol:self didLoadData:responseData]; + + [client URLProtocolDidFinishLoading:self]; + NSLog(@"Successfully loaded request from stub: %@", [self request]); + + } else { + NSLog(@"Could not load request successfully: %@", [self request]); + NSLog(@"This can happen if the request was not stubbed, or if the stubs were removed before this request was completed (due to asynchronous request loading)."); + [client URLProtocol: self + didFailWithError: [NSError errorWithDomain: kPBTestHTTPStubURLProtocolExceptionKey + code: 1 + userInfo: nil ] + ]; + } +} + +- (void)stopLoading { + // Do nothing, but method is required. +} + + + + +#pragma mark - Stubbing + +- (PBURLConnectionStub *)stubForRequest { + return [[PBHTTPStubbingManager sharedStubbingManager] stubForURLString:self.request.URL.absoluteString]; +} + + +- (NSURLResponse *)buildResponseForRequestUsingStub:(PBURLConnectionStub *)stub { + NSHTTPURLResponse *httpResponse = [[NSHTTPURLResponse alloc] initWithURL:[[self request] URL] + statusCode:stub.responseCode + HTTPVersion:@"HTTP/1.1" + headerFields:@{}]; + return httpResponse; +} + +- (NSData *)buildDataForRequestUsingStub:(PBURLConnectionStub *)stub { + if ([stub.responseBody isKindOfClass:[NSString class]]) { + return [stub.responseBody dataUsingEncoding:NSUTF8StringEncoding]; + } else if ([stub.responseBody isKindOfClass:[NSData class]]) { + return stub.responseBody; + } + return nil; +} + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubbingManager.h b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubbingManager.h new file mode 100644 index 000000000..558827385 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubbingManager.h @@ -0,0 +1,57 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 "PBHTTPStubURLProtocol.h" +#import "PBURLConnectionStub.h" + + + + +@interface PBHTTPStubbingManager : NSObject + +/** + If set to YES, then unstubbed requests will be ignored by this class and handled by the system. + If set to NO (default), then unstubbed requests will result in didFailToLoad errors. + + Default is NO. + */ +@property (nonatomic) BOOL ignoreUnstubbedRequests; + +/** + If set to YES, then all requests which trigger canInitWithRequest: will be broadcast + as kPBHTTPStubURLProtocolRequestDidLoadNotification notifications. The request will be in the user info, + as the value of the kPBHTTPStubURLProtocolRequest key. + + Default is NO. + */ +@property (nonatomic) BOOL broadcastRequests; + + + ++ (PBHTTPStubbingManager *)sharedStubbingManager; + +- (void)enable; +- (void)disable; + +- (void)addStub:(PBURLConnectionStub *)stub; +- (void)addStubs:(NSArray *)stubs; +- (void)removeAllStubs; + +- (PBURLConnectionStub *)stubForURLString:(NSString *)URLString; + +// ++ (NSDictionary *) jsonBodyOfURLRequestAsDictionary: (NSURLRequest *)urlRequest; + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubbingManager.m b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubbingManager.m new file mode 100644 index 000000000..408210092 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBHTTPStubbingManager.m @@ -0,0 +1,114 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 "PBHTTPStubbingManager.h" +#import "PBHTTPStubURLProtocol.h" +#import "PBTestGlobal.h" +//#import "ANSDKSettings.h" + +#import "NSURLRequest+HTTPBodyTesting.h" + + + + +@interface PBHTTPStubbingManager() +@property (nonatomic) NSMutableArray *stubs; +@end + + + + +@implementation PBHTTPStubbingManager + ++ (PBHTTPStubbingManager *)sharedStubbingManager { + static dispatch_once_t sharedStubbingManagerToken; + static PBHTTPStubbingManager *manager; + dispatch_once(&sharedStubbingManagerToken, ^{ + manager = [[PBHTTPStubbingManager alloc] init]; + }); + return manager; +} + +- (void)enable { + [NSURLProtocol registerClass:[PBHTTPStubURLProtocol class]]; +} + +- (void)disable { + [NSURLProtocol unregisterClass:[PBHTTPStubURLProtocol class]]; +} + +- (void)addStub:(PBURLConnectionStub *)stub { + [self.stubs addObject:stub]; +} + +- (void)addStubs:(NSArray *)stubs { + [self.stubs addObjectsFromArray:stubs]; +} + +- (void)removeAllStubs { + [self.stubs removeAllObjects]; +} + +- (NSMutableArray *)stubs { + @synchronized(self) { + if (!_stubs) _stubs = [[NSMutableArray alloc] init]; + return _stubs; + } +} + +- (PBURLConnectionStub *)stubForURLString:(NSString *)URLString +{ + __block PBURLConnectionStub *stubMatch = nil; + + [self.stubs enumerateObjectsUsingBlock: ^(PBURLConnectionStub *stub, NSUInteger idx, BOOL *stop) + { + NSError *error; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern: stub.requestURL + options: NSRegularExpressionDotMatchesLineSeparators + error: &error]; + if ([regex numberOfMatchesInString: URLString + options: 0 + range: NSMakeRange(0, [URLString length])]) + { + stubMatch = stub; + *stop = YES; + } + } ]; + return stubMatch; +} + + + + +#pragma mark - Helper class methods. + ++ (NSDictionary *) jsonBodyOfURLRequestAsDictionary: (NSURLRequest *)urlRequest +{ + TESTTRACE(); + + NSString *bodyAsString = [[NSString alloc] initWithData:[urlRequest PBHTTPStubs_HTTPBody] encoding:NSUTF8StringEncoding]; + NSData *objectData = [bodyAsString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *error = nil; + + NSDictionary *json = [NSJSONSerialization JSONObjectWithData: objectData + options: NSJSONReadingMutableContainers + error: &error]; + if (error) { return nil; } + + return json; +} + + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub+NSURLSessionConfiguration.m b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub+NSURLSessionConfiguration.m new file mode 100644 index 000000000..cf5cef272 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub+NSURLSessionConfiguration.m @@ -0,0 +1,64 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 + +#import "PBURLConnectionStub.h" +#import "NSObject+Swizzling.h" + + +/** + * This helper is used to swizzle NSURLSessionConfiguration constructor methods + * defaultSessionConfiguration and ephemeralSessionConfiguration to insert the private + * OHHTTPStubsProtocol into their protocolClasses array so that OHHTTPStubs is automagically + * supported when you create a new NSURLSession based on one of there configurations. + */ + +typedef NSURLSessionConfiguration*(*SessionConfigConstructor)(id,SEL); +static SessionConfigConstructor orig_defaultSessionConfiguration; +static SessionConfigConstructor orig_ephemeralSessionConfiguration; + +static NSURLSessionConfiguration* PBHTTPStubs_defaultSessionConfiguration(id self, SEL _cmd) +{ + NSURLSessionConfiguration* config = orig_defaultSessionConfiguration(self,_cmd); // call original method + [PBURLConnectionStub setEnabled:YES forSessionConfiguration:config]; // + return config; +} + +static NSURLSessionConfiguration* PBHTTPStubs_ephemeralSessionConfiguration(id self, SEL _cmd) +{ + NSURLSessionConfiguration* config = orig_ephemeralSessionConfiguration(self,_cmd); // call original method + [PBURLConnectionStub setEnabled:YES forSessionConfiguration:config]; // + return config; +} + +@interface NSURLSessionConfiguration(PBHTTPStubsSupport) @end + +@implementation NSURLSessionConfiguration(PBHTTPStubsSupport) + ++(void)load +{ + + orig_defaultSessionConfiguration = (SessionConfigConstructor)PBHTTPStubsReplaceMethod(@selector(defaultSessionConfiguration), + (IMP)PBHTTPStubs_defaultSessionConfiguration, + [NSURLSessionConfiguration class], + YES); + orig_ephemeralSessionConfiguration = (SessionConfigConstructor)PBHTTPStubsReplaceMethod(@selector(ephemeralSessionConfiguration), + (IMP)PBHTTPStubs_ephemeralSessionConfiguration, + [NSURLSessionConfiguration class], + YES); +} + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub.h b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub.h new file mode 100644 index 000000000..c6344ffed --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub.h @@ -0,0 +1,78 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 + + + + +@interface PBURLConnectionStub : NSObject + +@property (nonatomic, readwrite, strong) NSString *requestURL; +@property (nonatomic, readwrite, assign) NSInteger responseCode; +@property (nonatomic, readwrite, strong) id responseBody; //can be nsstring or nsdata + ++ (PBURLConnectionStub *)stubForStandardBannerWithAdSize:(CGSize)adSize + content:(NSString *)content; + ++ (PBURLConnectionStub *)stubForStandardBannerWithAdSize:(CGSize)adSize + contentFromResource:(NSString *)resource + ofType:(NSString *)type; + ++ (PBURLConnectionStub *)stubForResource:(NSString *)resource + ofType:(NSString *)type; + ++ (PBURLConnectionStub *)stubForResource:(NSString *)resource + ofType:(NSString *)type + withRequestURL:(NSString *)pattern; + ++ (PBURLConnectionStub *)stubForResource:(NSString *)resource + ofType:(NSString *)type + withRequestURL:(NSString *)pattern + inBundle:(NSBundle *)bundle; + + + +/** + * Enable or disable the stubs on a given `NSURLSessionConfiguration`. + * + * @param enabled If `YES`, enables the stubs for this `NSURLSessionConfiguration`. + * If `NO`, disable the stubs and let all the requests hit the real world + * @param sessionConfig The NSURLSessionConfiguration on which to enabled/disable the stubs + * + * @note OHHTTPStubs are enabled by default on newly created `defaultSessionConfiguration` + * and `ephemeralSessionConfiguration`, so there is no need to call this method with + * `YES` for stubs to work. You generally only use this if you want to disable + * `OHTTPStubs` per `NSURLSession` by calling it before building the `NSURLSession` + * with the `NSURLSessionConfiguration`. + * + * @note Important: As usual according to the way `NSURLSessionConfiguration` works, you + * MUST set this property BEFORE creating the `NSURLSession`. Once the `NSURLSession` + * object is created, they use a deep copy of the `NSURLSessionConfiguration` object + * used to create them, so changing the configuration later does not affect already + * created sessions. + */ ++ (void)setEnabled:(BOOL)enabled forSessionConfiguration:(NSURLSessionConfiguration *)sessionConfig; + +/** + * Whether stubs are enabled or disabled on a given `NSURLSessionConfiguration` + * + * @param sessionConfig The NSURLSessionConfiguration on which to enable/disable the stubs + * + * @return If `YES` the stubs are enabled for sessionConfig. If `NO` then the stubs are disabled + */ ++ (BOOL)isEnabledForSessionConfiguration:(NSURLSessionConfiguration *)sessionConfig; + +@end diff --git a/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub.m b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub.m new file mode 100644 index 000000000..a6126ccc9 --- /dev/null +++ b/PrebidMobileTests/FetchingLogictests/Shared/Stubbing/PBURLConnectionStub.m @@ -0,0 +1,180 @@ +/* Copyright 2018-2019 Prebid.org, Inc. + + 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 "PBURLConnectionStub.h" +//#import "ANGlobal.h" +//#import "ANSDKSettings+PrivateMethods.h" +#import "PBHTTPStubURLProtocol.h" + +@implementation PBURLConnectionStub + +- (id)copyWithZone:(NSZone *)zone { + PBURLConnectionStub *newStub = [[PBURLConnectionStub alloc] init]; + newStub.requestURL = self.requestURL; + newStub.responseCode = self.responseCode; + newStub.responseBody = self.responseBody; + return newStub; +} + +- (BOOL)isEqual:(PBURLConnectionStub *)object { + BOOL sameRequestURLString = [self.requestURL isEqualToString:object.requestURL]; + BOOL sameResponseCode = (self.responseCode == object.responseCode); + BOOL sameResponseBody = [self.responseBody isEqualToString:object.responseBody]; + return sameRequestURLString && sameResponseBody && sameResponseCode; +} + +- (NSUInteger)hash { + NSMutableString *description = [[NSMutableString alloc] init]; + [description appendString:self.requestURL]; + [description appendString:[NSString stringWithFormat:@"%ld", (long)self.responseCode]]; + [description appendString:self.responseBody]; + return [description hash]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"NSURLConnectionStub: \n\ + Request URL Pattern: %@,\n\ + Response Code: %ld,\n\ + Response Body: %@",self.requestURL, (long)self.responseCode, self.responseBody]; + +} + + + + +#pragma mark - Pre-Initialized Stubbers + ++ (PBURLConnectionStub *)stubForStandardBannerWithAdSize:(CGSize)adSize + contentFromResource:(NSString *)resource + ofType:(NSString *)type { + NSString *filePath = [[NSBundle mainBundle] pathForResource:resource + ofType:type]; + NSString *content = [[NSString alloc] initWithContentsOfFile:filePath + encoding:NSUTF8StringEncoding + error:nil]; + return [PBURLConnectionStub stubForStandardBannerWithAdSize:adSize + content:content]; +} + ++ (PBURLConnectionStub *)stubForStandardBannerWithAdSize:(CGSize)adSize + content:(NSString *)content { + PBURLConnectionStub *stub = [[PBURLConnectionStub alloc] init]; + stub.requestURL = @"https://prebid.adnxs.com/pbs/v1/openrtb2/auction"; + stub.responseCode = 200; + stub.responseBody = [NSJSONSerialization dataWithJSONObject:[[self class] responseForStandardBannerWithAdSize:adSize + content:content] + options:0 + error:nil]; + return stub; +} + + ++ (PBURLConnectionStub *)stubForResource:(NSString *)resource + ofType:(NSString *)type { + return [PBURLConnectionStub stubForResource:resource + ofType:type + withRequestURL:resource + inBundle:[NSBundle mainBundle]]; +} + ++ (PBURLConnectionStub *)stubForResource:(NSString *)resource + ofType:(NSString *)type + withRequestURL:(NSString *)pattern { + return [PBURLConnectionStub stubForResource:resource + ofType:type + withRequestURL:pattern + inBundle:[NSBundle mainBundle]]; +} + ++ (PBURLConnectionStub *)stubForResource:(NSString *)resource + ofType:(NSString *)type + withRequestURL:(NSString *)pattern + inBundle:(NSBundle *)bundle { + PBURLConnectionStub *stub = [[PBURLConnectionStub alloc] init]; + stub.responseCode = 200; + stub.requestURL = pattern; + stub.responseBody = [NSData dataWithContentsOfFile:[bundle pathForResource:resource + ofType:type]]; + return stub; +} + ++ (NSDictionary *)responseForStandardBannerWithAdSize:(CGSize)adSize + content:(NSString *)content { + NSMutableDictionary *response = [[NSMutableDictionary alloc] init]; + response[@"status"] = @"ok"; + NSDictionary *adElement = [[self class] adElementForAdType:@"banner" + adSize:adSize + content:content]; + response[@"ads"] = @[adElement]; + return [response copy]; +} + ++ (NSDictionary *)adElementForAdType:(NSString *)type + adSize:(CGSize)adSize + content:(NSString *)content { + NSMutableDictionary *adElement = [[NSMutableDictionary alloc] init]; + adElement[@"type"] = type; + adElement[@"width"] = [@(adSize.width) description]; + adElement[@"height"] = [@(adSize.height) description]; + adElement[@"content"] = content; + return [adElement copy]; +} + ++ (void)setEnabled:(BOOL)enable forSessionConfiguration:(NSURLSessionConfiguration*)sessionConfig +{ + // Runtime check to make sure the API is available on this version + if ( [sessionConfig respondsToSelector:@selector(protocolClasses)] + && [sessionConfig respondsToSelector:@selector(setProtocolClasses:)]) + { + NSMutableArray * urlProtocolClasses = [NSMutableArray arrayWithArray:sessionConfig.protocolClasses]; + Class protoCls = PBHTTPStubURLProtocol.class; + if (enable && ![urlProtocolClasses containsObject:protoCls]) + { + [urlProtocolClasses insertObject:protoCls atIndex:0]; + } + else if (!enable && [urlProtocolClasses containsObject:protoCls]) + { + [urlProtocolClasses removeObject:protoCls]; + } + sessionConfig.protocolClasses = urlProtocolClasses; + } + else + { + NSLog(@"[PBURLConnectionStub] %@ is only available when running on iOS7+/OSX9+. " + @"Use conditions like 'if ([NSURLSessionConfiguration class])' to only call " + @"this method if the user is running iOS7+/OSX9+.", NSStringFromSelector(_cmd)); + } +} + ++ (BOOL)isEnabledForSessionConfiguration:(NSURLSessionConfiguration *)sessionConfig +{ + // Runtime check to make sure the API is available on this version + if ( [sessionConfig respondsToSelector:@selector(protocolClasses)] + && [sessionConfig respondsToSelector:@selector(setProtocolClasses:)]) + { + NSMutableArray * urlProtocolClasses = [NSMutableArray arrayWithArray:sessionConfig.protocolClasses]; + Class protoCls = PBHTTPStubURLProtocol.class; + return [urlProtocolClasses containsObject:protoCls]; + } + else + { + NSLog(@"[PBURLConnectionStub] %@ is only available when running on iOS7+/OSX9+. " + @"Use conditions like 'if ([NSURLSessionConfiguration class])' to only call " + @"this method if the user is running iOS7+/OSX9+.", NSStringFromSelector(_cmd)); + return NO; + } +} + +@end