diff --git a/Gemfile b/Gemfile index fc4dc82e..1274d96b 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source "http://rubygems.org" gem "rake" -gem "uispecrunner", ">= 0.4.0" +gem "uispecrunner", ">= 0.4.2" gem "bundler", "~> 1.0.0" gem "sinatra", ">= 1.2.0" gem "shotgun", ">= 0.9" diff --git a/Gemfile.lock b/Gemfile.lock index a42803d9..917689bb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,7 +16,7 @@ GEM eventmachine (>= 0.12.6) rack (>= 1.0.0) tilt (1.2.2) - uispecrunner (0.4.0) + uispecrunner (0.4.2) open4 (= 1.0.1) PLATFORMS @@ -28,7 +28,7 @@ DEPENDENCIES shotgun (>= 0.9) sinatra (>= 1.2.0) thin (>= 1.2.8) - uispecrunner (>= 0.4.0) + uispecrunner (>= 0.4.2) METADATA version: 1.0.6 diff --git a/RestKit.xcodeproj/project.pbxproj b/RestKit.xcodeproj/project.pbxproj index c569ef12..a6c5a8f8 100644 --- a/RestKit.xcodeproj/project.pbxproj +++ b/RestKit.xcodeproj/project.pbxproj @@ -167,6 +167,8 @@ 259D53B8132854A900897272 /* RKSpecResponseLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 259D5135132854A700897272 /* RKSpecResponseLoader.m */; }; 259D5535132854A900897272 /* UISpec+UISpecRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 259D53A2132854A800897272 /* UISpec+UISpecRunner.m */; }; 259D5558132856D800897272 /* libUISpec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 259D5557132856D700897272 /* libUISpec.a */; }; + 259D56B5132E706D00897272 /* RKAuthenticationSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 259D56B4132E706D00897272 /* RKAuthenticationSpec.m */; }; + 259D56BC132E84B300897272 /* RKSpecEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 259D56BB132E84B300897272 /* RKSpecEnvironment.m */; }; 3F032A7910FFB89100F35142 /* RKCat.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F032A7810FFB89100F35142 /* RKCat.m */; }; 3F032AA810FFBBCD00F35142 /* RKHouse.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F032AA710FFBBCD00F35142 /* RKHouse.m */; }; 3F032AAB10FFBC1F00F35142 /* RKResident.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F032AAA10FFBC1F00F35142 /* RKResident.m */; }; @@ -463,6 +465,8 @@ 259D53A2132854A800897272 /* UISpec+UISpecRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UISpec+UISpecRunner.m"; sourceTree = ""; }; 259D5548132856A400897272 /* UISpec.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = UISpec.xcodeproj; path = UISpec/xcode/UISpec/UISpec.xcodeproj; sourceTree = ""; }; 259D5557132856D700897272 /* libUISpec.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libUISpec.a; sourceTree = SOURCE_ROOT; }; + 259D56B4132E706D00897272 /* RKAuthenticationSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKAuthenticationSpec.m; sourceTree = ""; }; + 259D56BB132E84B300897272 /* RKSpecEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKSpecEnvironment.m; sourceTree = ""; }; 25E075981279D9AB00B22EC9 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 3F032A7710FFB89100F35142 /* RKCat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RKCat.h; sourceTree = ""; }; 3F032A7810FFB89100F35142 /* RKCat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RKCat.m; sourceTree = ""; }; @@ -917,6 +921,7 @@ 259D51111328547000897272 /* RKParamsAttachmentSpec.m */, 259D51121328547000897272 /* RKRequestSpec.m */, 259D51131328547000897272 /* RKResponseSpec.m */, + 259D56B4132E706D00897272 /* RKAuthenticationSpec.m */, ); path = Network; sourceTree = ""; @@ -953,6 +958,7 @@ 259D53A1132854A800897272 /* UISpec+UISpecRunner.h */, 259D53A2132854A800897272 /* UISpec+UISpecRunner.m */, 259D5557132856D700897272 /* libUISpec.a */, + 259D56BB132E84B300897272 /* RKSpecEnvironment.m */, ); path = Runner; sourceTree = ""; @@ -1496,6 +1502,8 @@ 259D53B6132854A900897272 /* main.m in Sources */, 259D53B8132854A900897272 /* RKSpecResponseLoader.m in Sources */, 259D5535132854A900897272 /* UISpec+UISpecRunner.m in Sources */, + 259D56B5132E706D00897272 /* RKAuthenticationSpec.m in Sources */, + 259D56BC132E84B300897272 /* RKSpecEnvironment.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1886,9 +1894,9 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/UIKit.framework/Headers/UIKit.h"; HEADER_SEARCH_PATHS = ( - Build, Specs/Runner/OCMock/Headers, Specs/Runner/UISpec/headers, + Build, ); INFOPLIST_FILE = "Specs/Runner/UISpec-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; @@ -1924,9 +1932,9 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/UIKit.framework/Headers/UIKit.h"; HEADER_SEARCH_PATHS = ( - Build, Specs/Runner/OCMock/Headers, Specs/Runner/UISpec/headers, + Build, ); INFOPLIST_FILE = "Specs/Runner/UISpec-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; diff --git a/RestKit.xcworkspace/contents.xcworkspacedata b/RestKit.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..709e5bc0 --- /dev/null +++ b/RestKit.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,2499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Specs/CoreData/RKManagedObjectSpec.m b/Specs/CoreData/RKManagedObjectSpec.m index f9d2e3dc..f3e47764 100644 --- a/Specs/CoreData/RKManagedObjectSpec.m +++ b/Specs/CoreData/RKManagedObjectSpec.m @@ -7,7 +7,6 @@ // #import "RKSpecEnvironment.h" -#import "RKObjectManager.h" #import "RKHuman.h" @interface RKManagedObjectSpec : NSObject { diff --git a/Specs/Network/RKAuthenticationSpec.m b/Specs/Network/RKAuthenticationSpec.m new file mode 100644 index 00000000..128308e9 --- /dev/null +++ b/Specs/Network/RKAuthenticationSpec.m @@ -0,0 +1,63 @@ +// +// RKAuthenticationSpec.m +// RestKit +// +// Created by Blake Watters on 3/14/11. +// Copyright 2011 Two Toasters. All rights reserved. +// + +#import "RKSpecEnvironment.h" +#import "RKClient.h" + +static NSString* const RKAuthenticationSpecUsername = @"restkit"; +static NSString* const RKAuthenticationSpecPassword = @"authentication"; + +@interface RKAuthenticationSpec : NSObject { + +} + +@end + +@implementation RKAuthenticationSpec + +- (void)itShouldAccessUnprotectedResourcePaths { + RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader]; + RKClient* client = [RKClient clientWithBaseURL:RKSpecGetBaseURL()]; + [client get:@"/authentication/none" delegate:loader]; + [loader waitForResponse]; + [expectThat([loader.response isOK]) should:be(YES)]; +} + +- (void)itShouldAuthenticateViaHTTPAuthBasic { + RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader]; + RKClient* client = [RKClient clientWithBaseURL:RKSpecGetBaseURL()]; + client.username = RKAuthenticationSpecUsername; + client.password = RKAuthenticationSpecPassword; + [client get:@"/authentication/basic" delegate:loader]; + [loader waitForResponse]; + [expectThat([loader.response isOK]) should:be(YES)]; +} + +- (void)itShouldFailAuthenticationWithInvalidCredentialsForHTTPAuthBasic { + RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader]; + RKClient* client = [RKClient clientWithBaseURL:RKSpecGetBaseURL()]; + client.username = RKAuthenticationSpecUsername; + client.password = @"INVALID"; + [client get:@"/authentication/basic" delegate:loader]; + [loader waitForResponse]; + [expectThat([loader.response isOK]) should:be(NO)]; + [expectThat([loader.response statusCode]) should:be(0)]; + [expectThat([loader.failureError code]) should:be(NSURLErrorUserCancelledAuthentication)]; +} + +- (void)itShouldAuthenticateViaHTTPAuthDigest { + RKSpecResponseLoader* loader = [RKSpecResponseLoader responseLoader]; + RKClient* client = [RKClient clientWithBaseURL:RKSpecGetBaseURL()]; + client.username = RKAuthenticationSpecUsername; + client.password = RKAuthenticationSpecPassword; + [client get:@"/authentication/digest" delegate:loader]; + [loader waitForResponse]; + [expectThat([loader.response isOK]) should:be(YES)]; +} + +@end diff --git a/Specs/Network/RKClientSpec.m b/Specs/Network/RKClientSpec.m index 0f5eb97d..0661b090 100644 --- a/Specs/Network/RKClientSpec.m +++ b/Specs/Network/RKClientSpec.m @@ -7,7 +7,6 @@ // #import "RKSpecEnvironment.h" -#import @interface RKClientSpec : NSObject { } diff --git a/Specs/ObjectMapping/RKDynamicRouterSpec.m b/Specs/ObjectMapping/RKDynamicRouterSpec.m index dfa02603..4c02021d 100644 --- a/Specs/ObjectMapping/RKDynamicRouterSpec.m +++ b/Specs/ObjectMapping/RKDynamicRouterSpec.m @@ -7,10 +7,7 @@ // #import "RKSpecEnvironment.h" -#import "RKDynamicRouter.h" #import "RKHuman.h" -#import "RKObjectManager.h" -#import "RKManagedObjectStore.h" @interface RKDynamicRouterSpec : NSObject { } diff --git a/Specs/Runner/RKSpecEnvironment.h b/Specs/Runner/RKSpecEnvironment.h index a80f50e9..9b13898f 100644 --- a/Specs/Runner/RKSpecEnvironment.h +++ b/Specs/Runner/RKSpecEnvironment.h @@ -12,11 +12,15 @@ #import "UIExpectation.h" #import -//#import -//#import + +#import "RestKit.h" +#import "RKSpecResponseLoader.h" //////////////////////////////////////////////////////////////////////////// // OCMock - For some reason this macro is incorrect. Note the use of __typeof #undef OCMOCK_VALUE #define OCMOCK_VALUE(variable) [NSValue value:&variable withObjCType:@encode(__typeof(variable))] + +// The Base URL for the Spec server. See Specs/Server/ +NSString* RKSpecGetBaseURL(); diff --git a/Specs/Runner/RKSpecEnvironment.m b/Specs/Runner/RKSpecEnvironment.m new file mode 100644 index 00000000..73956e46 --- /dev/null +++ b/Specs/Runner/RKSpecEnvironment.m @@ -0,0 +1,18 @@ +// +// RKSpecEnvironment.m +// RestKit +// +// Created by Blake Watters on 3/14/11. +// Copyright 2011 Two Toasters. All rights reserved. +// + +#import "RKSpecEnvironment.h" + +NSString* RKSpecGetBaseURL() { + char* ipAddress = getenv("RESTKIT_IP_ADDRESS"); + if (NULL == ipAddress) { + ipAddress = "localhost"; + } + + return [NSString stringWithFormat:@"http://%s:4567", ipAddress]; +} diff --git a/Specs/Runner/RKSpecResponseLoader.h b/Specs/Runner/RKSpecResponseLoader.h index fbe996fb..a2efa2f5 100644 --- a/Specs/Runner/RKSpecResponseLoader.h +++ b/Specs/Runner/RKSpecResponseLoader.h @@ -32,6 +32,9 @@ @property (nonatomic, assign) NSTimeInterval timeout; +// Return a new auto-released loader ++ (RKSpecResponseLoader*)responseLoader; + // Wait for a response to load - (void)waitForResponse; - (void)loadResponse:(id)response; diff --git a/Specs/Runner/RKSpecResponseLoader.m b/Specs/Runner/RKSpecResponseLoader.m index b6274c4d..5ddf98be 100644 --- a/Specs/Runner/RKSpecResponseLoader.m +++ b/Specs/Runner/RKSpecResponseLoader.m @@ -17,10 +17,14 @@ @synthesize success = _success; @synthesize timeout = _timeout; ++ (RKSpecResponseLoader*)responseLoader { + return [[[self alloc] init] autorelease]; +} + - (id)init { self = [super init]; if (self) { - _timeout = 100; + _timeout = 3; _awaitingResponse = NO; } @@ -54,16 +58,29 @@ _success = YES; } +- (void)loadError:(NSError*)error { + NSLog(@"Error: %@", error); + _awaitingResponse = NO; + _success = NO; + _failureError = [error retain]; +} + +- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response { + NSLog(@"Loaded response: %@", response); + [self loadResponse:response]; +} + +- (void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error { + [self loadError:error]; +} + - (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects { NSLog(@"Response: %@", [objectLoader.response bodyAsString]); [self loadResponse:objects]; } -- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error; { - NSLog(@"Error: %@", error); - _awaitingResponse = NO; - _success = NO; - _failureError = [error retain]; +- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error; { + [self loadError:error]; } @end diff --git a/Specs/Server/lib/restkit.rb b/Specs/Server/lib/restkit.rb new file mode 100644 index 00000000..2c4aaca0 --- /dev/null +++ b/Specs/Server/lib/restkit.rb @@ -0,0 +1,2 @@ +require 'restkit/network/authentication' +require 'restkit/object_mapping/model' \ No newline at end of file diff --git a/Specs/Server/lib/restkit/network/authentication.rb b/Specs/Server/lib/restkit/network/authentication.rb new file mode 100644 index 00000000..46961c6f --- /dev/null +++ b/Specs/Server/lib/restkit/network/authentication.rb @@ -0,0 +1,50 @@ +module RestKit + module Network + class Authentication < Sinatra::Base + AUTH_USERNAME = 'restkit' + AUTH_PASSWORD = 'authentication' + + helpers do + def protected! + unless authorized? + response['WWW-Authenticate'] = %(Basic realm="Restricted Area") + throw(:halt, [401, "Not authorized\n"]) + end + end + + def authorized? + @auth ||= Rack::Auth::Basic::Request.new(request.env) + @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ['admin', 'admin'] + end + end + + get '/authentication/none' do + "Success!" + end + + get '/authentication/basic' do + @auth ||= Rack::Auth::Basic::Request.new(request.env) + unless @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == [AUTH_USERNAME, AUTH_PASSWORD] + response['WWW-Authenticate'] = %(Basic realm="Restricted Area") + throw(:halt, [401, "Not authorized\n"]) + end + end + + get '/authentication/digest' do + # TODO.. + @auth = Rack::Auth::Digest::Request.new(request.env) + unless @auth.provided? && @auth.digest? && @auth.credentials && @auth.credentials == [AUTH_USERNAME, AUTH_PASSWORD] + response['WWW-Authenticate'] = %(Basic realm="Restricted Area") + throw(:halt, [401, "Not authorized\n"]) + end + + # do |username| + # username == 'Alice' ? Digest::MD5.hexdigest("Alice:#{realm}:correct-password") : nil + #end + # app.realm = realm + # app.opaque = 'this-should-be-secret' + # app.passwords_hashed = true + end + end + end +end \ No newline at end of file diff --git a/Specs/Server/lib/restkit/object_mapping/model.rb b/Specs/Server/lib/restkit/object_mapping/model.rb new file mode 100644 index 00000000..f45c4e7f --- /dev/null +++ b/Specs/Server/lib/restkit/object_mapping/model.rb @@ -0,0 +1,25 @@ +# TODO: Move this out somewhere/somehow... +# Replace with ActiveModel or something??? +class Model + def self.attributes(*attributes) + @attributes ||= [] + @attributes += attributes + attributes.each { |attr| attr_accessor attr } + end + + def self.defined_attributes + @attributes + end + + def initialize(options = {}) + options.each { |k,v| self.send("#{k}=", v) } + end + + def to_hash + self.class.defined_attributes.inject({}) { |hash, attr| hash[attr] = self.send(attr); hash } + end + + def to_json + JSON.generate(self.to_hash) + end +end diff --git a/Specs/Server/server.rb b/Specs/Server/server.rb index 85bce02c..95da235c 100644 --- a/Specs/Server/server.rb +++ b/Specs/Server/server.rb @@ -2,53 +2,36 @@ # RestKit Spec Server require 'rubygems' -require 'sinatra' +#require 'sinatra' require 'sinatra/base' require 'json' require 'ruby-debug' Debugger.start -# TODO: Push the lib directory onto the include path... +# Import the RestKit Spec server +$: << File.join(File.expand_path(File.dirname(__FILE__)), 'lib') require 'restkit' -# TODO: Move this out somewhere/somehow... -# Replace with ActiveModel or something??? -class Model - def self.attributes(*attributes) - @attributes ||= [] - @attributes += attributes - attributes.each { |attr| attr_accessor attr } - end - - def self.defined_attributes - @attributes - end - - def initialize(options = {}) - options.each { |k,v| self.send("#{k}=", v) } - end - - def to_hash - self.class.defined_attributes.inject({}) { |hash, attr| hash[attr] = self.send(attr); hash } - end - - def to_json - JSON.generate(self.to_hash) - end -end - +# TODO: Factor me out... class Human < Model attributes :id, :name, :sex, :age, :birthday, :created_at, :updated_at end class RestKit::SpecServer < Sinatra::Base + self.app_file = __FILE__ use RestKit::Network::Authentication + configure do + set :logging, true + set :dump_errors, true + end + post '/photo' do content_type 'application/json' "OK" end + # TODO: Move to object_mapping dir get '/humans/1' do content_type 'application/json' JSON.generate(:human => Human.new(:name => 'Blake Watters').to_hash) @@ -58,14 +41,6 @@ class RestKit::SpecServer < Sinatra::Base content_type 'application/json' JSON.generate([{:human => Human.new(:name => 'Blake Watters').to_hash}, {:human => Human.new(:name => "Other").to_hash}]) end - - # TODO: Factor these out... - get '/authentication/basic' do - - end - - get '/authentication/digest' do - end # start the server if ruby file executed directly run! if app_file == $0