public void testDeleteDB() {
    Map<String, String> beforeMap = new HashMap<String, String>();
    beforeMap.put("added", "before");
    JSONObject before = new JSONObject(beforeMap);

    Map<String, String> afterMap = new HashMap<String, String>();
    afterMap.put("added", "after");
    JSONObject after = new JSONObject(afterMap);

    MPDbAdapter adapter = new MPDbAdapter(getContext(), "DeleteTestDB");
    adapter.addJSON(before, MPDbAdapter.Table.EVENTS);
    adapter.addJSON(before, MPDbAdapter.Table.PEOPLE);
    adapter.deleteDB();

    String[] emptyEventsData = adapter.generateDataString(MPDbAdapter.Table.EVENTS);
    assertEquals(emptyEventsData, null);
    String[] emptyPeopleData = adapter.generateDataString(MPDbAdapter.Table.PEOPLE);
    assertEquals(emptyPeopleData, null);

    adapter.addJSON(after, MPDbAdapter.Table.EVENTS);
    adapter.addJSON(after, MPDbAdapter.Table.PEOPLE);

    try {
      String[] someEventsData = adapter.generateDataString(MPDbAdapter.Table.EVENTS);
      JSONArray someEvents = new JSONArray(someEventsData[1]);
      assertEquals(someEvents.length(), 1);
      assertEquals(someEvents.getJSONObject(0).get("added"), "after");

      String[] somePeopleData = adapter.generateDataString(MPDbAdapter.Table.PEOPLE);
      JSONArray somePeople = new JSONArray(somePeopleData[1]);
      assertEquals(somePeople.length(), 1);
      assertEquals(somePeople.getJSONObject(0).get("added"), "after");
    } catch (JSONException e) {
      fail("Unexpected JSON or lack thereof in MPDbAdapter test");
    }
  }
  public void testMessageQueuing() {
    final BlockingQueue<String> messages = new LinkedBlockingQueue<String>();
    final SynchronizedReference<Boolean> okToDecide = new SynchronizedReference<Boolean>();
    okToDecide.set(false);

    final MPDbAdapter mockAdapter =
        new MPDbAdapter(getContext()) {
          @Override
          public int addJSON(JSONObject message, MPDbAdapter.Table table) {
            try {
              messages.put("TABLE " + table.getName());
              messages.put(message.toString());
            } catch (InterruptedException e) {
              throw new RuntimeException(e);
            }

            return super.addJSON(message, table);
          }
        };
    mockAdapter.cleanupEvents(Long.MAX_VALUE, MPDbAdapter.Table.EVENTS);
    mockAdapter.cleanupEvents(Long.MAX_VALUE, MPDbAdapter.Table.PEOPLE);

    final ServerMessage mockPoster =
        new ServerMessage() {
          @Override
          public byte[] performRequest(String endpointUrl, List<NameValuePair> nameValuePairs) {
            final boolean decideIsOk = okToDecide.get();
            if (null == nameValuePairs) {
              if (decideIsOk) {
                assertEquals(
                    "DECIDE_ENDPOINT?version=1&lib=android&token=Test+Message+Queuing&distinct_id=new+person",
                    endpointUrl);
              } else {
                fail(
                    "User is unidentified, we shouldn't be checking decide. (URL WAS "
                        + endpointUrl
                        + ")");
              }
              return TestUtils.bytes("{}");
            }

            assertEquals(nameValuePairs.get(0).getName(), "data");
            final String decoded = Base64Coder.decodeString(nameValuePairs.get(0).getValue());

            try {
              messages.put("SENT FLUSH " + endpointUrl);
              messages.put(decoded);
            } catch (InterruptedException e) {
              throw new RuntimeException(e);
            }

            return TestUtils.bytes("1\n");
          }
        };

    final MPConfig mockConfig =
        new MPConfig(new Bundle()) {
          @Override
          public int getFlushInterval() {
            return -1;
          }

          @Override
          public int getBulkUploadLimit() {
            return 40;
          }

          @Override
          public String getEventsEndpoint() {
            return "EVENTS_ENDPOINT";
          }

          @Override
          public String getPeopleEndpoint() {
            return "PEOPLE_ENDPOINT";
          }

          @Override
          public String getDecideEndpoint() {
            return "DECIDE_ENDPOINT";
          }
        };

    final AnalyticsMessages listener =
        new AnalyticsMessages(getContext()) {
          @Override
          protected MPDbAdapter makeDbAdapter(Context context) {
            return mockAdapter;
          }

          @Override
          protected MPConfig getConfig(Context context) {
            return mockConfig;
          }

          @Override
          protected ServerMessage getPoster() {
            return mockPoster;
          }
        };

    MixpanelAPI metrics =
        new TestUtils.CleanMixpanelAPI(getContext(), mMockPreferences, "Test Message Queuing") {
          @Override
          protected AnalyticsMessages getAnalyticsMessages() {
            return listener;
          }
        };

    // Test filling up the message queue
    for (int i = 0; i < mockConfig.getBulkUploadLimit() - 1; i++) {
      metrics.track("frequent event", null);
    }

    metrics.track("final event", null);
    String expectedJSONMessage = "<No message actually received>";

    try {
      for (int i = 0; i < mockConfig.getBulkUploadLimit() - 1; i++) {
        String messageTable = messages.poll(1, TimeUnit.SECONDS);
        assertEquals("TABLE " + MPDbAdapter.Table.EVENTS.getName(), messageTable);

        expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
        JSONObject message = new JSONObject(expectedJSONMessage);
        assertEquals("frequent event", message.getString("event"));
      }

      String messageTable = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("TABLE " + MPDbAdapter.Table.EVENTS.getName(), messageTable);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONObject message = new JSONObject(expectedJSONMessage);
      assertEquals("final event", message.getString("event"));

      String messageFlush = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("SENT FLUSH EVENTS_ENDPOINT", messageFlush);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONArray bigFlush = new JSONArray(expectedJSONMessage);
      assertEquals(mockConfig.getBulkUploadLimit(), bigFlush.length());

      metrics.track("next wave", null);
      metrics.flush();

      String nextWaveTable = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("TABLE " + MPDbAdapter.Table.EVENTS.getName(), nextWaveTable);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONObject nextWaveMessage = new JSONObject(expectedJSONMessage);
      assertEquals("next wave", nextWaveMessage.getString("event"));

      String manualFlush = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("SENT FLUSH EVENTS_ENDPOINT", manualFlush);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONArray nextWave = new JSONArray(expectedJSONMessage);
      assertEquals(1, nextWave.length());

      JSONObject nextWaveEvent = nextWave.getJSONObject(0);
      assertEquals("next wave", nextWaveEvent.getString("event"));

      okToDecide.set(true);
      metrics.getPeople().identify("new person");
      metrics.getPeople().set("prop", "yup");
      metrics.flush();

      String peopleTable = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("TABLE " + MPDbAdapter.Table.PEOPLE.getName(), peopleTable);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONObject peopleMessage = new JSONObject(expectedJSONMessage);

      assertEquals("new person", peopleMessage.getString("$distinct_id"));
      assertEquals("yup", peopleMessage.getJSONObject("$set").getString("prop"));

      String peopleFlush = messages.poll(1, TimeUnit.SECONDS);
      assertEquals("SENT FLUSH PEOPLE_ENDPOINT", peopleFlush);

      expectedJSONMessage = messages.poll(1, TimeUnit.SECONDS);
      JSONArray peopleSent = new JSONArray(expectedJSONMessage);
      assertEquals(1, peopleSent.length());

    } catch (InterruptedException e) {
      fail("Expected a log message about mixpanel communication but did not recieve it.");
    } catch (JSONException e) {
      fail(
          "Expected a JSON object message and got something silly instead: " + expectedJSONMessage);
    }
  }