// // ASIS3RequestTests.m // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest // // Created by Ben Copsey on 12/07/2009. // Copyright 2009 All-Seeing Interactive. All rights reserved. // #import "ASIS3RequestTests.h" #import "ASINetworkQueue.h" #import "ASIS3BucketObject.h" #import "ASIS3ObjectRequest.h" #import "ASIS3BucketRequest.h" #import "ASIS3ServiceRequest.h" // Fill in these to run the tests that actually connect and manipulate objects on S3 static NSString *secretAccessKey = @""; static NSString *accessKey = @""; // You should run these tests on a bucket that does not yet exist static NSString *bucket = @""; // Used for subclass test @interface ASIS3ObjectRequestSubclass : ASIS3ObjectRequest {} @end @implementation ASIS3ObjectRequestSubclass; @end @interface ASIS3BucketRequestSubclass : ASIS3BucketRequest {} @end @implementation ASIS3BucketRequestSubclass; @end @interface ASIS3BucketObjectSubclass : ASIS3BucketObject {} @end @implementation ASIS3BucketObjectSubclass; @end // Stop clang complaining about undeclared selectors @interface ASIS3RequestTests () - (void)GETRequestDone:(ASIHTTPRequest *)request; - (void)GETRequestFailed:(ASIHTTPRequest *)request; - (void)PUTRequestDone:(ASIHTTPRequest *)request; - (void)PUTRequestFailed:(ASIHTTPRequest *)request; - (void)DELETERequestDone:(ASIHTTPRequest *)request; - (void)DELETERequestFailed:(ASIHTTPRequest *)request; @end @implementation ASIS3RequestTests // All these tests are based on Amazon's examples at: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/ - (void)testAuthenticationHeaderGeneration { NSString *exampleSecretAccessKey = @"uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"; NSString *exampleAccessKey = @"0PN5J17HBGZHT7JJ3X82"; NSString *exampleBucket = @"johnsmith"; // Test list all my buckets NSString *dateString = @"Wed, 28 Mar 2007 01:29:59 +0000"; ASIS3ServiceRequest *serviceRequest = [ASIS3ServiceRequest serviceRequest]; [serviceRequest setSecretAccessKey:exampleSecretAccessKey]; [serviceRequest setAccessKey:exampleAccessKey]; [serviceRequest setDateString:dateString]; [serviceRequest buildRequestHeaders]; BOOL success = [[[serviceRequest requestHeaders] valueForKey:@"Authorization"] isEqualToString:@"AWS 0PN5J17HBGZHT7JJ3X82:Db+gepJSUbZKwpx1FR0DLtEYoZA="]; GHAssertTrue(success,@"Failed to generate the correct authorisation header for a GET service request"); // Test GET NSString *key = @"photos/puppy.jpg"; dateString = @"Tue, 27 Mar 2007 19:36:42 +0000"; ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:exampleBucket key:key]; [request setDateString:dateString]; [request setSecretAccessKey:exampleSecretAccessKey]; [request setAccessKey:exampleAccessKey]; [request buildRequestHeaders]; success = [[[request requestHeaders] valueForKey:@"Authorization"] isEqualToString:@"AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbA="]; GHAssertTrue(success,@"Failed to generate the correct authorisation header for a GET request"); // Test PUT key = @"photos/puppy.jpg"; dateString = @"Tue, 27 Mar 2007 21:15:45 +0000"; request = [ASIS3ObjectRequest requestWithBucket:exampleBucket key:key]; [request setRequestMethod:@"PUT"]; [request setMimeType:@"image/jpeg"]; [request setDateString:dateString]; [request setSecretAccessKey:exampleSecretAccessKey]; [request setAccessKey:exampleAccessKey]; [request buildRequestHeaders]; success = [[[request requestHeaders] valueForKey:@"Authorization"] isEqualToString:@"AWS 0PN5J17HBGZHT7JJ3X82:hcicpDDvL9SsO6AkvxqmIWkmOuQ="]; GHAssertTrue(success,@"Failed to generate the correct authorisation header for a PUT request"); // Test List dateString = @"Tue, 27 Mar 2007 19:42:41 +0000"; ASIS3BucketRequest *listRequest = [ASIS3BucketRequest requestWithBucket:exampleBucket]; [listRequest setPrefix:@"photos"]; [listRequest setMaxResultCount:50]; [listRequest setMarker:@"puppy"]; [listRequest setDateString:dateString]; [listRequest setSecretAccessKey:exampleSecretAccessKey]; [listRequest setAccessKey:exampleAccessKey]; [listRequest buildRequestHeaders]; success = [[[listRequest requestHeaders] valueForKey:@"Authorization"] isEqualToString:@"AWS 0PN5J17HBGZHT7JJ3X82:jsRt/rhG+Vtp88HrYL706QhE4w4="]; GHAssertTrue(success,@"Failed to generate the correct authorisation header for a list request"); // Test fetch ACL dateString = @"Tue, 27 Mar 2007 19:44:46 +0000"; listRequest = [ASIS3BucketRequest requestWithBucket:exampleBucket subResource:@"acl"]; [listRequest setDateString:dateString]; [listRequest setSecretAccessKey:exampleSecretAccessKey]; [listRequest setAccessKey:exampleAccessKey]; [listRequest buildRequestHeaders]; success = [[[listRequest requestHeaders] valueForKey:@"Authorization"] isEqualToString:@"AWS 0PN5J17HBGZHT7JJ3X82:thdUi9VAkzhkniLj96JIrOPGi0g="]; GHAssertTrue(success,@"Failed to generate the correct authorisation header for a list request"); // Test Unicode keys // Comment out this test for now, as the S3 example is relying on mixed-case hex-encoded characters in the url, which isn't going to be easy to replicate // exampleBucket = @"dictionary"; // key = @"français/préfère"; // dateString = @"Wed, 28 Mar 2007 01:49:49 +0000"; // request = [ASIS3ObjectRequest requestWithBucket:exampleBucket key:key]; // [request setDateString:dateString]; // [request setSecretAccessKey:exampleSecretAccessKey]; // [request setAccessKey:exampleAccessKey]; // [request buildRequestHeaders]; // success = [[[request requestHeaders] valueForKey:@"Authorization"] isEqualToString:@"AWS 0PN5J17HBGZHT7JJ3X82:dxhSBHoI6eVSPcXJqEghlUzZMnY="]; //GHAssertTrue(success,@"Failed to generate the correct authorisation header for a list request"); } - (void)testFailure { // Needs expanding to cover more failure states - this is just a test to ensure Amazon's error description is being added to the error // We're actually going to try with the Amazon example details, but the request will fail because the date is old NSString *exampleSecretAccessKey = @"uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"; NSString *exampleAccessKey = @"0PN5J17HBGZHT7JJ3X82"; NSString *exampleBucket = @"johnsmith"; NSString *key = @"photos/puppy.jpg"; NSString *dateString = @"Tue, 27 Mar 2007 19:36:42 +0000"; ASIS3Request *request = [ASIS3ObjectRequest requestWithBucket:exampleBucket key:key]; [request setDateString:dateString]; [request setSecretAccessKey:exampleSecretAccessKey]; [request setAccessKey:exampleAccessKey]; [request startSynchronous]; GHAssertNotNil([request error],@"Failed to generate an error when the request was not correctly signed"); BOOL success = ([[request error] code] == ASIS3ResponseErrorType); GHAssertTrue(success,@"Generated error had the wrong error code"); success = ([[[request error] localizedDescription] isEqualToString:@"The difference between the request time and the current time is too large."]); GHAssertTrue(success,@"Generated error had the wrong description"); // Ensure a bucket request will correctly parse an error from S3 request = [ASIS3BucketRequest requestWithBucket:exampleBucket]; [request setDateString:dateString]; [request setSecretAccessKey:exampleSecretAccessKey]; [request setAccessKey:exampleAccessKey]; [request startSynchronous]; GHAssertNotNil([request error],@"Failed to generate an error when the request was not correctly signed"); success = ([[request error] code] == ASIS3ResponseErrorType); GHAssertTrue(success,@"Generated error had the wrong error code"); success = ([[[request error] localizedDescription] isEqualToString:@"The difference between the request time and the current time is too large."]); GHAssertTrue(success,@"Generated error had the wrong description"); // Ensure a service request will correctly parse an error from S3 request = [ASIS3ServiceRequest serviceRequest]; [request setDateString:dateString]; [request setSecretAccessKey:exampleSecretAccessKey]; [request setAccessKey:exampleAccessKey]; [request startSynchronous]; GHAssertNotNil([request error],@"Failed to generate an error when the request was not correctly signed"); success = ([[request error] code] == ASIS3ResponseErrorType); GHAssertTrue(success,@"Generated error had the wrong error code"); success = ([[[request error] localizedDescription] isEqualToString:@"The difference between the request time and the current time is too large."]); GHAssertTrue(success,@"Generated error had the wrong description"); } - (void)createTestBucket { // Test creating a bucket ASIS3BucketRequest *bucketRequest = [ASIS3BucketRequest PUTRequestWithBucket:bucket]; [bucketRequest setSecretAccessKey:secretAccessKey]; [bucketRequest setAccessKey:accessKey]; [bucketRequest startSynchronous]; GHAssertNil([bucketRequest error],@"Failed to create a bucket"); } // To run this test, uncomment and fill in your S3 access details - (void)testREST { [self createTestBucket]; BOOL success = (![secretAccessKey isEqualToString:@""] && ![accessKey isEqualToString:@""] && ![bucket isEqualToString:@""]); GHAssertTrue(success,@"You need to supply your S3 access details to run the REST test (see the top of ASIS3RequestTests.m)"); // Test creating a bucket ASIS3BucketRequest *bucketRequest = [ASIS3BucketRequest PUTRequestWithBucket:bucket]; [bucketRequest setSecretAccessKey:secretAccessKey]; [bucketRequest setAccessKey:accessKey]; [bucketRequest startSynchronous]; GHAssertNil([bucketRequest error],@"Failed to create a bucket"); // List buckets to make sure the bucket is there ASIS3ServiceRequest *serviceRequest = [ASIS3ServiceRequest serviceRequest]; [serviceRequest setSecretAccessKey:secretAccessKey]; [serviceRequest setAccessKey:accessKey]; [serviceRequest startSynchronous]; GHAssertNil([serviceRequest error],@"Failed to fetch the list of buckets from S3"); BOOL foundBucket = NO; for (ASIS3Bucket *theBucket in [serviceRequest buckets]) { if ([[theBucket name] isEqualToString:bucket]) { foundBucket = YES; break; } } GHAssertTrue(foundBucket,@"Failed to retrive the newly-created bucket in a list of buckets"); NSString *key = @"test"; // Create the file NSString *text = @"This is my content"; NSString *filePath = [[self filePathForTemporaryTestFiles] stringByAppendingPathComponent:@"testfile.txt"]; [[text dataUsingEncoding:NSUTF8StringEncoding] writeToFile:filePath atomically:NO]; // PUT the file ASIS3ObjectRequest *request = [ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:bucket key:key]; [request setSecretAccessKey:secretAccessKey]; [request setAccessKey:accessKey]; [request setStorageClass:ASIS3StorageClassReducedRedundancy]; [request startSynchronous]; success = [[request responseString] isEqualToString:@""]; GHAssertTrue(success,@"Failed to PUT a file to S3"); // GET the file request = [ASIS3ObjectRequest requestWithBucket:bucket key:key]; [request setSecretAccessKey:secretAccessKey]; [request setAccessKey:accessKey]; [request startSynchronous]; success = [[request responseString] isEqualToString:@"This is my content"]; GHAssertTrue(success,@"Failed to GET the correct data from S3"); // Test fetch subresource request = [ASIS3ObjectRequest requestWithBucket:bucket key:key subResource:@"acl"]; [request setSecretAccessKey:secretAccessKey]; [request setAccessKey:accessKey]; [request startSynchronous]; success = ([[request responseString] rangeOfString:@" 0); GHAssertTrue(success,@"Failed to create a retained copy"); success = ([request2 isKindOfClass:[ASIS3Request class]]); GHAssertTrue(success,@"Copy is of wrong class"); [request2 release]; pool = [[NSAutoreleasePool alloc] init]; ASIS3BucketRequest *request3 = [ASIS3BucketRequest requestWithBucket:@"foo"]; ASIS3BucketRequest *request4 = [request3 copy]; GHAssertNotNil(request4,@"Failed to create a copy"); [pool release]; success = ([request4 retainCount] > 0); GHAssertTrue(success,@"Failed to create a retained copy"); success = ([request4 isKindOfClass:[ASIS3BucketRequest class]]); GHAssertTrue(success,@"Copy is of wrong class"); [request4 release]; pool = [[NSAutoreleasePool alloc] init]; ASIS3BucketObject *bucketObject = [ASIS3BucketObject objectWithBucket:@"foo"]; ASIS3BucketObject *bucketObject2 = [bucketObject copy]; GHAssertNotNil(bucketObject2,@"Failed to create a copy"); [pool release]; success = ([bucketObject2 retainCount] > 0); GHAssertTrue(success,@"Failed to create a retained copy"); [bucketObject2 release]; } - (void)testHTTPS { [ASIS3Request setSharedAccessKey:accessKey]; [ASIS3Request setSharedSecretAccessKey:secretAccessKey]; // Create a bucket ASIS3Request *request = [ASIS3BucketRequest PUTRequestWithBucket:bucket]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; GHAssertNil([request error],@"Failed to create a bucket"); // PUT something in it NSString *key = @"king"; request = [ASIS3ObjectRequest PUTRequestForData:[@"fink" dataUsingEncoding:NSUTF8StringEncoding] withBucket:bucket key:key]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; BOOL success = [[request responseString] isEqualToString:@""]; GHAssertTrue(success,@"Failed to PUT some data into S3"); // GET it request = [ASIS3ObjectRequest requestWithBucket:bucket key:key]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; success = [[request responseString] isEqualToString:@"fink"]; GHAssertTrue(success,@"Failed to GET the correct data from S3"); // DELETE it request = [ASIS3ObjectRequest DELETERequestWithBucket:bucket key:@"king"]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; success = [[request responseString] isEqualToString:@""]; GHAssertTrue(success,@"Failed to DELETE the object from S3"); // Delete the bucket request = [ASIS3BucketRequest DELETERequestWithBucket:bucket]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; GHAssertNil([request error],@"Failed to delete a bucket"); [ASIS3Request setSharedAccessKey:nil]; [ASIS3Request setSharedSecretAccessKey:nil]; } // Ideally this test would actually parse the ACL XML and check it, but for now it just makes sure S3 doesn't return an error - (void)testCannedACLs { [ASIS3Request setSharedAccessKey:accessKey]; [ASIS3Request setSharedSecretAccessKey:secretAccessKey]; // Create a bucket ASIS3Request *request = [ASIS3BucketRequest PUTRequestWithBucket:bucket]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; GHAssertNil([request error],@"Failed to create a bucket"); NSArray *ACLs = [NSArray arrayWithObjects:ASIS3AccessPolicyPrivate,ASIS3AccessPolicyPublicRead,ASIS3AccessPolicyPublicReadWrite,ASIS3AccessPolicyAuthenticatedRead,ASIS3AccessPolicyBucketOwnerRead,ASIS3AccessPolicyBucketOwnerFullControl,nil]; for (NSString *cannedACL in ACLs) { // PUT object NSString *key = @"king"; request = [ASIS3ObjectRequest PUTRequestForData:[@"fink" dataUsingEncoding:NSUTF8StringEncoding] withBucket:bucket key:key]; [request setAccessPolicy:cannedACL]; [request startSynchronous]; GHAssertNil([request error],@"Failed to PUT some data into S3"); // GET object ACL request = [ASIS3ObjectRequest requestWithBucket:bucket key:key subResource:@"acl"]; [request startSynchronous]; GHAssertNil([request error],@"Failed to fetch the object"); } // DELETE it request = [ASIS3ObjectRequest DELETERequestWithBucket:bucket key:@"king"]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; BOOL success = [[request responseString] isEqualToString:@""]; GHAssertTrue(success,@"Failed to DELETE the object from S3"); // Delete the bucket request = [ASIS3BucketRequest DELETERequestWithBucket:bucket]; [request setRequestScheme:ASIS3RequestSchemeHTTPS]; [request startSynchronous]; GHAssertNil([request error],@"Failed to delete a bucket"); [ASIS3Request setSharedAccessKey:nil]; [ASIS3Request setSharedSecretAccessKey:nil]; } @synthesize networkQueue; @end