package com.samknows.tests; import android.os.Debug; import android.support.v4.BuildConfig; import android.util.Log; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.SocketTimeoutException; import java.util.List; import com.samknows.libcore.SKPorting; public final class DownloadTest extends HttpTest { private final byte[] buff = new byte[getDownloadBufferSize()]; private int readBytes = 0; private DownloadTest(List<Param> params) { super(_DOWNSTREAM, params); } public static DownloadTest sCreateDownloadTest(List<Param> params) { DownloadTest result = new DownloadTest(params); if (result != null) { if (result.isReady()) { return result; } else { SKPorting.sAssert(false); return null; } } else { SKPorting.sAssert(false); } return result; } private String[] formValuesArr() { String[] values = new String[1]; values[0] = String.format("%.2f", (getTransferBytesPerSecond() * 8d / 1000000)); return values; } private String getHeaderRequest() { String request = "GET /%s HTTP/1.1\r\nHost: %s \r\nACCEPT: */*\r\n\r\n"; return String.format(request, getFile(), getTarget()); } private int readResponse(InputStream is) { // Reads the http response and returns the http status code int ret = 0; try { BufferedReader reader = new BufferedReader(new InputStreamReader(is)); String line = reader.readLine(); if (line != null && line.length() != 0) { // Should be of the form: // HTTP/1.1 200 OK String[] words = line.split(" "); if (words.length >= 2) { ret = Integer.parseInt(words[1]); } else { SKPorting.sAssert(getClass(), false); } } while ((line = reader.readLine()) != null) { if (line.length() == 0) { break; } } } catch (IOException IOe) { SKPorting.sAssert(getClass(), false); setErrorIfEmpty("IOexception while reading http header: ", IOe); ret = 0; } catch (NumberFormatException nfe) { SKPorting.sAssert(getClass(), false); setErrorIfEmpty("Error in converting the http code: ", nfe); ret = 0; } catch (Exception e) { SKPorting.sAssert(getClass(), false); setErrorIfEmpty("Error in converting the http code: ", e); ret = 0; } return ret; } private Double getBytesPerSecond(boolean isWarmup) { if (isWarmup) { // If warmup mode is active return getWarmupBytesPerSecond(); } else { // If transmission mode is active return getTransferBytesPerSecond(); } } private boolean getTransmissionDone(boolean isWarmup, int readBytes) { if (getShouldCancel()) { if (Debug.isDebuggerConnected()) { Log.d("DEBUG", "Download - getTransmissionDone - cancel test!"); } return true; } if (isWarmup) { return isWarmupDone(readBytes); } else { return isTransferDone(readBytes); } } private boolean transmit(ISKHttpSocket socket, int threadIndex, boolean isWarmup) { // Callable<Integer> bytesPerSecond = null; /* Generic method returning the current average speed across all thread since thread started */ // Callable<Boolean> transmissionDone = null; /* Generic method returning the transmission state */ if (isWarmup) { /* If warmup mode is active */ sendHeaderRequest(socket); /* Send download request is the part of the warm up process */ if (getError().get()) { /* Error relates to sendHeader procedure */ SKPorting.sAssert(getClass(), false); return false; } } InputStream connIn = getInput(socket); if (connIn == null) { closeConnection(socket); SKPorting.sAssert(getClass(), false); //hahaSKLogger.e(TAG(this), "Error in setting up input stream, exiting... thread: " + this.getThreadIndex()); return false; } try { do { readBytes = connIn.read(buff, 0, buff.length); if (readBytes == -1) { // This can happen if we reach the end of the stream more quickly than expected... readBytes = 0; } SKPorting.sAssert(readBytes > 0); if (getBytesPerSecond(isWarmup) >= 0) { // -1 would mean no result found (as not enough time yet spent measuring) sSetLatestSpeedForExternalMonitorInterval(extMonitorUpdateInterval, "Download", getBytesPerSecond(isWarmup)); } } while (!getTransmissionDone(isWarmup, readBytes)); } catch (SocketTimeoutException e) { // This happens so often - that we just log it (but only when debugger in use) //if (OtherUtils.isDebuggable(SKApplication.getAppInstance())) if (BuildConfig.DEBUG) { Log.e("DownloadTest", e.getMessage()); } readBytes = BYTESREADERR; //SKLogger.sAssert(getClass(), false); return false; } catch (IOException io) { readBytes = BYTESREADERR; SKPorting.sAssert(getClass(), false); return false; } catch (Exception io) { readBytes = BYTESREADERR; SKPorting.sAssert(getClass(), false); return false; } return true; } private void sendHeaderRequest(ISKHttpSocket socket) { InputStream connIn = getInput(socket); OutputStream connOut = getOutput(socket); if (connOut == null || connIn == null) { closeConnection(socket); SKPorting.sAssert(getClass(), false); getError().set(true); //hahaSKLogger.e(TAG(this), "Error in setting up output stream, exiting... thread: " + getThreadIndex()); return; } try { PrintWriter writerOut = new PrintWriter(connOut, false); writerOut.print(getHeaderRequest()); writerOut.flush(); int httpResponse = readResponse(connIn); if (httpResponse != HTTPOK) { setErrorIfEmpty("Http response received: " + httpResponse); getError().set(true); } } catch (Exception io) { getError().set(true); SKPorting.sAssert(getClass(), false); } } @Override protected boolean transfer(ISKHttpSocket socket, int threadIndex) { boolean isWarmup = false; return transmit(socket, threadIndex, isWarmup); } @Override protected boolean warmup(ISKHttpSocket socket, int threadIndex) { boolean isWarmup = true; return transmit(socket, threadIndex, isWarmup); } @Override public String getStringID() { String ret = ""; if (getThreadsNum() == 1) { ret = DOWNSTREAMSINGLE; } else { ret = DOWNSTREAMMULTI; } return ret; } @Override public int getNetUsage() { return (int) (getTotalTransferBytes() + getTotalWarmUpBytes()); } }