Android testing. Mocking HttpUrlConnection(partially) - android

I have to create a test system that intercept all HTTP requests but should handle only few, after some researches I found this article that shows how to mock HttpUrlConnection but I have to adapt, I want to use this only for requests that is part of my test, the others should go through internet as usualy, my try was to return different HttpUrlConnection objects that depends on url and obviously didn't work.
public class MockURLStreamHandler extends URLStreamHandler implements URLStreamHandlerFactory
{
..............................
// *** URLStreamHandler
#Override
protected URLConnection openConnection(URL u) throws IOException {
mConnection = new MockHttpURLConnection(u);
if(u.toString().equals(myTestUrl))
{
return mConnection;
}
else
{
//this doesn't work
return new HttpUrlConnection(u){..}
}
}
...............................
}
Any ideas ? after what I should looking for?
Thanks in advance.

Take a look at MockWebServer
This library makes it easy to test that your app Does The Right Thing
when it makes HTTP and HTTPS calls. It lets you specify which
responses to return and then verify that requests were made as
expected.
Because it exercises your full HTTP stack, you can be confident that
you're testing everything. You can even copy & paste HTTP responses
from your real web server to create representative test cases. Or test
that your code survives in awkward-to-reproduce situations like 500
errors or slow-loading responses.

Related

Android - OkHttp - Tagging all network requests with TrafficStats

I'm trying to figure out specifically how much of my app's data use is being used by the requests I send with OkHttpClient, and I saw that I can use TrafficStats to tag a thread and then see it's network activity with the tag.
if I do something like
TrafficStats.setThreadStatsTag(1234);
okHttpClient.execute(request);
then it actually tags it okay(ish), but then when I use the async method (okHttpClient.enqueue(request)) it doesn't (which is kinda obvious though I hoped they'd have support for that).
So I tried a couple of things:
Setting a dispatcher for the client where it's a normal dispatcher which basically on every execute replaces the Runnable it receives with a new runnable that first tags the thread an then runs the original runnable - some traffic was tagged but a lot wasn't.
Setting a socket factory which basically tags every socket it produces - still some some traffic tagged but most of it wasn't.
Any ideas?
I think TrafficStats.setThreadStatsTag() is for thread, so maybe we can add an interceptor for okhttp client.
private static class TrafficStatInterceptor implements Interceptor {
int mTrafficTag;
TrafficStatInterceptor(int trafficTag) {
mTrafficTag = trafficTag;
}
#Override
public Response intercept(Chain chain) throws IOException {
if (mTrafficTag > 0) {
TrafficStatUtils.setThreadStatsTag(mTrafficTag);
} else {
Log.w(TAG, "invalid traffic tag " + mTrafficTag);
}
return chain.proceed(chain.request());
}
}
then just add this interceptor
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.addNetworkInterceptor(new TrafficStatInterceptor(trafficTag));
It’s difficult to do generally because with HTTP/2 sockets are shared across requests. With HTTP/1.1 they’re reused. Your best bet will be to write a network interceptor to tag the current thread. That’ll handle all HTTP/1.1 traffic and outgoing HTTP/2 traffic. There’s currently no API to access the thread that reads incoming HTTP/2 traffic.

Junit test on Meteor, Android-DDP library

I'm trying to carry out junit test for the Android-DDP library.
To initialize the meteor object, we need a reference to a android context which I'm able to achieve using Robolectric. But the web-sockets is probably talking to the server on a different thread because of which the callback methods are not called and the test methods are getting end.
I used netstat to check if the android client is trying to communicate or not. It shows various ping/pong messages. So, Yes it is trying to talk to the server.
I went through this tutorial as well,
Android AsyncTask testing with Android Test Framework. This one tells how to handle the network on UI thread. But nothing seems right.
The sample code, I have worked is:
#Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
#RunWith(RobolectricGradleTestRunner.class)
public class MainActivityTest {
private MainActivity activity;
private Meteor meteor;
private String globalUrl = "ws://10.0.3.222:3000/websocket";
#Before
public void setup() {
activity = Robolectric.setupActivity(MainActivity.class);
meteor = new Meteor(activity, globalUrl);
meteor.reconnect();
/*
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
}
#Test
public void validateMeteorIsConnected() {
assertTrue(meteor.isConnected());
}
}
Any help would be appreciable. Thanks in advance.
You defined two methods, setup() and validateMeteorIsConnected(), but where are they called?
First, your setup is not correct. After your call to new Meteor(...), you don't need the reconnect() call because the constructor does already establish the connection.
Moreover, you must set up a listener so that you know when the connection has been established or data comes in. This is done with mMeteor.setCallback(...); where the parameter is this or activity.
As you said, the work is done on a different thread and everything is asynchronous.
So you can't just call validateMeteorIsConnected() immediately after connecting.
You need some timer, as shown in the question that you linked to.

Unable to connect to Tridion Core Service from an Android client

I am developing an Android app for connecting to Tridion 2011 SP1 Core Service.
So far I have created Android WS Stubs from the core service wsdl using wsclient.
Imported those stubs, which allow access to all the core service methods.
I can now authenticate to Tridion via the Android application but as soon as I try to perform even the most basic of web service calls, such as getApiVersion(), I get the error:
ReflectionHelper*java.lang.NoSuchFieldException: GetApiVersionResult.
I was wondering has anyone else managed to create a java android app that communicates with the Core Service?
Interestingly enough, if I run the code as a java application, using wsimport stubs everything works a treat.
Any help appreciated. For reference here is a code snippet:
To connect to Tridion:
class TridionConnect extends AsyncTask<String, Integer, String> {
// Called to initiate the background activity
#Override
protected String doInBackground(String... statuses) {
try {
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("username", "password".toCharArray());
}
});
url = new URL("http://tridion-server/webservices/CoreService2011.svc?wsdl");
System.out.println(String.format("Get Service"));
service = new CoreService2011();
System.out.println(String.format("Get Client"));
client = service.getBasicHttp();
return "Authenticated To Tridion";
} catch (Exception e) {
Log.e("Authentication failure", e.toString());
e.printStackTrace();
return "Failed to authenticate";
}
}
// Called when there's a status to be updated
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Not used in this case
}
// Called once the background activity has completed
#Override
protected void onPostExecute(String result) { //
Toast.makeText(FullscreenActivity.this, result, Toast.LENGTH_LONG).show();
area.setText("Authenticated to Tridion OK");
}
}
To get the ApiVersion
client.getApiVersion();
UserData currentUser = client.getCurrentUser();
System.out.println(String.format("'%s' %s", currentUser.getTitle(), currentUser.getId()));
Frank,
It is not possible for a couple of reasons.
If you use wsimport to create the coreservice proxy it will use the javax library, which exists in the JRE. However Dalvik implements only a subset of the javax library which means this approach is impossible in the Android environment.
I then looked at Ksoap2 tools for creating the proxy. This seemed to work OK, in as much as it did create a proxy, however it did not match the coreservice so I was unable to authenticate. I didn't get any further with this approach beyond examining the JRE proxy v Ksoap2 proxy. They were quite different.
At this point I took a step back, had a cup of tea and re-engineered the approach.
I created a c# REST service to sit between the android app and the core service.
This approach seemed a bit complex, but it offers lots of advantages. Lots of the spade work can be done in the REST service, which will be much quicker than similar code on a tablet or phone.
Secondly the REST service sits on the same server as the CMS/CoreService so the comms is quicker and you can make the REST requests from the android app much lighter.
I have got the application to the point where you can authenticate to Tridion, select a publication, and components that is then rendered in a dynamic layout ready for update/save/publish.
The one big downside of this approach is that the REST service 'should' be stateless so superficially you have to authenticate to the coreservice for every request. Of course I don't do that, but you have to come up with some alternative approach Oauth, shared secret etc.
In initial tests this approach has seemed to be fairly slick on an android device.

Android usb host: asynchronous interrupt transfer

I'm trying to connect a USB-Device ( build by myself ) to communicate with my development board ( ODROID-X )
Unfortunately, the examples are very little, as far as the asynchronous communication. I'd some problems with the interrupt driven data exchange - how to build the connection by using the asynchronous interrupt mode?
In one direction, the transmission was possible ... but in both it doesn't work. Is there an example like this:
send a ByteBuffer with endpoint_OUT
get a message from device on endpoint_IN
both in interrupt mode.
Thanks a lot for your support.
Hardy
Perhaps I am misunderstanding the question here.
The sample missile lanucher app that is part of the API package from level 12 onwards uses the queue() and requestWait() methods to handle interrupt type endpoints.
Requests are either In or Out and depend on the direction of the EndPoint.
The code for a pretty noddy request->reply looks something like this. You would want to structure real code differently but this gives you the gist of what needs to happen (I hope)
public void run() {
int bufferMaxLength=mEndpointOut.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferMaxLength);
UsbRequest request = new UsbRequest(); // create an URB
request.initialize(mConnection, mEndpointOut);
buffer.put(/* your payload here */;
// queue the outbound request
boolean retval = request.queue(buffer, 1);
if (mConnection.requestWait() == request) {
// wait for confirmation (request was sent)
UsbRequest inRequest = new UsbRequest();
// URB for the incoming data
inRequest.initialize(mConnection, mEndpointIn);
// the direction is dictated by this initialisation to the incoming endpoint.
if(inRequest.queue(buffer, bufferMaxLength) == true){
mConnection.requestWait();
// wait for this request to be completed
// at this point buffer contains the data received
}
}
}
If you are actually looking for a way to run this IO in an asynchronous manner without binding a thread to it, then I think you need to consider using the DeviceConnection.getFilehandle() method to return a standard file handle which in theory you can then use as if it were any other file type resource. I would note however that I have not tried this.
If neither of these addresses the issue please revise the question to clarify what you are struggling to find examples of.
I hope this helps.

How to auto-accept Wi-Fi Direct connection requests in Android

I have 2 Android devices using WiFi Direct. On one device I can get information about the other device using the WifiP2pManager class, and request a connection to the other device. However when I request a connection, the other device pops up a little window and asks the user if they want to accept the connection request.
Is it possible to auto-accept these connection requests? I.E to be able to connect to the other device without user confirmation?
It can be easily done with the help of Xposed framework. You just need to replace the single method inside one of android java classes (see the link from snihalani's answer). But of course to use Xposed your device must be rooted. The main idea can be expressed in the following code (using Xposed)
#Override
public void handleLoadPackage(LoadPackageParam lpparam) {
try {
Class<?> wifiP2pService = Class.forName("android.net.wifi.p2p.WifiP2pService", false, lpparam.classLoader);
for (Class<?> c : wifiP2pService.getDeclaredClasses()) {
//XposedBridge.log("inner class " + c.getSimpleName());
if ("P2pStateMachine".equals(c.getSimpleName())) {
XposedBridge.log("Class " + c.getName() + " found");
Method notifyInvitationReceived = c.getDeclaredMethod("notifyInvitationReceived");
final Method sendMessage = c.getMethod("sendMessage", int.class);
XposedBridge.hookMethod(notifyInvitationReceived, new XC_MethodReplacement() {
#Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
final int PEER_CONNECTION_USER_ACCEPT = 0x00023000 + 2;
sendMessage.invoke(param.thisObject, PEER_CONNECTION_USER_ACCEPT);
return null;
}
});
break;
}
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
I tested it on SGS4 stock 4.2.2 ROM and it worked.
I guess the same could be done with the help of Substrate for android.
From my current understanding of the API, You cannot really accept connections automatically without user's intervention. You can initiate a connection, that doesn't require user intervention. If both of your devices are mobile devices, you will have to accept connection request on one end.
I have put this as a feature request in android project hosting.
You can monitor their response here: https://code.google.com/p/android/issues/detail?id=30880
Based on the comments, do you really need to connect to the devices if you just want to track and log the vehicles around you ?
I don't know the scope of the project, but you could simply use the WifiP2pDeviceList that you get when you request the peers in the WifiP2pManager. You could get the list of the devices (~= vehicles) around you and could log this.
Connection is useful if you want to send more detailed information I guess.
If you can modify the framework, you can ignore the accept window and direct send the "PEER_CONNECTION_USER_ACCEPT".
Base on Android 5.0, "frameworks/opt/net/wifi/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java".
You must find the "notifyInvitationReceived", and modify to ...
private void notifyInvitationReceived() {
/*Direct sends the accept message.*/
sendMessage(PEER_CONNECTION_USER_ACCEPT);
/*
... old code
*/
}

Categories

Resources