Skip to content

Instantly share code, notes, and snippets.

@justintuchek
Last active October 20, 2016 13:58
Show Gist options
  • Save justintuchek/90ca2f622879978a1df122bb013c0413 to your computer and use it in GitHub Desktop.
Save justintuchek/90ca2f622879978a1df122bb013c0413 to your computer and use it in GitHub Desktop.
A behavioral transformer for observables! All inspiration from Retrofit's mock network behavior configurations.
public final class BehaviorTransformer {
private final Random random = new Random();
private long delayMs = 2000;
private int variancePercent = 40;
private int errorCode = 1337;
private int failurePercent = 3;
public <T> Observable.Transformer<T, T> modify() {
return new Observable.Transformer<T, T>() {
@Override
public Observable<T> call(Observable<T> source) {
return source.delay(calculateDelay(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS)
.concatMap(new Func1<T, Observable<T>>() {
@Override
public Observable<T> call(T t) {
if(calculateIsFailure()) {
return Observable.error(new EnumeratedException(errorCode, new RuntimeException()));
} else {
return Observable.just(t);
}
}
});
}
};
}
public void setDelayMs(long delayMs) {
this.delayMs = delayMs;
}
public void setVariancePercent(int variancePercent) {
this.variancePercent = variancePercent;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public void setFailurePercent(int failurePercent) {
this.failurePercent = failurePercent;
}
private boolean calculateIsFailure() {
int randomValue = random.nextInt(100);
return randomValue < failurePercent;
}
private long calculateDelay(TimeUnit unit) {
float delta = variancePercent / 100f; // e.g., 20 / 100f == 0.2f
float lowerBound = 1f - delta; // 0.2f --> 0.8f
float upperBound = 1f + delta; // 0.2f --> 1.2f
float bound = upperBound - lowerBound; // 1.2f - 0.8f == 0.4f
float delayPercent = lowerBound + (random.nextFloat() * bound); // 0.8 + (rnd * 0.4)
long callDelayMs = (long) (delayMs * delayPercent);
return MILLISECONDS.convert(callDelayMs, unit);
}
}
public class EnumeratedException extends Throwable {
private final int errorCode;
public EnumeratedException(int errorCode, Throwable cause) {
super(cause);
this.errorCode = errorCode;
}
public int getErrorCode() {
return errorCode;
}
}
public class MockUserService {
private final BehaviorTransformer behavior;
private Boolean isLoggedIn = Boolean.TRUE;
public MockUserService(BehaviorTransformer behavior) {
this.behavior = behavior;
}
public Observable<String> getUsername() {
return Observable.just("Justin Tuchek").compose(behavior.<String>modify());
}
public Observable<Boolean> logout() {
return Observable.just(Boolean.TRUE).compose(behavior.<Boolean>modify())
.doOnNext(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
isLoggedIn = Boolean.FALSE;
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment