-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implemented full xep-0030 and added tests
- Loading branch information
Andres Canal
committed
Jul 11, 2016
1 parent
c4aeead
commit 12db9b7
Showing
6 changed files
with
341 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// XMPPServiceDiscovery.h | ||
// Mangosta | ||
// | ||
// Created by Andres Canal on 4/27/16. | ||
// Copyright © 2016 Inaka. All rights reserved. | ||
// | ||
|
||
#import <XMPPFramework/XMPPFramework.h> | ||
|
||
@class XMPPIDTracker; | ||
|
||
@interface XMPPServiceDiscovery : XMPPModule { | ||
XMPPIDTracker *xmppIDTracker; | ||
} | ||
|
||
- (void)discoverInformationAboutJID:(nonnull XMPPJID *)jid; | ||
- (void)discoverItemsAssociatedWithJID:(nonnull XMPPJID *)jid; | ||
|
||
@end | ||
|
||
@protocol XMPPServiceDiscoveryDelegate | ||
|
||
@optional | ||
|
||
- (void)xmppServiceDiscovery:(nonnull XMPPServiceDiscovery *)sender didDiscoverInformation:(nonnull NSArray<NSXMLElement *> *)items; | ||
- (void)xmppServiceDiscovery:(nonnull XMPPServiceDiscovery *)sender didDiscoverItems:(nonnull NSArray <NSXMLElement *>*)items; | ||
|
||
- (void)xmppServiceDiscovery:(nonnull XMPPServiceDiscovery *)sender didFailToDiscover:(nonnull XMPPIQ *)iq; | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// | ||
// XMPPServiceDiscovery.m | ||
// Mangosta | ||
// | ||
// Created by Andres Canal on 4/27/16. | ||
// Copyright © 2016 Inaka. All rights reserved. | ||
// | ||
|
||
#import "XMPPServiceDiscovery.h" | ||
#import "XMPPIQ+XEP_0030.h" | ||
#import "XMPPIDTracker.h" | ||
#import "XMPPConstants.h" | ||
|
||
@implementation XMPPServiceDiscovery | ||
|
||
- (BOOL)activate:(XMPPStream *)aXmppStream { | ||
|
||
if ([super activate:aXmppStream]) { | ||
xmppIDTracker = [[XMPPIDTracker alloc] initWithDispatchQueue:moduleQueue]; | ||
|
||
return YES; | ||
} | ||
|
||
return NO; | ||
} | ||
|
||
- (void)deactivate { | ||
dispatch_block_t block = ^{ @autoreleasepool { | ||
|
||
[xmppIDTracker removeAllIDs]; | ||
xmppIDTracker = nil; | ||
|
||
}}; | ||
|
||
if (dispatch_get_specific(moduleQueueTag)) | ||
block(); | ||
else | ||
dispatch_sync(moduleQueue, block); | ||
|
||
[super deactivate]; | ||
} | ||
|
||
- (void) discoverWithIQ:(XMPPIQ *) infoOrItem { | ||
|
||
dispatch_block_t block = ^{ @autoreleasepool { | ||
|
||
NSString *iqID = [infoOrItem elementID]; | ||
[xmppIDTracker addID:iqID | ||
target:self | ||
selector:@selector(handleDiscovery:withInfo:) | ||
timeout:60.0]; | ||
|
||
[xmppStream sendElement:infoOrItem]; | ||
}}; | ||
|
||
if (dispatch_get_specific(moduleQueueTag)) | ||
block(); | ||
else | ||
dispatch_async(moduleQueue, block); | ||
} | ||
|
||
- (void)discoverInformationAboutJID:(XMPPJID *)jid{ | ||
[self discoverWithIQ:[XMPPIQ discoverInfoAssociatedWithJID:jid]]; | ||
} | ||
|
||
|
||
- (void)discoverItemsAssociatedWithJID:(XMPPJID *)jid{ | ||
[self discoverWithIQ:[XMPPIQ discoverItemsAssociatedWithJID:jid]]; | ||
} | ||
|
||
- (void)handleDiscovery:(XMPPIQ *)iq withInfo:(id <XMPPTrackingInfo>)info{ | ||
|
||
if ([[iq type] isEqualToString:@"result"]){ | ||
NSXMLElement *query = [iq elementForName:@"query"]; | ||
NSArray *items = [query children]; | ||
|
||
if ([query.xmlns isEqualToString:XMPPDiscoInfoNamespace]) { | ||
[multicastDelegate xmppServiceDiscovery:self didDiscoverInformation:items]; | ||
} else { | ||
[multicastDelegate xmppServiceDiscovery:self didDiscoverItems:items]; | ||
} | ||
|
||
} else { | ||
[multicastDelegate xmppServiceDiscovery:self didFailToDiscover:iq]; | ||
} | ||
} | ||
|
||
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq { | ||
|
||
NSString *type = [iq type]; | ||
|
||
if ([type isEqualToString:@"result"] || [type isEqualToString:@"error"]){ | ||
return [xmppIDTracker invokeForID:[iq elementID] withObject:iq]; | ||
} | ||
|
||
return NO; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
// | ||
// XMPPServiceDiscoveryTests.m | ||
// XMPPFrameworkTests | ||
// | ||
// Created by Andres Canal on 5/27/16. | ||
// | ||
// | ||
|
||
#import <XCTest/XCTest.h> | ||
#import "XMPPFramework/XMPPServiceDiscovery.h" | ||
#import "XMPPMockStream.h" | ||
|
||
@interface XMPPServiceDiscoveryTests : XCTestCase <XMPPServiceDiscoveryDelegate> | ||
@property (nonatomic, strong) XCTestExpectation *delegateExpectation; | ||
@end | ||
|
||
@implementation XMPPServiceDiscoveryTests | ||
|
||
- (void) testDiscoverInformationAbout{ | ||
self.delegateExpectation = [self expectationWithDescription:@"Information Response"]; | ||
|
||
XMPPMockStream *streamTest = [[XMPPMockStream alloc] init]; | ||
XMPPServiceDiscovery *serviceDiscovery = [[XMPPServiceDiscovery alloc] init]; | ||
[serviceDiscovery activate:streamTest]; | ||
[serviceDiscovery addDelegate:self delegateQueue:dispatch_get_main_queue()]; | ||
|
||
__weak typeof(XMPPMockStream) *weakStreamTest = streamTest; | ||
streamTest.elementReceived = ^void(NSXMLElement *element) { | ||
NSString *elementID = [element attributeForName:@"id"].stringValue; | ||
XMPPIQ *iq = [self fakeInfoIQWithID:elementID]; | ||
[weakStreamTest fakeIQResponse:iq]; | ||
}; | ||
|
||
[serviceDiscovery discoverInformationAboutJID:[XMPPJID jidWithString:@"test.com"]]; | ||
|
||
[self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) { | ||
if(error){ | ||
XCTFail(@"Expectation Failed with error: %@", error); | ||
} | ||
}]; | ||
} | ||
|
||
- (void)xmppServiceDiscovery:(XMPPServiceDiscovery *)sender didDiscoverInformation:(NSArray *)items{ | ||
XCTAssertEqual(items.count, 9); | ||
[self.delegateExpectation fulfill]; | ||
} | ||
|
||
- (void) testDiscoverItems{ | ||
self.delegateExpectation = [self expectationWithDescription:@"Items Response"]; | ||
|
||
XMPPMockStream *streamTest = [[XMPPMockStream alloc] init]; | ||
XMPPServiceDiscovery *serviceDiscovery = [[XMPPServiceDiscovery alloc] init]; | ||
[serviceDiscovery activate:streamTest]; | ||
[serviceDiscovery addDelegate:self delegateQueue:dispatch_get_main_queue()]; | ||
|
||
__weak typeof(XMPPMockStream) *weakStreamTest = streamTest; | ||
streamTest.elementReceived = ^void(NSXMLElement *element) { | ||
NSString *elementID = [element attributeForName:@"id"].stringValue; | ||
XMPPIQ *iq = [self fakeItemIQWithID:elementID]; | ||
[weakStreamTest fakeIQResponse:iq]; | ||
}; | ||
|
||
[serviceDiscovery discoverItemsAssociatedWithJID:[XMPPJID jidWithString:@"test.com"]]; | ||
|
||
[self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) { | ||
if(error){ | ||
XCTFail(@"Expectation Failed with error: %@", error); | ||
} | ||
}]; | ||
} | ||
|
||
- (void)xmppServiceDiscovery:(XMPPServiceDiscovery *)sender didDiscoverItems:(NSArray *)items{ | ||
XCTAssertEqual(items.count, 8); | ||
[self.delegateExpectation fulfill]; | ||
} | ||
|
||
- (void) testError{ | ||
self.delegateExpectation = [self expectationWithDescription:@"Error Response"]; | ||
|
||
XMPPMockStream *streamTest = [[XMPPMockStream alloc] init]; | ||
XMPPServiceDiscovery *serviceDiscovery = [[XMPPServiceDiscovery alloc] init]; | ||
[serviceDiscovery activate:streamTest]; | ||
[serviceDiscovery addDelegate:self delegateQueue:dispatch_get_main_queue()]; | ||
|
||
__weak typeof(XMPPMockStream) *weakStreamTest = streamTest; | ||
streamTest.elementReceived = ^void(NSXMLElement *element) { | ||
NSString *elementID = [element attributeForName:@"id"].stringValue; | ||
XMPPIQ *iq = [self fakeErrorWithID:elementID]; | ||
[weakStreamTest fakeIQResponse:iq]; | ||
}; | ||
|
||
[serviceDiscovery discoverItemsAssociatedWithJID:[XMPPJID jidWithString:@"test.com"]]; | ||
|
||
[self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) { | ||
if(error){ | ||
XCTFail(@"Expectation Failed with error: %@", error); | ||
} | ||
}]; | ||
} | ||
|
||
- (XMPPIQ *)fakeErrorWithID:(NSString *) elementID{ | ||
NSMutableString *s = [NSMutableString string]; | ||
[s appendString:@"<iq type='error'"]; | ||
[s appendString:@" from='mim.shakespeare.lit'"]; | ||
[s appendString:@" to='romeo@montague.net/orchard'"]; | ||
[s appendString:@" id='info3'>"]; | ||
[s appendString:@" <query xmlns='http://jabber.org/protocol/disco#info' "]; | ||
[s appendString:@" node='http://jabber.org/protocol/commands'/>"]; | ||
[s appendString:@" <error type='cancel'>"]; | ||
[s appendString:@" <not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"]; | ||
[s appendString:@" </error>"]; | ||
[s appendString:@"</iq>"]; | ||
|
||
NSError *error; | ||
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithXMLString:s options:0 error:&error]; | ||
XMPPIQ *iq = [XMPPIQ iqFromElement:[doc rootElement]]; | ||
[iq addAttributeWithName:@"id" stringValue:elementID]; | ||
|
||
return iq; | ||
} | ||
|
||
- (void)xmppServiceDiscovery:(XMPPServiceDiscovery *)sender didFailToDiscover:(XMPPIQ *)iq{ | ||
XCTAssertNotNil([iq elementForName:@"error"]); | ||
[self.delegateExpectation fulfill]; | ||
} | ||
|
||
|
||
- (XMPPIQ *)fakeItemIQWithID:(NSString *) elementID{ | ||
NSMutableString *s = [NSMutableString string]; | ||
[s appendString:@"<iq type='result'"]; | ||
[s appendString:@" from='shakespeare.lit'"]; | ||
[s appendString:@" to='romeo@montague.net/orchard'"]; | ||
[s appendString:@" id='items1'>"]; | ||
[s appendString:@" <query xmlns='http://jabber.org/protocol/disco#items'>"]; | ||
[s appendString:@" <item jid='people.shakespeare.lit'"]; | ||
[s appendString:@" name='Directory of Characters'/>"]; | ||
[s appendString:@" <item jid='plays.shakespeare.lit'"]; | ||
[s appendString:@" name='Play-Specific Chatrooms'/>"]; | ||
[s appendString:@" <item jid='mim.shakespeare.lit'"]; | ||
[s appendString:@" name='Gateway to Marlowe IM'/>"]; | ||
[s appendString:@" <item jid='words.shakespeare.lit'"]; | ||
[s appendString:@" name='Shakespearean Lexicon'/>"]; | ||
[s appendString:@" <item jid='globe.shakespeare.lit'"]; | ||
[s appendString:@" name='Calendar of Performances'/>"]; | ||
[s appendString:@" <item jid='headlines.shakespeare.lit'"]; | ||
[s appendString:@" name='Latest Shakespearean News'/>"]; | ||
[s appendString:@" <item jid='catalog.shakespeare.lit'"]; | ||
[s appendString:@" name='Buy Shakespeare Stuff!'/>"]; | ||
[s appendString:@" <item jid='en2fr.shakespeare.lit'"]; | ||
[s appendString:@" name='French Translation Service'/>"]; | ||
[s appendString:@" </query>"]; | ||
[s appendString:@"</iq>"]; | ||
|
||
NSError *error; | ||
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithXMLString:s options:0 error:&error]; | ||
XMPPIQ *iq = [XMPPIQ iqFromElement:[doc rootElement]]; | ||
[iq addAttributeWithName:@"id" stringValue:elementID]; | ||
|
||
return iq; | ||
} | ||
|
||
- (XMPPIQ *)fakeInfoIQWithID:(NSString *) elementID{ | ||
|
||
NSMutableString *s = [NSMutableString string]; | ||
[s appendString: @"<iq type='result'"]; | ||
[s appendString: @" from='plays.shakespeare.lit'"]; | ||
[s appendString: @" to='romeo@montague.net/orchard'"]; | ||
[s appendString: @" id='info1'>"]; | ||
[s appendString: @" <query xmlns='http://jabber.org/protocol/disco#info'>"]; | ||
[s appendString: @" <identity"]; | ||
[s appendString: @" category='conference'"]; | ||
[s appendString: @" type='text'"]; | ||
[s appendString: @" name='Play-Specific Chatrooms'/>"]; | ||
[s appendString: @" <identity"]; | ||
[s appendString: @" category='directory'"]; | ||
[s appendString: @" type='chatroom'"]; | ||
[s appendString: @" name='Play-Specific Chatrooms'/>"]; | ||
[s appendString: @" <feature var='http://jabber.org/protocol/disco#info'/>"]; | ||
[s appendString: @" <feature var='http://jabber.org/protocol/disco#items'/>"]; | ||
[s appendString: @" <feature var='http://jabber.org/protocol/muc'/>"]; | ||
[s appendString: @" <feature var='jabber:iq:register'/>"]; | ||
[s appendString: @" <feature var='jabber:iq:search'/>"]; | ||
[s appendString: @" <feature var='jabber:iq:time'/>"]; | ||
[s appendString: @" <feature var='jabber:iq:version'/>"]; | ||
[s appendString: @" </query>"]; | ||
[s appendString: @"</iq>"]; | ||
|
||
NSError *error; | ||
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithXMLString:s options:0 error:&error]; | ||
XMPPIQ *iq = [XMPPIQ iqFromElement:[doc rootElement]]; | ||
[iq addAttributeWithName:@"id" stringValue:elementID]; | ||
|
||
return iq; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.