What is the product flavor for androidTest - android

The first time, I started to write test cases for Android app, I have searched a lot but could not find the full-phased proper way
Like I am testing Instrumentation Test cases in "androidTest" folder
Below is code for LoginTestCases
#Test
public void loginUserAccount() {
NetworkHelper.MOCK_URL =
String userName = "abacus#hotmail.com";
String password = "abacus#112";
boolean keepMeLoggedInChecked = false;
boolean touchIdEnabled = false;
boolean optIn = false;
mAuthenticationService.logIn(userName, password, keepMeLoggedInChecked, touchIdEnabled, optIn).done(new DoneCallback<LogInResponse>() {
#Override
public void onDone(final LogInResponse result) {
Assert.assertEquals(true,true);
}
}).fail(new FailCallback<Throwable>() {
#Override
public void onFail(Throwable result) {
Assert.assertEquals(true,false);
}
});
}
For testing I need to change MOCK_URL value to "/" so I can implement MockWebServer and choose what response I want, I have used static variable MOCK_URL like below code
public class NetworkHelper {
private final OkHttpClient mOkHttpClient;
public static HttpUrl MOCK_URL = null;
public NetworkHelper(OkHttpClient httpClient) {
mOkHttpClient = httpClient;
}
public Retrofit initialize(String baseUrl) {
if(MOCK_URL!=null) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(MOCK_URL)
.addConverterFactory(JacksonConverterFactory.create())
.client(mOkHttpClient)
.build();
return retrofit;
I know that static is not the proper way if anybody knows another way then please give me the solution.

Related

How to (RxJava) properly set conditions on which handler will process data, emitted from Observable?

So, my task is to push my device's Location info, when it changes, to the remote server Json API service. If remote server is unavailable, my DatabaseManager must save them to a local database.
Here is my Retrofit API:
public interface GpsService {
#POST("/v1/savelocationbatch")
SaveResponse saveLocationBatch(#Body LocationBatch locationBatch);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(myBaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
GpsService service = retrofit.create(GpsService.class);
And a POJO class:
public class LocationBatch{
#SerializedName("LocationPointList")
ArrayList<LocationPoint> locationPointList;
#SerializedName("ClientId")
String clientId;
#SerializedName("ClientSecret")
String clientSecret;
//setter & getter
}
My LocationPoint model:
#Table(name="LocationPoints", id = "_id")
public class LocationPoint extends Model {
#SerializedName("Latitude")
#Column(name="latitude")
public Double latitude;
#SerializedName("Longitude")
#Column(name="longitude")
public Double longitude;
#SerializedName("Altitude")
#Column(name="altitude")
public Double altitude;
//... setters, getters etc
}
All of my last locations are stored in a CurrentLocationHolder singleton (for batch sending/saving to DB/emitting from Observable). It's setLocation() method updates currentLocation variable, then puts it to the locationBuffer, than checks the buffer's size, than if buffer's size exceeds my MAX_BUFFER_SIZE variable, it fires locationBufferChanged.onNext(with a copy of a locationBuffer as argument), then it clears locationBuffer...
public class CurrentLocationHolder {
private List<LocationPoint> locationBuffer =
Collections.synchronizedList(new ArrayList<>());
private LocationPoint currentLocation;
private final PublishSubject<List<LocationPoint>> locationBufferFull =
PublishSubject.create();
public Observable<List<LocationPoint>>
observeLocationBufferFull(boolean emitCurrentValue) {
return emitCurrentValue ?
locationBufferFull.startWith(locationBuffer) :
locationBufferFull;
}
public void setLocation(LocationPoint point) {
this.currentLocation = point;
locationBuffer.add(point);
if (locationBuffer.size() >= MAX_BUFFER_SIZE) {
locationBufferChanged.onNext(new ArrayList<>(this.locationBuffer));
}
locationBuffer.clear();
}
}
And here is my DatabaseManager:
public class DatabaseManager {
private Subscription locationBufferSubscription;
private static DatabaseManager instance;
public static void InitInstance() {
if (instance == null)
instance = new DatabaseManager();
}
}
public void saveToDb(ArrayList<LocationPoint> locArray){
ActiveAndroid.beginTransaction();
try {
for (int i = 0; i < locArray.size(); i++) {
locArray.get(i).save();
}
ActiveAndroid.setTransactionSuccessful();
}
finally {
ActiveAndroid.endTransaction();
}
}
}
My application's main goal:
To write all of the listened LocationPoints to the HTTP server through Retrofit. If a remote server will be suddenly down for some reason (or internet connection would lost), my app should seamlessly write new locationPoints to a local database. When the server (or internet) will be up, some mechanism should provide saved local data to Retrofit's call.
So, my questions are:
How to create an Rx-Observable object, which will emit List normally to a Retrofit service, but when server (or internet) goes down, it should provide unsaved LocationPoints to DatabaseManager.saveToDb() method?
How to catch internet connection or server "up" state? Is it a good idea to create some Observable, which will ping my remote server, and as result should emit some boolean value to it's subscribers? What is the best way to implement this behavior?
Is there a simple way to enqueue Retrofit calls with a locally saved data (from local DB), when internet connection (server) will become "up"?
How not to loose any of my LocationPoints on the server-side? (finally my client app must send all of them!
Am I doing something wrong? I am a newbie to Android, Java and
particularly to RxJava...
Interesting task! First of all: you don't need to create DB for storing such tiny info. Android has good place for storing any Serializable data.
So for saving locally data crate Model like:
public class MyLocation implements Serializable {
#Nonnull
private final String id;
private final Location location;
private final boolean isSynced;
// constructor...
// getters...
}
Singleton class:
public class UserPreferences {
private static final String LOCATIONS = "locations";
#Nonnull
private final SharedPreferences preferences;
#Nonnull
private final Gson gson;
private final PublishSubject<Object> locationRefresh = PublishSubject.create();
public void addLocation(MyLocation location) {
final String json = preferences.getString(LOCATIONS, null);
final Type type = new TypeToken<List<MyLocation>>() {
}.getType();
final List<MyLocation> list;
if (!Strings.isNullOrEmpty(json)) {
list = gson.fromJson(json, type);
} else {
list = new ArrayList<MyLocation>();
}
list.add(lication);
final String newJson = gson.toJson(set);
preferences.edit().putString(LOCATIONS, newJson).commit();
locationRefresh.onNext(null);
}
private List<String> getLocations() {
final String json = preferences.getString(LOCATIONS, null);
final Type type = new TypeToken<List<MyLocation>>() {
}.getType();
final List<MyLocation> list = new ArrayList<MyLocation>();
if (!Strings.isNullOrEmpty(json)) {
list.addAll(gson.<List<MyLocation>>fromJson(json, type));
}
return list;
}
#Nonnull
public Observable<List<MyLocation>> getLocationsObservable() {
return Observable
.defer(new Func0<Observable<List<MyLocation>>>() {
#Override
public Observable<List<MyLocation>> call() {
return Observable.just(getLocations())
.filter(Functions1.isNotNull());
}
})
.compose(MoreOperators.<List<MyLocation>>refresh(locationRefresh));
}
// also You need to create getLocationsObservable() and getLocations() methods but only for not synced Locations.
}
Change:
public interface GpsService {
#POST("/v1/savelocationbatch")
Observable<SaveResponse> saveLocationBatch(#Body LocationBatch locationBatch);
}
Now the most interesting...make it all works.
There is extention for RxJava. It has a lot of "cool tools" (btw, MoreOperators in UserPref class from there), also it has something for handling retrofit errors.
So let assume that location saving suppose to happens, when Observable saveLocationObservable emit something. In that case your code looks like:
final Observable<ResponseOrError<SaveResponse>> responseOrErrorObservable = saveLocationObservable
.flatMap(new Func1<MyLocation, Observable<ResponseOrError<SaveResponse>>>() {
#Override
public Observable<ResponseOrError<SaveResponse>> call(MyLocation myLocation) {
final LocationBatch locationBatch = LocationBatch.fromMyLocation(myLocation); // some method to convert local location to requesr one
return saveLocationBatch(locationBatch)
.observeOn(uiScheduler)
.subscribeOn(networkScheduler)
.compose(ResponseOrError.<SaveResponse>toResponseOrErrorObservable());
}
})
.replay(1)
.refCount();
final Observable<Throwable> error = responseOrErrorObservable
.compose(ResponseOrError.<SaveResponse>onlyError())
.withLatestFrom(saveLocationObservable, Functions2.<MyLocation>secondParam())
.subscribe(new Action1<MyLocation>() {
#Override
public void call(MyLocation myLocation) {
// save location to UserPref with flag isSynced=flase
}
});
final Observable<UserInfoResponse> success = responseOrErrorObservable
.compose(ResponseOrError.<SaveResponse>onlySuccess())
.subscribe(new Action1<SaveResponse>() {
#Override
public void call(SaveResponse response) {
// save location to UserPref with flag isSynced=true
}
});

Retrofit2 Tail Recursion Using RxJava / RxAndroid

I am really trying to get a hang of using Retrofit with RxJava / RxAndroid. I've done this using normal Retrofit2 Callback method in a previous app without the use of Reactive Programming and it worked fine. So, here is it. I need to Tail Recall a function meant to fetch all Local Government from the server. The API uses pagination (I have to construct the URL with ?page=1, perPage=2). I've to do this till I've the whole data. So, below is my Rx code
public static Observable<LgaListResponse> getPages(Context acontext) {
String token = PrefUtils.getToken(acontext);
BehaviorSubject<Integer> pageControl = BehaviorSubject.<Integer>create(1);
Observable<LgaListResponse> ret2 = pageControl.asObservable().concatMap(integer -> {
if (integer > 0) {
Log.e(TAG, "Integer: " + integer);
return ServiceGenerator.createService(ApiService.class, token)
.getLgas(String.valueOf(integer), String.valueOf(21))
.doOnNext(lgaListResponse -> {
if (lgaListResponse.getMeta().getPage() != lgaListResponse.getMeta().getPageCount()) {
pageControl.onNext(initialPage + 1);
} else {
pageControl.onNext(-1);
}
});
} else {
return Observable.<LgaListResponse>empty().doOnCompleted(pageControl::onCompleted);
}
});
return Observable.defer(() -> ret2);
}
And my ServiceGenerator Class
public class ServiceGenerator {
private static final String TAG = "ServiceGen";
private static OkHttpClient.Builder builder = new OkHttpClient.Builder();
private static Retrofit.Builder retrofitBuilder =
new Retrofit.Builder()
.baseUrl(BuildConfig.HOST)
.addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
.addConverterFactory(GsonConverterFactory.create(CustomGsonParser.returnCustomParser()));
public static <S> S createService(Class<S> serviceClass, String token) {
builder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY));
/*builder.addNetworkInterceptor(new StethoInterceptor());*/
builder.connectTimeout(30000, TimeUnit.SECONDS);
builder.readTimeout(30000, TimeUnit.SECONDS);
if (token != null) {
Interceptor interceptor = chain -> {
Request newRequest = chain.request().newBuilder()
.addHeader("x-mobile", "true")
.addHeader("Authorization", "Bearer " + token).build();
return chain.proceed(newRequest);
};
builder.addInterceptor(interceptor);
}
OkHttpClient client = builder.build();
Retrofit retrofit = retrofitBuilder.client(client).build();
Log.e(TAG, retrofit.baseUrl().toString());
return retrofit.create(serviceClass);
}
public static Retrofit retrofit() {
OkHttpClient client = builder.build();
return retrofitBuilder.client(client).build();
}
public static class CustomGsonParser {
public static Gson returnCustomParser(){
return new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class);
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
})
.create();
}
}
}
So, I noticed on the first call, I get a response, but on the second one, the 440Error is thrown. The URL is formed, but the request throws a 400Error. I don't know why it's throwing a 400 everything is working fine if I use POSTMAN to test. And, I tested with my old code too. The Log is too long, so I put it in pastebin LOGS any help thanks. I've written most of this app with RxAndroid / RxJava. Thanks
I suggest you simplify things (and remove recursion). First build up your pages using something like
public static Observable<LgaListResponse> getPages(Context acontext, int initialPage, int perPage) {
String token = PrefUtils.getToken(acontext);
BehaviorSubject<Integer> pagecontrol = BehaviorSubject.<Integer>create(initialPage);
Observable<LgaListResponse> ret2 = pagecontrol.asObservable().concatMap(
new Func1<Integer,Observable<LgaListResponse>>() {
Observable<LgaListResponse> call(Integer pageNumber) {
if (pageNumber > 0) {
return ServiceGenerator.createService(ApiService.class, token)
.getLgas(String.valueOf(aKey), String.valueOf(perPage))
.doOnNext(
new Action1<LgaListResponse>() {
void call(LgaListResponse page) {
if (page.getMeta().getPage() != page.getMeta().getPageCount()) {
pagecontrol.onNext(page.getMeta().getNextPage());
} else {
pagecontrol.onNext(-1);
}
}
}
);
}
else {
return Observable.<LgaListResponse>empty().doOnCompleted(()->pagecontrol.onCompleted());
}
}
}
);
return Observable.defer(
new Func0<Observable<LgaListResponse>() {
Observable<LgaListResponse> call() {
return ret2;
}
}
);
}
then subscribe to the resulting observable. It looks horrible because I've avoided using lambdas but it should work.

Add header to Google Cloud Endpoint in Android

I have the following approach for getting instance of my endpoint. I want to add a header to it. How do I do that? Please modify my code following, to include the header bit. Thanks.
public class RemoteServiceEndpointReference {
private static final boolean USING_LOCAL_SERVER = false;
private static final String LOCAL_SERVER_PATH = “…”;
private static RemoteService service;
public static RemoteService getRemoteServiceEndpoint() {
if (null != service) {
return service;
}
RemoteService.Builder builder = new RemoteService.Builder(
AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(),
null
);
forLocalServer(builder);
service = builder.build();
return service;
}
private static void forLocalServer(AbstractGoogleJsonClient.Builder builder) {
if (USING_LOCAL_SERVER) {
builder.setRootUrl(LOCAL_SERVER_PATH)
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
#Override
public void initialize(AbstractGoogleClientRequest<?> request) throws IOException {
request.setDisableGZipContent(true);
}
});
}
}
}
You should be able to do something like this:
#Override
public void initialize(AbstractGoogleClientRequest<?> request) throws IOException {
HttpHeaders yourHeaders = new HttpHeaders();
header.set("yourHeader", value);
// ...
request.setDisableGZipContent(true);
request.setRequestHeaders(yourHeaders); // setting the headers
}

How to return different code and error with MockRestAdapter

I use MockRestAdapter to return mock data in my tests, but I'd also like to test errors (401, 503, UnknownHostException, etc)
For SocketTimeoutException, there's an API, but how about different response code?
I've tried MockWebServer but no matter what I enqueue, I always get a 200 with the mock data from the adapter.
update: I want to run my tests like this:
#RunWith(AndroidJUnit4.class)
#LargeTest
public class LoginActivityTest {
#Test public void goodCredentials() {
activity.login("username", "password");
assert(...); // Got back 200 and user object (from mock)
}
#Test public void wrongCredentials() {
activity.login("username", "wrong_password");
something.setResponse(401, "{error: wrong password}");
assert(...);
}
#Test public void someError() {
activity.login("username", "password");
something.setResponse(503, "{error: server error}");
assert(...);
}
}
update 2:
Found something, rather ugly, but does what I need:
MockApi implements ServiceApi {
public static Throwable throwable;
#Override login(Callback<User> callback) {
if (throwable != null) {
sendError(callback)
} else {
callback.success(new User("{name:test}"));
}
}
private void sendError(Callback callback) {
callback.failure(RetrofitError.unexpectedError("", throwable));
}
}
public class LoginActivityTest {
#Test public void someError() {
MockApi.throwable = new InterruptedIOException()
activity.login("username", "password");
// Assert having a time out message
}
#Test public void someError() {
MockApi.throwable = new UnknownHostException()
activity.login("username", "password");
// Assert having a no internet message
}
}
Still working on it, so any feedback will help :)
It's fairly easy to do. You just need to implement Client and pass it when you build your mock RestAdapter.
Creating client with appropriate response:
Client client = new Client() {
#Override public Response execute(Request request) throws IOException {
final String reason = "Some reason.";
final List<Header> headers = new ArrayList<>();
final TypedString body = new TypedString("");//could be json or what ever you want
final int status = 401;
return new Response(request.getUrl(), status, reason, headers, body);
}
};
And passing it to your RestAdapter.Builder:
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.com")
.setClient(client)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
restAdapter.create(API.class);

RETROFIT & AUTH COOKIE

I need to know how to add an authorization cookie header in retrofit. I have seen advice like using request intercepter etc. Below is what I am trying, but is this correct? First of all I already needed a RequestAdatper to get the session id the first time around. This can only be set by the builder of the request adapter. But I needed to make a request just to get the session id in the first place. Do I need two rest adapters one to get the sessionId and another one after I have obtained it. What I really need is a method on adapter to set the cookie after I get it but it does not appear to be such a method. This is getting awkward. How do I set authorization cookie in retrofit? I don't see this in FAQ or tutorials.
RequestInterceptor requestInterceptor = new RequestInterceptor()
{
#Override
public void intercept(RequestFacade request) {
request.addHeader("Set-Cookie", "sessionId="+sessionIdentifier);
}
};
RestAdapter.Builder().setServer(serverURL)..setRequestIntercepter(requestIntercepter).build();
// but I don't have sessionId when this is first issued ???
Keep a reference to the interceptor and treat it as a singleton like you would be RestAdapter itself.
public class ApiHeaders implements RequestInterceptor {
private String sessionId;
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public void clearSessionId() {
sessionId = null;
}
#Override public void intercept(RequestFacade request) {
if (sessionId != null) {
request.setHeader(...);
}
}
}
Now, simply call setSessionId after your authentication call. All subsequent requests will include the header.
You can get the cookies like this
public class MyCookieManager extends CookieManager {
#Override
public void put(URI uri, Map<String, List<String>> stringListMap) throws IOException {
super.put(uri, stringListMap);
if (stringListMap != null && stringListMap.get("Set-Cookie") != null)
for (String string : stringListMap.get("Set-Cookie")) {
if (string.contains("JSESSIONID")) {
Preference.getInstance().setSessionId(string);
}
}
}
}
Use this to set the CookieHandler
MyCookieManager myCookieManager = new MyCookieManager();
CookieHandler.setDefault(myCookieManager);
and then use it like this in your request Interceptor
String sessionId = preference.getSessionId();
if (sessionId != null)
requestFacade.addHeader(Cookie, sessionId);
Step 1. Parse Response headers.
Call this method inside your Callback in overriden success method.
/**
* Method extracts cookie string from headers
* #param response with headers
* #return cookie string if present or null
*/
private String getCookieString(Response response) {
for (Header header : response.getHeaders()) {
if (null!= header.getName() && header.getName().equals("Set-Cookie")) {
return header.getValue();
}
}
return null;
}
Step 2. Write some static class or singleton to keep cookies and your RequestInterceptor instance. Inside RequestInterceptor override intercept method to add your cookies to Header.
public class RestAdapter {
private static String cookies;
public static String getCookies() {
return cookies;
}
public static void setCookies(String cookies) {
RestAdapter.cookies = cookies;
}
/**
* Injects cookies to every request
*/
private static final RequestInterceptor COOKIES_REQUEST_INTERCEPTOR = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
if (null != cookies && cookies.length() > 0) {
request.addHeader("Cookie", cookies);
}
}
};
public static final RestInterface getService() {
return new RestAdapter.Builder()
.setEndpoint(Config.ENDPOINT)
.setRequestInterceptor(COOKIES_REQUEST_INTERCEPTOR)
.setConverter(new JacksonConverter())
.setLogLevel(RestAdapter.LogLevel.NONE)
.build()
.create(RestInterface.class);
}
}
According to #sbtgE's answer, but with some corrections. CookieHandler.getDefault() may be null, so I use CookieManager.
app's build.gradle:
dependencies {
...
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.1'
}
Setting up Retrofit:
service = new Retrofit.Builder()
.baseUrl(/* your base URL */)
.addConverterFactory(/* your favourite converter */)
.client(
new OkHttpClient.Builder()
// this line is the important one:
.cookieJar(new JavaNetCookieJar(new CookieManager()))
.build())
.build()
.create(YourInterface.class);
Simple solution using lib. compile com.squareup.okhttp3:okhttp-urlconnection:3.2.0.
JavaNetCookieJar jncj = new JavaNetCookieJar(CookieHandler.getDefault());
OkHttpClient.Builder().cookieJar(jncj).build();

Categories

Resources