Skip to content

Commit

Permalink
Add tests for #470
Browse files Browse the repository at this point in the history
  • Loading branch information
paddybyers committed Jul 9, 2019
1 parent 45460c4 commit bfd6f6e
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 11 deletions.
127 changes: 116 additions & 11 deletions lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
package io.ably.lib.test.realtime;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.junit.Test;
import io.ably.lib.realtime.*;
import io.ably.lib.transport.ConnectionManager;
import io.ably.lib.transport.Defaults;
import io.ably.lib.util.Log;

import io.ably.lib.debug.DebugOptions;
import io.ably.lib.realtime.AblyRealtime;
import io.ably.lib.realtime.Channel;
import io.ably.lib.realtime.ChannelState;
import io.ably.lib.realtime.ConnectionState;
import io.ably.lib.rest.AblyRest;
import io.ably.lib.rest.Auth;
import io.ably.lib.rest.Auth.TokenDetails;
Expand All @@ -26,6 +19,9 @@
import io.ably.lib.types.ErrorInfo;
import io.ably.lib.types.Message;
import io.ably.lib.types.ProtocolMessage;
import org.junit.Test;

import static org.junit.Assert.*;

public class RealtimeAuthTest extends ParameterizedTest {

Expand Down Expand Up @@ -700,4 +696,113 @@ public void auth_clientid_publish_explicit_before_identified() {
}
}
}

/**
* Verify that with queryTime=false, when instancing with an already-expired token and authCallback,
* connection can succeed
*/
@Test
public void auth_expired_token_expire_before_connect_renew() {
try {
/* get a TokenDetails */
final String testKey = testVars.keys[0].keyStr;
ClientOptions optsForToken = createOptions(testKey);
optsForToken.queryTime = false;
final AblyRest ablyForToken = new AblyRest(optsForToken);

TokenDetails tokenDetails = ablyForToken.auth.requestToken(new Auth.TokenParams(){{ ttl = 100L; }}, null);
assertNotNull("Expected token value", tokenDetails.token);

/* allow to expire */
try { Thread.sleep(200L); } catch(InterruptedException ie) {}

/* clear the cached server time (it is static so shared between library instances) */
Auth.clearCachedServerTime();

/* create Ably realtime instance with token and authCallback */
ClientOptions opts = createOptions();
opts.tokenDetails = tokenDetails;
opts.authCallback = new Auth.TokenCallback() {
/* implement callback, using Ably instance with key */
@Override
public Object getTokenRequest(Auth.TokenParams params) throws AblyException {
return ablyForToken.auth.requestToken(params, null);
}
};

/* disable token validity check */
opts.queryTime = false;

opts.logLevel = Log.VERBOSE;

/* temporarily override the disconnected retry interval */
ConnectionManager.states.get(ConnectionState.disconnected).timeout = 1000L;
int oldDisconnectTimeout = Defaults.TIMEOUT_DISCONNECT;
Defaults.TIMEOUT_DISCONNECT = 1000;

final AblyRealtime ably = new AblyRealtime(opts);

Helpers.ConnectionWaiter connectionWaiter = new Helpers.ConnectionWaiter(ably.connection);
boolean isConnected = connectionWaiter.waitFor(ConnectionState.connected, 1, 4000L);

ConnectionManager.states.get(ConnectionState.disconnected).timeout = Defaults.TIMEOUT_DISCONNECT;

if(isConnected) {
/* done */
ably.close();
} else {
fail("auth_expired_token_expire_renew: unable to connect; final state = " + ably.connection.state);
}
} catch (AblyException e) {
e.printStackTrace();
fail("auth_expired_token_expire_renew: Unexpected exception instantiating library");
}
}

/**
* Verify that with queryTime=false, when instancing with an already-expired token and authCallback,
* connection can succeed
*/
@Test
public void auth_expired_token_expire_after_connect_renew() {
try {
/* get a TokenDetails and allow to expire */
final String testKey = testVars.keys[0].keyStr;
ClientOptions optsForToken = createOptions(testKey);
optsForToken.queryTime = false;
final AblyRest ablyForToken = new AblyRest(optsForToken);
TokenDetails tokenDetails = ablyForToken.auth.requestToken(new Auth.TokenParams(){{ ttl = 2000L; }}, null);
assertNotNull("Expected token value", tokenDetails.token);

/* clear the cached server time (it is static so shared between library instances) */
Auth.clearCachedServerTime();

/* create Ably realtime with token and authCallback */
ClientOptions opts = createOptions();
opts.tokenDetails = tokenDetails;
opts.queryTime = false;
opts.authCallback = new Auth.TokenCallback() {
/* implement callback, using Ably instance with key */
@Override
public Object getTokenRequest(Auth.TokenParams params) throws AblyException {
return ablyForToken.auth.requestToken(params, null);
}
};

opts.logLevel = Log.VERBOSE;
final AblyRealtime ably = new AblyRealtime(opts);

Helpers.ConnectionWaiter connectionWaiter = new Helpers.ConnectionWaiter(ably.connection);
if(connectionWaiter.waitFor(ConnectionState.connected, 2, 4000L)) {
/* done */
ably.close();
} else {
fail("auth_expired_token_expire_renew: unable to connect; final state = " + ably.connection.state);
}
} catch (AblyException e) {
e.printStackTrace();
fail("auth_expired_token_expire_renew: Unexpected exception instantiating library");
}
}

}
57 changes: 57 additions & 0 deletions lib/src/test/java/io/ably/lib/test/rest/RestAuthTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import io.ably.lib.http.HttpConstants;
import io.ably.lib.http.HttpCore;
import io.ably.lib.test.common.Helpers;
import io.ably.lib.types.*;

import org.junit.AfterClass;
Expand Down Expand Up @@ -1854,6 +1855,62 @@ public void auth_local_token_expiry_check_nosync() {
}
}

/**
* Verify that if a local token validity check suppressed because queryTime == false
* this does not prevent token renewal by an auth callback when a request fails
* Spec: RSA4b1
*/
@Test
public void auth_local_token_expiry_check_nosync_retried() {
try {
/* get a TokenDetails and allow to expire */
final String testKey = testVars.keys[0].keyStr;
ClientOptions optsForToken = createOptions(testKey);
optsForToken.queryTime = false;
final AblyRest ablyForToken = new AblyRest(optsForToken);

TokenDetails tokenDetails = ablyForToken.auth.requestToken(new TokenParams(){{ ttl = 100L; }}, null);

/* clear the cached server time (it is static so shared between library instances) */
Auth.clearCachedServerTime();

/* create Ably instance with token details */
DebugOptions opts = new DebugOptions();
fillInOptions(opts);
opts.queryTime = false;
opts.tokenDetails = tokenDetails;
opts.authCallback = new TokenCallback() {
@Override
public Object getTokenRequest(TokenParams params) throws AblyException {
return ablyForToken.auth.createTokenRequest(params, null);
}
};

RawHttpTracker httpListener = new RawHttpTracker();
opts.httpListener = httpListener;
AblyRest ably = new AblyRest(opts);

/* wait for the token to expire */
try { Thread.sleep(200L); } catch(InterruptedException ie) {}

/* make a request that relies on authentication */
try {
ably.stats(new Param[] { new Param("by", "hour"), new Param("limit", "1") });
} catch (AblyException e) {
fail("auth_local_token_expiry_check_nosync: API call unexpectedly failed");
return;
}
assertEquals("Verify API request attempted", httpListener.size(), 3);
for(Helpers.RawHttpRequest x : httpListener.values()) {
System.out.println(x.url.toString());
}
assertEquals("Verify API request failed with token expiry error", httpListener.getFirstRequest().response.headers.get("x-ably-errorcode").get(0), "40142");
} catch (AblyException e) {
e.printStackTrace();
fail("auth_local_token_expiry_check_nosync: Unexpected exception instantiating library");
}
}

private static TokenServer tokenServer;
private static SessionHandlerNanoHTTPD nanoHTTPD;

Expand Down

0 comments on commit bfd6f6e

Please sign in to comment.