/*
 * Copyright (C) 2011, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.bandwidthtest;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.TrafficStats;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Process;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;

import com.android.bandwidthtest.util.BandwidthTestUtil;
import com.android.bandwidthtest.util.ConnectionUtil;

import java.io.File;

/**
 * Test that downloads files from a test server and reports the bandwidth metrics collected.
 */
public class BandwidthTest extends InstrumentationTestCase {

    private static final String LOG_TAG = "BandwidthTest";
    private final static String PROF_LABEL = "PROF_";
    private final static String PROC_LABEL = "PROC_";
    private final static int INSTRUMENTATION_IN_PROGRESS = 2;

    private final static String BASE_DIR =
            Environment.getExternalStorageDirectory().getAbsolutePath();
    private final static String TMP_FILENAME = "tmp.dat";
    // Download 10.486 * 106 bytes (+ headers) from app engine test server.
    private final int FILE_SIZE = 10485613;
    private Context mContext;
    private ConnectionUtil mConnectionUtil;
    private TelephonyManager mTManager;
    private int mUid;
    private String mSsid;
    private String mTestServer;
    private String mDeviceId;
    private BandwidthTestRunner mRunner;


    @Override
    protected void setUp() throws Exception {
        super.setUp();
        mRunner = (BandwidthTestRunner) getInstrumentation();
        mSsid = mRunner.mSsid;
        mTestServer = mRunner.mTestServer;
        mContext = mRunner.getTargetContext();
        mConnectionUtil = new ConnectionUtil(mContext);
        mConnectionUtil.initialize();
        Log.v(LOG_TAG, "Initialized mConnectionUtil");
        mUid = Process.myUid();
        mTManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
        mDeviceId = mTManager.getDeviceId();
    }

    @Override
    protected void tearDown() throws Exception {
        mConnectionUtil.cleanUp();
        super.tearDown();
    }

    /**
     * Ensure that downloading on wifi reports reasonable stats.
     */
    @LargeTest
    public void testWifiDownload() throws Exception {
        mConnectionUtil.wifiTestInit();
        assertTrue("Could not connect to wifi!", setDeviceWifiAndAirplaneMode(mSsid));
        downloadFile();
    }

    /**
     * Ensure that downloading on mobile reports reasonable stats.
     */
    @LargeTest
    public void testMobileDownload() throws Exception {
        // As part of the setup we disconnected from wifi; make sure we are connected to mobile and
        // that we have data.
        assertTrue("Do not have mobile data!", hasMobileData());
        downloadFile();
    }

    /**
     * Helper method that downloads a file using http connection from a test server and reports the
     * data usage stats to instrumentation out.
     */
    protected void downloadFile() throws Exception {
        NetworkStats pre_test_stats = fetchDataFromProc(mUid);
        String ts = Long.toString(System.currentTimeMillis());

        String targetUrl = BandwidthTestUtil.buildDownloadUrl(
                mTestServer, FILE_SIZE, mDeviceId, ts);
        TrafficStats.startDataProfiling(mContext);
        File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
        assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile));
        NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
        Log.d(LOG_TAG, prof_stats.toString());

        NetworkStats post_test_stats = fetchDataFromProc(mUid);
        NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);

        // Output measurements to instrumentation out, so that it can be compared to that of
        // the server.
        Bundle results = new Bundle();
        results.putString("device_id", mDeviceId);
        results.putString("timestamp", ts);
        results.putInt("size", FILE_SIZE);
        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
        addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
        getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);

        // Clean up.
        assertTrue(cleanUpFile(tmpSaveFile));
    }

    /**
     * Ensure that uploading on wifi reports reasonable stats.
     */
    @LargeTest
    public void testWifiUpload() throws Exception {
        mConnectionUtil.wifiTestInit();
        assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
        uploadFile();
    }

    /**
     *  Ensure that uploading on wifi reports reasonable stats.
     */
    @LargeTest
    public void testMobileUpload() throws Exception {
        assertTrue(hasMobileData());
        uploadFile();
    }

    /**
     * Helper method that downloads a test file to upload. The stats reported to instrumentation out
     * only include upload stats.
     */
    protected void uploadFile() throws Exception {
        // Download a file from the server.
        String ts = Long.toString(System.currentTimeMillis());
        String targetUrl = BandwidthTestUtil.buildDownloadUrl(
                mTestServer, FILE_SIZE, mDeviceId, ts);
        File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
        assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile));

        ts = Long.toString(System.currentTimeMillis());
        NetworkStats pre_test_stats = fetchDataFromProc(mUid);
        TrafficStats.startDataProfiling(mContext);
        assertTrue(BandwidthTestUtil.postFileToServer(mTestServer, mDeviceId, ts, tmpSaveFile));
        NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
        Log.d(LOG_TAG, prof_stats.toString());
        NetworkStats post_test_stats = fetchDataFromProc(mUid);
        NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);

        // Output measurements to instrumentation out, so that it can be compared to that of
        // the server.
        Bundle results = new Bundle();
        results.putString("device_id", mDeviceId);
        results.putString("timestamp", ts);
        results.putInt("size", FILE_SIZE);
        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
        addStatsToResults(PROC_LABEL, proc_stats, results, mUid);
        getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);

        // Clean up.
        assertTrue(cleanUpFile(tmpSaveFile));
    }

    /**
     * We want to make sure that if we use wifi and the  Download Manager to download stuff,
     * accounting still goes to the app making the call and that the numbers still make sense.
     */
    @LargeTest
    public void testWifiDownloadWithDownloadManager() throws Exception {
        mConnectionUtil.wifiTestInit();
        assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
        downloadFileUsingDownloadManager();
    }

    /**
     * We want to make sure that if we use mobile data and the Download Manager to download stuff,
     * accounting still goes to the app making the call and that the numbers still make sense.
     */
    @LargeTest
    public void testMobileDownloadWithDownloadManager() throws Exception {
        assertTrue(hasMobileData());
        downloadFileUsingDownloadManager();
    }

    /**
     * Helper method that downloads a file from a test server using the download manager and reports
     * the stats to instrumentation out.
     */
    protected void downloadFileUsingDownloadManager() throws Exception {
        // If we are using the download manager, then the data that is written to /proc/uid_stat/
        // is accounted against download manager's uid, since it uses pre-ICS API.
        int downloadManagerUid = mConnectionUtil.downloadManagerUid();
        assertTrue(downloadManagerUid >= 0);
        NetworkStats pre_test_stats = fetchDataFromProc(downloadManagerUid);
        // start profiling
        TrafficStats.startDataProfiling(mContext);
        String ts = Long.toString(System.currentTimeMillis());
        String targetUrl = BandwidthTestUtil.buildDownloadUrl(
                mTestServer, FILE_SIZE, mDeviceId, ts);
        Log.v(LOG_TAG, "Download url: " + targetUrl);
        File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
        assertTrue(mConnectionUtil.startDownloadAndWait(targetUrl, 500000));
        NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
        NetworkStats post_test_stats = fetchDataFromProc(downloadManagerUid);
        NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
        Log.d(LOG_TAG, prof_stats.toString());
        // Output measurements to instrumentation out, so that it can be compared to that of
        // the server.
        Bundle results = new Bundle();
        results.putString("device_id", mDeviceId);
        results.putString("timestamp", ts);
        results.putInt("size", FILE_SIZE);
        addStatsToResults(PROF_LABEL, prof_stats, results, mUid);
        // remember to use download manager uid for proc stats
        addStatsToResults(PROC_LABEL, proc_stats, results, downloadManagerUid);
        getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);

        // Clean up.
        assertTrue(cleanUpFile(tmpSaveFile));
    }

    /**
     * Fetch network data from /proc/uid_stat/uid
     *
     * @return populated {@link NetworkStats}
     */
    public NetworkStats fetchDataFromProc(int uid) {
        String root_filepath = "/proc/uid_stat/" + uid + "/";
        File rcv_stat = new File (root_filepath + "tcp_rcv");
        int rx = BandwidthTestUtil.parseIntValueFromFile(rcv_stat);
        File snd_stat = new File (root_filepath + "tcp_snd");
        int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat);
        NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
        stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT,
                NetworkStats.TAG_NONE, rx, 0, tx, 0, 0);
        return stats;
    }

    /**
     * Turn on Airplane mode and connect to the wifi.
     *
     * @param ssid of the wifi to connect to
     * @return true if we successfully connected to a given network.
     */
    public boolean setDeviceWifiAndAirplaneMode(String ssid) {
        mConnectionUtil.setAirplaneMode(mContext, true);
        assertTrue(mConnectionUtil.connectToWifi(ssid));
        assertTrue(mConnectionUtil.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
                ConnectionUtil.LONG_TIMEOUT));
        assertTrue(mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
                State.CONNECTED, ConnectionUtil.LONG_TIMEOUT));
        return mConnectionUtil.hasData();
    }

    /**
     * Helper method to make sure we are connected to mobile data.
     *
     * @return true if we successfully connect to mobile data.
     */
    public boolean hasMobileData() {
        assertTrue(mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
                State.CONNECTED, ConnectionUtil.LONG_TIMEOUT));
        assertTrue("Not connected to mobile", mConnectionUtil.isConnectedToMobile());
        assertFalse("Still connected to wifi.", mConnectionUtil.isConnectedToWifi());
        return mConnectionUtil.hasData();
    }

    /**
     * Output the {@link NetworkStats} to Instrumentation out.
     *
     * @param label to attach to this given stats.
     * @param stats {@link NetworkStats} to add.
     * @param results {@link Bundle} to be added to.
     * @param uid for which to report the results.
     */
    public void addStatsToResults(String label, NetworkStats stats, Bundle results, int uid){
        if (results == null || results.isEmpty()) {
            Log.e(LOG_TAG, "Empty bundle provided.");
            return;
        }
        Entry totalStats = null;
        for (int i = 0; i < stats.size(); ++i) {
            Entry statsEntry = stats.getValues(i, null);
            // We are only interested in the all inclusive stats.
            if (statsEntry.tag != 0) {
                continue;
            }
            // skip stats for other uids
            if (statsEntry.uid != uid) {
                continue;
            }
            if (totalStats == null || statsEntry.set == NetworkStats.SET_ALL) {
                totalStats = statsEntry;
            } else {
                totalStats.rxBytes += statsEntry.rxBytes;
                totalStats.txBytes += statsEntry.txBytes;
            }
        }
        // Output merged stats to bundle.
        results.putInt(label + "uid", totalStats.uid);
        results.putLong(label + "tx", totalStats.txBytes);
        results.putLong(label + "rx", totalStats.rxBytes);
    }

    /**
     * Remove file if it exists.
     * @param file {@link File} to delete.
     * @return true if successfully deleted the file.
     */
    private boolean cleanUpFile(File file) {
        if (file.exists()) {
            return file.delete();
        }
        return true;
    }
}
