Michael Mayo

tests, container, and object support

@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 NSString *contentType; 16 NSString *contentType;
17 NSDate *lastModified; 17 NSDate *lastModified;
18 NSData *data; 18 NSData *data;
19 - NSDictionary *metadata; 19 + NSMutableDictionary *metadata;
20 } 20 }
21 21
22 @property (nonatomic, retain) NSString *name; 22 @property (nonatomic, retain) NSString *name;
@@ -25,7 +25,7 @@ @@ -25,7 +25,7 @@
25 @property (nonatomic, retain) NSString *contentType; 25 @property (nonatomic, retain) NSString *contentType;
26 @property (nonatomic, retain) NSDate *lastModified; 26 @property (nonatomic, retain) NSDate *lastModified;
27 @property (nonatomic, retain) NSData *data; 27 @property (nonatomic, retain) NSData *data;
28 -@property (nonatomic, retain) NSDictionary *metadata; 28 +@property (nonatomic, retain) NSMutableDictionary *metadata;
29 29
30 + (id)object; 30 + (id)object;
31 31
@@ -12,6 +12,9 @@ @@ -12,6 +12,9 @@
12 12
13 @interface ASICloudFilesObjectRequest : ASICloudFilesRequest { 13 @interface ASICloudFilesObjectRequest : ASICloudFilesRequest {
14 14
  15 + NSString *accountName;
  16 + NSString *containerName;
  17 +
15 // Internally used while parsing the response 18 // Internally used while parsing the response
16 NSString *currentContent; 19 NSString *currentContent;
17 NSString *currentElement; 20 NSString *currentElement;
@@ -20,6 +23,9 @@ @@ -20,6 +23,9 @@
20 23
21 } 24 }
22 25
  26 +@property (nonatomic, retain) NSString *accountName;
  27 +@property (nonatomic, retain) NSString *containerName;
  28 +
23 @property (nonatomic, retain) NSString *currentElement; 29 @property (nonatomic, retain) NSString *currentElement;
24 @property (nonatomic, retain) NSString *currentContent; 30 @property (nonatomic, retain) NSString *currentContent;
25 @property (nonatomic, retain) ASICloudFilesObject *currentObject; 31 @property (nonatomic, retain) ASICloudFilesObject *currentObject;
@@ -31,6 +37,10 @@ @@ -31,6 +37,10 @@
31 - (NSUInteger)containerObjectCount; 37 - (NSUInteger)containerObjectCount;
32 - (NSUInteger)containerBytesUsed; 38 - (NSUInteger)containerBytesUsed;
33 39
  40 +// HEAD /<api version>/<account>/<container>/<object>
  41 +// to get metadata
  42 ++ (id)objectInfoRequest:(NSString *)containerName objectPath:(NSString *)objectPath;
  43 +
34 44
35 // GET 45 // GET
36 - (NSArray *)objects; 46 - (NSArray *)objects;
@@ -13,6 +13,7 @@ @@ -13,6 +13,7 @@
13 @implementation ASICloudFilesObjectRequest 13 @implementation ASICloudFilesObjectRequest
14 14
15 @synthesize currentElement, currentContent, currentObject; 15 @synthesize currentElement, currentContent, currentObject;
  16 +@synthesize accountName, containerName;
16 17
17 + (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName { 18 + (id)storageRequestWithMethod:(NSString *)method containerName:(NSString *)containerName {
18 NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest storageURL], containerName]; 19 NSString *urlString = [NSString stringWithFormat:@"%@/%@", [ASICloudFilesRequest storageURL], containerName];
@@ -20,6 +21,7 @@ @@ -20,6 +21,7 @@
20 ASICloudFilesObjectRequest *request = [[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]]; 21 ASICloudFilesObjectRequest *request = [[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
21 [request setRequestMethod:method]; 22 [request setRequestMethod:method];
22 [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]]; 23 [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
  24 + request.containerName = containerName;
23 return request; 25 return request;
24 } 26 }
25 27
@@ -29,6 +31,7 @@ @@ -29,6 +31,7 @@
29 ASICloudFilesObjectRequest *request = [[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]]; 31 ASICloudFilesObjectRequest *request = [[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
30 [request setRequestMethod:method]; 32 [request setRequestMethod:method];
31 [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]]; 33 [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
  34 + request.containerName = containerName;
32 return request; 35 return request;
33 } 36 }
34 37
@@ -38,6 +41,7 @@ @@ -38,6 +41,7 @@
38 ASICloudFilesObjectRequest *request = [[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]]; 41 ASICloudFilesObjectRequest *request = [[ASICloudFilesObjectRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
39 [request setRequestMethod:method]; 42 [request setRequestMethod:method];
40 [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]]; 43 [request addRequestHeader:@"X-Auth-Token" value:[ASICloudFilesRequest authToken]];
  44 + request.containerName = containerName;
41 return request; 45 return request;
42 } 46 }
43 47
@@ -58,6 +62,14 @@ @@ -58,6 +62,14 @@
58 } 62 }
59 63
60 #pragma mark - 64 #pragma mark -
  65 +#pragma mark Object Info
  66 +
  67 ++ (id)objectInfoRequest:(NSString *)containerName objectPath:(NSString *)objectPath {
  68 + ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"HEAD" containerName:containerName objectPath:objectPath];
  69 + return request;
  70 +}
  71 +
  72 +#pragma mark -
61 #pragma mark List Requests 73 #pragma mark List Requests
62 74
63 + (NSString *)queryStringWithContainer:(NSString *)container limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path { 75 + (NSString *)queryStringWithContainer:(NSString *)container limit:(NSUInteger)limit marker:(NSString *)marker prefix:(NSString *)prefix path:(NSString *)path {
@@ -166,23 +178,38 @@ @@ -166,23 +178,38 @@
166 #pragma mark GET Object 178 #pragma mark GET Object
167 179
168 + (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath { 180 + (id)getObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath {
169 - return nil; 181 + return [ASICloudFilesObjectRequest storageRequestWithMethod:@"GET" containerName:containerName objectPath:objectPath];
170 } 182 }
171 183
172 - (ASICloudFilesObject *)object { 184 - (ASICloudFilesObject *)object {
173 ASICloudFilesObject *object = [ASICloudFilesObject object]; 185 ASICloudFilesObject *object = [ASICloudFilesObject object];
174 186
175 - object.name = nil; // TODO: store this cleanly somehow 187 + NSString *path = [self url].path;
  188 + NSRange range = [path rangeOfString:self.containerName];
  189 + path = [path substringFromIndex:range.location + range.length + 1];
  190 +
  191 + object.name = path;
176 object.hash = [[self responseHeaders] objectForKey:@"ETag"]; 192 object.hash = [[self responseHeaders] objectForKey:@"ETag"];
177 object.bytes = [[[self responseHeaders] objectForKey:@"Content-Length"] intValue]; 193 object.bytes = [[[self responseHeaders] objectForKey:@"Content-Length"] intValue];
178 object.contentType = [[self responseHeaders] objectForKey:@"Content-Type"]; 194 object.contentType = [[self responseHeaders] objectForKey:@"Content-Type"];
179 object.lastModified = [[self responseHeaders] objectForKey:@"Last-Modified"]; 195 object.lastModified = [[self responseHeaders] objectForKey:@"Last-Modified"];
180 - // TODO: hash == ETag? 196 + object.metadata = [[NSMutableDictionary alloc] init];
181 - //object.etag = [[self responseHeaders] objectForKey:@"ETag"]; 197 +
182 - object.metadata = nil; 198 + NSDictionary *headers = [self responseHeaders];
  199 + NSArray *keys = [headers allKeys];
  200 + for (int i = 0; i < [keys count]; i++) {
  201 + NSString *key = [keys objectAtIndex:i];
  202 + NSString *value = [headers objectForKey:key];
  203 + NSRange range = [key rangeOfString:@"X-Object-Meta-"];
  204 +
  205 + if (range.location == 0) {
  206 + [object.metadata setObject:value forKey:[key substringFromIndex:range.length]];
  207 + }
  208 + }
  209 +
183 object.data = [self responseData]; 210 object.data = [self responseData];
184 211
185 - return nil; 212 + return object;
186 } 213 }
187 214
188 #pragma mark - 215 #pragma mark -
@@ -196,7 +223,7 @@ @@ -196,7 +223,7 @@
196 223
197 // TODO: etag? 224 // TODO: etag?
198 225
199 - ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"PUT" containerName:containerName objectPath:objectPath]; 226 + ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"PUT" containerName:containerName objectPath:objectPath];
200 [request addRequestHeader:@"Content-Type" value:contentType]; 227 [request addRequestHeader:@"Content-Type" value:contentType];
201 [request addRequestHeader:@"Content-Length" value:[NSString stringWithFormat:@"%i", objectData.length]]; 228 [request addRequestHeader:@"Content-Length" value:[NSString stringWithFormat:@"%i", objectData.length]];
202 229
@@ -222,7 +249,7 @@ @@ -222,7 +249,7 @@
222 } 249 }
223 250
224 + (id)postObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath metadata:(NSDictionary *)metadata { 251 + (id)postObjectRequestWithContainer:(NSString *)containerName objectPath:(NSString *)objectPath metadata:(NSDictionary *)metadata {
225 - ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"PUT" containerName:containerName objectPath:objectPath]; 252 + ASICloudFilesObjectRequest *request = [ASICloudFilesObjectRequest storageRequestWithMethod:@"POST" containerName:containerName objectPath:objectPath];
226 253
227 // add metadata to headers 254 // add metadata to headers
228 if (metadata) { 255 if (metadata) {
@@ -293,5 +320,13 @@ @@ -293,5 +320,13 @@
293 [self setCurrentContent:[[self currentContent] stringByAppendingString:string]]; 320 [self setCurrentContent:[[self currentContent] stringByAppendingString:string]];
294 } 321 }
295 322
  323 +- (void)dealloc {
  324 + [currentElement release];
  325 + [currentContent release];
  326 + [currentObject release];
  327 + [accountName release];
  328 + [containerName release];
  329 + [super dealloc];
  330 +}
296 331
297 @end 332 @end
@@ -27,6 +27,7 @@ @@ -27,6 +27,7 @@
27 } 27 }
28 28
29 + (NSString *)storageURL; 29 + (NSString *)storageURL;
  30 ++ (NSString *)cdnManagementURL;
30 + (NSString *)authToken; 31 + (NSString *)authToken;
31 32
32 #pragma mark Rackspace Cloud Authentication 33 #pragma mark Rackspace Cloud Authentication
@@ -22,15 +22,18 @@ static NSString *rackspaceCloudAuthURL = @"https://auth.api.rackspacecloud.com/v @@ -22,15 +22,18 @@ static NSString *rackspaceCloudAuthURL = @"https://auth.api.rackspacecloud.com/v
22 22
23 @implementation ASICloudFilesRequest 23 @implementation ASICloudFilesRequest
24 24
  25 ++ (NSString *)authToken {
  26 + return authToken;
  27 +}
  28 +
25 + (NSString *)storageURL { 29 + (NSString *)storageURL {
26 return storageURL; 30 return storageURL;
27 } 31 }
28 32
29 -+ (NSString *)authToken { 33 ++ (NSString *)cdnManagementURL {
30 - return authToken; 34 + return cdnManagementURL;
31 } 35 }
32 36
33 -  
34 + (id)authenticationRequest { 37 + (id)authenticationRequest {
35 ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:rackspaceCloudAuthURL]]; 38 ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:rackspaceCloudAuthURL]];
36 39
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 #import "ASIInputStream.h" 21 #import "ASIInputStream.h"
22 22
23 // Automatically set on build 23 // Automatically set on build
24 -NSString *ASIHTTPRequestVersion = @"v1.2-27 2010-01-07"; 24 +NSString *ASIHTTPRequestVersion = @"v1.2-28 2010-01-08";
25 25
26 // We use our own custom run loop mode as CoreAnimation seems to want to hijack our threads otherwise 26 // We use our own custom run loop mode as CoreAnimation seems to want to hijack our threads otherwise
27 static CFStringRef ASIHTTPRequestRunMode = CFSTR("ASIHTTPRequest"); 27 static CFStringRef ASIHTTPRequestRunMode = CFSTR("ASIHTTPRequest");
@@ -6,13 +6,40 @@ @@ -6,13 +6,40 @@
6 // Copyright 2010 __MyCompanyName__. All rights reserved. 6 // Copyright 2010 __MyCompanyName__. All rights reserved.
7 // 7 //
8 8
9 -#import <Foundation/Foundation.h>  
10 #import "ASITestCase.h" 9 #import "ASITestCase.h"
11 10
12 @class ASINetworkQueue; 11 @class ASINetworkQueue;
13 12
14 -@interface ASICloudFilesRequestTests : NSObject { 13 +@interface ASICloudFilesRequestTests : ASITestCase {
15 ASINetworkQueue *networkQueue; 14 ASINetworkQueue *networkQueue;
  15 + float progress;
16 } 16 }
17 17
  18 +@property (retain,nonatomic) ASINetworkQueue *networkQueue;
  19 +
  20 +// Convenience Constructors
  21 +- (void)testSubclasses;
  22 +
  23 +// ASICloudFilesRequest
  24 +- (void)testAuthentication;
  25 +- (void)testDateParser;
  26 +
  27 +// ASICloudFilesContainerRequest
  28 +- (void)testAccountInfo;
  29 +- (void)testContainerList; // TODO: with marker and limit permutations as well
  30 +- (void)testContainerCreate;
  31 +- (void)testContainerDelete;
  32 +
  33 +// ASICloudFilesObjectRequest
  34 +- (void)testContainerInfo;
  35 +- (void)testObjectInfo;
  36 +- (void)testObjectList; // TODO: all permutations
  37 +- (void)testGetObject;
  38 +- (void)testPutObject; // TODO: all permutations?
  39 +- (void)testPostObject; // TODO: all permutations?
  40 +- (void)testDeleteObject;
  41 +
  42 +// ASICloudFilesCDNRequest
  43 +// ???
  44 +
18 @end 45 @end
This diff is collapsed. Click to expand it.
@@ -9,12 +9,6 @@ @@ -9,12 +9,6 @@
9 #import "iPhoneSampleAppDelegate.h" 9 #import "iPhoneSampleAppDelegate.h"
10 #import "ASIHTTPRequest.h" 10 #import "ASIHTTPRequest.h"
11 #import "Reachability.h" 11 #import "Reachability.h"
12 -#import "ASICloudFilesRequest.h"  
13 -#import "ASICloudFilesContainerRequest.h"  
14 -#import "ASICloudFilesObjectRequest.h"  
15 -#import "ASICloudFilesCDNRequest.h"  
16 -#import "ASICloudFilesContainer.h"  
17 -#import "ASICloudFilesObject.h"  
18 12
19 @implementation iPhoneSampleAppDelegate 13 @implementation iPhoneSampleAppDelegate
20 14
@@ -29,129 +23,7 @@ @@ -29,129 +23,7 @@
29 [super dealloc]; 23 [super dealloc];
30 } 24 }
31 25
32 -// TODO: remove  
33 --(NSDate *)dateFromString:(NSString *)dateString {  
34 - NSDateFormatter *format = [[NSDateFormatter alloc] init];  
35 - // example: 2009-11-04T19:46:20.192723  
36 - //[format setDateFormat:@"EEE, d MMM yyyy H:mm:ss zzz"];  
37 - //[format setDateFormat:@"yyyy-MM-ddTH:mm:ss"];  
38 - [format setDateFormat:@"yyyy-MM-dd'T'H:mm:ss"];  
39 - NSDate *date = [format dateFromString:dateString];  
40 - [format release];  
41 -  
42 - return date;  
43 -}  
44 -  
45 -  
46 -  
47 - (void)applicationDidFinishLaunching:(UIApplication *)application { 26 - (void)applicationDidFinishLaunching:(UIApplication *)application {
48 -  
49 - NSLog(@"DATE TESTS!!!");  
50 -  
51 - NSDate *date = [self dateFromString:@"2009-11-04T19:46:20.192723"];  
52 - NSLog(@"date: %@", [date description]);  
53 -  
54 -  
55 - NSLog(@"time to test Cloud Files!");  
56 -  
57 - [ASICloudFilesRequest setUsername:@"greenisus"];  
58 - [ASICloudFilesRequest setApiKey:@"1c331a7a4a6eb58ca6072afe81e812d0"];  
59 - [ASICloudFilesRequest authenticate];  
60 -  
61 - NSLog(@"Storage URL: %@", [ASICloudFilesRequest storageURL]);  
62 -  
63 - NSArray *containers = nil;  
64 - containers; // to suppress warning when test are commented out  
65 -  
66 - /*  
67 - NSLog(@"account info:");  
68 -  
69 - ASICloudFilesContainerRequest *accountInfoRequest = [ASICloudFilesContainerRequest accountInfoRequest];  
70 - [accountInfoRequest start];  
71 -  
72 -// NSLog(@"Response status code: %i", [accountInfoRequest responseStatusCode]);  
73 -// NSLog(@"Response status message: %@", [accountInfoRequest responseStatusMessage]);  
74 - NSLog(@"Container count: %i", [accountInfoRequest containerCount]);  
75 - NSLog(@"Bytes used: %i", [accountInfoRequest bytesUsed]);  
76 -  
77 -// NSLog(@"All headers:");  
78 -// NSDictionary *headers = [accountInfoRequest responseHeaders];  
79 -// NSArray *keys = [headers allKeys];  
80 -// for (int i = 0; i < [keys count]; i++) {  
81 -// NSString *key = [keys objectAtIndex:i];  
82 -// NSLog(@"%@: %@", key, [headers objectForKey:key]);  
83 -// }  
84 -  
85 - ASICloudFilesContainerRequest *containerListRequest = [ASICloudFilesContainerRequest listRequest];  
86 - [containerListRequest start];  
87 -  
88 - containers = [containerListRequest containers];  
89 - NSLog(@"Containers list count: %i", [containers count]);  
90 -  
91 - for (int i = 0; i < [containers count]; i++) {  
92 - ASICloudFilesContainer *container = [containers objectAtIndex:i];  
93 - NSLog(@"%@ - %i objects, %i bytes", container.name, container.count, container.bytes);  
94 - }  
95 -  
96 - ASICloudFilesContainerRequest *limitContainerListRequest = [ASICloudFilesContainerRequest listRequestWithLimit:2];  
97 - [limitContainerListRequest start];  
98 -  
99 - containers = [limitContainerListRequest containers];  
100 - NSLog(@"Limit 2 Containers list count: %i", [containers count]);  
101 -  
102 - for (int i = 0; i < [containers count]; i++) {  
103 - ASICloudFilesContainer *container = [containers objectAtIndex:i];  
104 - NSLog(@"%@ - %i objects, %i bytes", container.name, container.count, container.bytes);  
105 - }  
106 -  
107 - ASICloudFilesContainerRequest *markerContainerListRequest = [ASICloudFilesContainerRequest listRequestWithMarker:@"personal"];  
108 - [markerContainerListRequest start];  
109 -  
110 - containers = [markerContainerListRequest containers];  
111 - NSLog(@"Marker personal Containers list count: %i", [containers count]);  
112 -  
113 - for (int i = 0; i < [containers count]; i++) {  
114 - ASICloudFilesContainer *container = [containers objectAtIndex:i];  
115 - NSLog(@"%@ - %i objects, %i bytes", container.name, container.count, container.bytes);  
116 - }  
117 -  
118 - ASICloudFilesContainerRequest *limitMarkerContainerListRequest = [ASICloudFilesContainerRequest listRequestWithLimit:3 marker:@"cf_service"];  
119 - [limitMarkerContainerListRequest start];  
120 -  
121 - containers = [limitMarkerContainerListRequest containers];  
122 - NSLog(@"Limit 3 Marker cf_service Containers list count: %i", [containers count]);  
123 -  
124 - for (int i = 0; i < [containers count]; i++) {  
125 - ASICloudFilesContainer *container = [containers objectAtIndex:i];  
126 - NSLog(@"%@ - %i objects, %i bytes", container.name, container.count, container.bytes);  
127 - }  
128 -  
129 - ASICloudFilesContainerRequest *createContainerRequest = [ASICloudFilesContainerRequest createContainerRequest:@"ASICloudFiles"];  
130 - [createContainerRequest start];  
131 - NSLog(@"Create response status code: %i", [createContainerRequest responseStatusCode]);  
132 - NSLog(@"Create response status message: %@", [createContainerRequest responseStatusMessage]);  
133 -  
134 - ASICloudFilesContainerRequest *deleteContainerRequest = [ASICloudFilesContainerRequest deleteContainerRequest:@"ASICloudFiles"];  
135 - [deleteContainerRequest start];  
136 - NSLog(@"Delete response status code: %i", [deleteContainerRequest responseStatusCode]);  
137 - NSLog(@"Delete response status message: %@", [deleteContainerRequest responseStatusMessage]);  
138 - */  
139 -  
140 - // OBJECT LIST TEST  
141 - /*  
142 - ASICloudFilesObjectRequest *objectListRequest = [ASICloudFilesObjectRequest listRequestWithContainer:@"cf_service"];  
143 - [objectListRequest start];  
144 -  
145 - containers = [objectListRequest objects];  
146 - NSLog(@"cf_service object list count: %i", [containers count]);  
147 - for (int i = 0; i < [containers count]; i++) {  
148 - ASICloudFilesObject *object = [containers objectAtIndex:i];  
149 - NSLog(@"%@ - %@ - %i bytes, %@, %@", object.name, object.hash, object.bytes, object.contentType, [object.lastModified description]);  
150 - }  
151 - */  
152 -  
153 -  
154 -  
155 // Add the tab bar controller's current view as a subview of the window 27 // Add the tab bar controller's current view as a subview of the window
156 [window addSubview:[tabBarController view]]; 28 [window addSubview:[tabBarController view]];
157 [[tabBarController view] setFrame:CGRectMake(0,47,320,433)]; 29 [[tabBarController view] setFrame:CGRectMake(0,47,320,433)];