mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			191 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Objective-C
		
	
			
		
		
	
	
			191 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Objective-C
		
	
| #import <XCTest/XCTest.h>
 | |
| #import <CoreFoundation/CFSocket.h>
 | |
| #import "IpAddress.h"
 | |
| #import "TestUtil.h"
 | |
| #import "ThreadManager.h"
 | |
| #import "UdpSocket.h"
 | |
| #import "Util.h"
 | |
| 
 | |
| @interface UdpSocketTest : XCTestCase
 | |
| 
 | |
| @end
 | |
| 
 | |
| @implementation UdpSocketTest
 | |
| -(void) testSpecifiedPortLocally {
 | |
|     TOCCancelTokenSource* receiverLife = [TOCCancelTokenSource new];
 | |
|     TOCCancelTokenSource* senderLife = [TOCCancelTokenSource new];
 | |
|     
 | |
|     __block NSData* received = nil;
 | |
|     __block bool senderReceivedData = false;
 | |
|     NSData* r1 = [@[@2,@3,@5] ows_toUint8Data];
 | |
|     NSData* r2 = [@[@7,@11,@13] ows_toUint8Data];
 | |
|     NSData* r3 = [@[@17,@19,@23] ows_toUint8Data];
 | |
|     
 | |
|     in_port_t port1 = (in_port_t)(arc4random_uniform(40000) + 10000);
 | |
|     in_port_t port2 = port1 + (in_port_t)1;
 | |
|     
 | |
|     UdpSocket* receiver = [UdpSocket udpSocketFromLocalPort:port1 toRemoteEndPoint:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:port2]];
 | |
|     UdpSocket* sender = [UdpSocket udpSocketFromLocalPort:port2 toRemoteEndPoint:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:port1]];
 | |
|     [receiver startWithHandler:[PacketHandler packetHandler:^(id packet) {
 | |
|         received = packet;
 | |
|     } withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
 | |
|         test(false);
 | |
|     }] untilCancelled:receiverLife.token];
 | |
|     __block bool failed = false;
 | |
|     [sender startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
 | |
|         // there's a length check here because when the destination is unreachable the sender sometimes gets a superfluous empty data callback... no idea why.
 | |
|         senderReceivedData |= packet.length > 0;
 | |
|     } withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
 | |
|         failed = true;
 | |
|     }] untilCancelled:senderLife.token];
 | |
|     
 | |
|     test(receiver.isLocalPortKnown);
 | |
|     test(receiver.localPort == port1);
 | |
|     test(sender.isLocalPortKnown);
 | |
|     test(sender.localPort == port2);
 | |
| 
 | |
|     testChurnAndConditionMustStayTrue(received == nil, 0.1);
 | |
|     
 | |
|     [sender send:r1];
 | |
|     testChurnUntil([received isEqualToData:r1], 1.0);
 | |
|     test([received isEqualToData:r1]);
 | |
|     
 | |
|     [sender send:r2];
 | |
|     testChurnUntil([received isEqualToData:r2], 1.0);
 | |
|     
 | |
|     [receiverLife cancel];
 | |
|     test(!failed);
 | |
|     [sender send:r3];
 | |
|     testChurnUntil(failed, 1.0);
 | |
|     test([received isEqualToData:r2]);
 | |
|     
 | |
|     [senderLife cancel];
 | |
|     test(!senderReceivedData);
 | |
| }
 | |
| -(void) testArbitraryPortLocally {
 | |
|     TOCCancelTokenSource* receiverLife = [TOCCancelTokenSource new];
 | |
|     TOCCancelTokenSource* senderLife = [TOCCancelTokenSource new];
 | |
|     
 | |
|     __block NSData* received = nil;
 | |
|     __block bool senderReceivedData = false;
 | |
|     NSData* r1 = [@[@2,@3,@5] ows_toUint8Data];
 | |
|     NSData* r2 = [@[@7,@11,@13] ows_toUint8Data];
 | |
|     NSData* r3 = [@[@17,@19,@23] ows_toUint8Data];
 | |
|     
 | |
|     in_port_t unusedPort = (in_port_t)(arc4random_uniform(40000) + 10000);
 | |
|     
 | |
|     UdpSocket* receiver = [UdpSocket udpSocketTo:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost
 | |
|                                                                           onPort:unusedPort]];
 | |
|     [receiver startWithHandler:[PacketHandler packetHandler:^(id packet) {
 | |
|         @synchronized (churnLock()) {
 | |
|             received = packet;
 | |
|         }
 | |
|     } withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
 | |
|         test(false);
 | |
|     }] untilCancelled:receiverLife.token];
 | |
|     
 | |
|     __block bool failed = false;
 | |
|     UdpSocket* sender = [UdpSocket udpSocketFromLocalPort:unusedPort
 | |
|                                          toRemoteEndPoint:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost
 | |
|                                                                                    onPort:receiver.localPort]];
 | |
|     [sender startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
 | |
|         // there's a length check here because when the destination is unreachable the sender sometimes gets a superfluous empty data callback... no idea why.
 | |
|         senderReceivedData |= packet.length > 0;
 | |
|     } withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
 | |
|         failed = true;
 | |
|     }] untilCancelled:senderLife.token];
 | |
|     
 | |
|     
 | |
|     testChurnAndConditionMustStayTrue(received == nil, 0.1);
 | |
|     
 | |
|     [sender send:r1];
 | |
|     testChurnUntil([received isEqualToData:r1], 1.0);
 | |
|     
 | |
|     [sender send:r2];
 | |
|     testChurnUntil([received isEqualToData:r2], 1.0);
 | |
|     
 | |
|     [receiverLife cancel];
 | |
|     test(!failed);
 | |
|     [sender send:r3];
 | |
|     testChurnAndConditionMustStayTrue([received isEqualToData:r2], 0.1);
 | |
|     test([received isEqualToData:r2]);
 | |
|     
 | |
|     [senderLife cancel];
 | |
|     test(!senderReceivedData);
 | |
| }
 | |
| -(void) testUdpListen {
 | |
|     TOCCancelTokenSource* receiverLife = [TOCCancelTokenSource new];
 | |
|     TOCCancelTokenSource* senderLife = [TOCCancelTokenSource new];
 | |
|     
 | |
|     __block NSUInteger listenerReceiveCount = 0;
 | |
|     __block NSUInteger listenerReceiveLength = 0;
 | |
|     __block NSData* listenerReceivedLast = nil;
 | |
|     __block NSUInteger clientReceiveCount = 0;
 | |
|     __block NSUInteger clientReceiveLength = 0;
 | |
|     __block NSData* clientReceivedLast = nil;
 | |
|     
 | |
|     in_port_t port = (in_port_t)(arc4random_uniform(40000) + 10000);
 | |
|     
 | |
|     UdpSocket* listener = [UdpSocket udpSocketToFirstSenderOnLocalPort:port];
 | |
|     [listener startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
 | |
|         listenerReceiveCount += 1;
 | |
|         listenerReceiveLength += packet.length;
 | |
|         listenerReceivedLast = packet;
 | |
|     } withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
 | |
|         test(false);
 | |
|     }] untilCancelled:receiverLife.token];
 | |
|     
 | |
|     IpEndPoint* e = [IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:port];
 | |
|     UdpSocket* client = [UdpSocket udpSocketTo:e];
 | |
|     [client startWithHandler:[PacketHandler packetHandler:^(NSData* packet) {
 | |
|         clientReceiveCount += 1;
 | |
|         clientReceiveLength += packet.length;
 | |
|         clientReceivedLast = packet;
 | |
|     } withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
 | |
|         test(false);
 | |
|     }] untilCancelled:senderLife.token];
 | |
|     
 | |
|     test(!listener.isRemoteEndPointKnown);
 | |
|     testThrows([listener remoteEndPoint]);
 | |
|     test(client.isRemoteEndPointKnown);
 | |
|     test([client remoteEndPoint] == e);
 | |
|     test(listenerReceiveCount == 0);
 | |
|     test(clientReceiveCount == 0);
 | |
|     
 | |
|     [client send:increasingData(10)];
 | |
|     testChurnUntil(listenerReceiveCount > 0, 1.0);
 | |
|     test(clientReceiveCount == 0);
 | |
|     test(listener.isRemoteEndPointKnown);
 | |
|     test([[[[listener remoteEndPoint] address] description] isEqualToString:@"127.0.0.1"]);
 | |
|     test(listenerReceiveLength == 10);
 | |
|     test([listenerReceivedLast isEqualToData:increasingData(10)]);
 | |
|     
 | |
|     [listener send:increasingData(20)];
 | |
|     testChurnUntil(clientReceiveCount > 0, 1.0);
 | |
|     test(listenerReceiveCount == 1);
 | |
|     test(clientReceiveCount == 1);
 | |
|     test(clientReceiveLength == 20);
 | |
|     test([clientReceivedLast isEqualToData:increasingData(20)]);
 | |
|     
 | |
|     [receiverLife cancel];
 | |
|     [senderLife cancel];
 | |
| }
 | |
| -(void) testUdpFail {
 | |
|     TOCCancelTokenSource* life = [TOCCancelTokenSource new];
 | |
|     
 | |
|     in_port_t unusedPort = 10000 + (in_port_t)arc4random_uniform(30000);
 | |
|     UdpSocket* udp = [UdpSocket udpSocketTo:[IpEndPoint ipEndPointAtAddress:IpAddress.localhost onPort:unusedPort]];
 | |
|     __block bool failed = false;
 | |
|     [udp startWithHandler:[PacketHandler packetHandler:^(id packet) {
 | |
|         test(false);
 | |
|     } withErrorHandler:^(id error, id relatedInfo, bool causedTermination) {
 | |
|         failed = true;
 | |
|     }] untilCancelled:life.token];
 | |
|     
 | |
|     [udp send:increasingData(20)];
 | |
|     testChurnUntil(failed, 1.0);
 | |
|     
 | |
|     [life cancel];
 | |
| }
 | |
| @end
 |