public void testLooperDestruction() { final BlockingQueue<JSONObject> messages = new LinkedBlockingQueue<JSONObject>(); // If something terrible happens in the worker thread, we // should make sure final MPDbAdapter explodingDb = new MPDbAdapter(getContext()) { @Override public int addJSON(JSONObject message, MPDbAdapter.Table table) { messages.add(message); throw new RuntimeException("BANG!"); } }; final AnalyticsMessages explodingMessages = new AnalyticsMessages(getContext()) { // This will throw inside of our worker thread. @Override public MPDbAdapter makeDbAdapter(Context context) { return explodingDb; } }; MixpanelAPI mixpanel = new TestUtils.CleanMixpanelAPI( getContext(), mMockPreferences, "TEST TOKEN testLooperDisaster") { @Override protected AnalyticsMessages getAnalyticsMessages() { return explodingMessages; } }; try { mixpanel.clearPreferences(); assertFalse(explodingMessages.isDead()); mixpanel.track("event1", null); JSONObject found = messages.poll(1, TimeUnit.SECONDS); assertNotNull(found); Thread.sleep(1000); assertTrue(explodingMessages.isDead()); mixpanel.track("event2", null); JSONObject shouldntFind = messages.poll(1, TimeUnit.SECONDS); assertNull(shouldntFind); assertTrue(explodingMessages.isDead()); } catch (InterruptedException e) { fail("Unexpected interruption"); } }
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mixpanelAPI.track(ROUTING_START, null); createGroup(); bus.register(this); }
private void parseFBData(JSONObject jsonObject, AccessToken token) { try { String id = jsonObject.getString("id"); String email = jsonObject.getString("email"); // String name = jsonObject.getString("name"); String gender = jsonObject.getString("gender"); String first_name = jsonObject.getString("first_name"); String last_name = jsonObject.getString("last_name"); Intent mIntent = new Intent(getActivity(), LoginUserDetails.class); mIntent.putExtra("login_method", "facebook"); mIntent.putExtra("email", email); mIntent.putExtra("first_name", first_name); mIntent.putExtra("last_name", last_name); // mIntent.putExtra("id", id); mIntent.putExtra("id", token.getUserId()); // mIntent.putExtra("name",name); if (jsonObject.has("birthday")) { String birthday = jsonObject.getString("birthday"); mIntent.putExtra("birthday", birthday); } mixpanel.track("Login - Facebook"); mIntent.putExtra("gender", gender); startActivity(mIntent); } catch (JSONException e) { e.printStackTrace(); } }
@Override public void onConnected(Bundle bundle) { if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null) { Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient); String personName = currentPerson.getDisplayName(); String personPhoto = currentPerson.getImage().getUrl(); String firstName = currentPerson.getName().getGivenName(); String lastName = currentPerson.getName().getFamilyName(); String personGooglePlusProfile = currentPerson.getUrl(); String date = currentPerson.getBirthday(); if (date == null) { date = ""; } int gender = currentPerson.getGender(); String email = Plus.AccountApi.getAccountName(mGoogleApiClient); Intent mIntent = new Intent(getActivity(), LoginUserDetails.class); mIntent.putExtra("login_method", "google"); mIntent.putExtra("email", email); mIntent.putExtra("first_name", firstName); mIntent.putExtra("gender", gender); mIntent.putExtra("last_name", lastName); mIntent.putExtra("photo", personPhoto); mixpanel.track("Login - Google"); startActivity(mIntent); } else { Toast.makeText(getContext(), "You do not have a google+ account", Toast.LENGTH_SHORT).show(); showSocialLoginDialog(); } Log.d(TAG, "onConnected:" + bundle); mShouldResolve = false; }
@Override public void run() { final MPDbAdapter dbMock = new MPDbAdapter(getContext()) { @Override public int addJSON(JSONObject message, MPDbAdapter.Table table) { mMessages.add(message); return 1; } }; final AnalyticsMessages analyticsMessages = new AnalyticsMessages(getContext()) { @Override public MPDbAdapter makeDbAdapter(Context context) { return dbMock; } }; MixpanelAPI mixpanel = new TestUtils.CleanMixpanelAPI(getContext(), mMockPreferences, "TEST TOKEN") { @Override protected AnalyticsMessages getAnalyticsMessages() { return analyticsMessages; } }; mixpanel.clearPreferences(); mixpanel.track("test in thread", new JSONObject()); }
public void trackEvent(String eventName) { JSONObject props = new JSONObject(); try { props.put("Email", InfoUtil.getEmailAddress(context)); props.put("Date", new Date().toString()); mixpanelAPI.track(eventName, props); } catch (JSONException e) { // e.printStackTrace(); } }
@Override public void onActivityStopped(Activity activity) { // Remove from the current list of running activities status.remove(activity.toString()); // If there are no running activities, the app is backgrounded // In this scenario, log the event to Mixpanel if (status.isEmpty()) { // Send the session tracking information to Mixpanel mixpanelCallbacks.track("$app_open"); // Mark the current session as inactive so we properly start a new one mixpanelCallbacks.unregisterSuperProperty("Session"); // Force all queued Mixpanel data to be sent to Mixpanel mixpanelCallbacks.flush(); } Log.d("Current Activities", "onStop() " + status.toString()); }
public static void sendEvent(android.content.Context context, String eventTitle) { MixpanelAPI mixpanel = MixpanelAPI.getInstance(context, MIXPANEL_TOKEN); mixpanel.track(eventTitle, null); }
/** * Tracks a Mixpanel event with properties. (for compatibilty with iOS version) * * @param event * @param properties */ @ReactMethod public void trackWithProperties(String event, ReadableMap properties) { mixpanel.track(event, this.readableMapToJson(properties)); }
/** * Tracks a Mixpanel event. * * @param event * @param properties */ @ReactMethod public void track(String event) { mixpanel.track(event); }
public void testPersistence() { MixpanelAPI metricsOne = new MixpanelAPI(getContext(), mMockPreferences, "SAME TOKEN"); metricsOne.clearPreferences(); JSONObject props; try { props = new JSONObject("{ 'a' : 'value of a', 'b' : 'value of b' }"); } catch (JSONException e) { throw new RuntimeException("Can't construct fixture for super properties test."); } metricsOne.clearSuperProperties(); metricsOne.registerSuperProperties(props); metricsOne.identify("Expected Events Identity"); metricsOne.getPeople().identify("Expected People Identity"); // We exploit the fact that any metrics object with the same token // will get their values from the same persistent store. final List<Object> messages = new ArrayList<Object>(); final AnalyticsMessages listener = new AnalyticsMessages(getContext()) { @Override public void eventsMessage(EventDescription heard) { messages.add(heard); } @Override public void peopleMessage(JSONObject heard) { messages.add(heard); } }; class ListeningAPI extends MixpanelAPI { public ListeningAPI(Context c, Future<SharedPreferences> prefs, String token) { super(c, prefs, token); } @Override protected AnalyticsMessages getAnalyticsMessages() { return listener; } } MixpanelAPI differentToken = new ListeningAPI(getContext(), mMockPreferences, "DIFFERENT TOKEN"); differentToken.track("other event", null); differentToken.getPeople().set("other people prop", "Word"); // should be queued up. assertEquals(1, messages.size()); AnalyticsMessages.EventDescription eventMessage = (AnalyticsMessages.EventDescription) messages.get(0); try { JSONObject eventProps = eventMessage.getProperties(); String sentId = eventProps.getString("distinct_id"); String sentA = eventProps.optString("a"); String sentB = eventProps.optString("b"); assertFalse("Expected Events Identity".equals(sentId)); assertEquals("", sentA); assertEquals("", sentB); } catch (JSONException e) { fail("Event message has an unexpected shape " + e); } messages.clear(); MixpanelAPI metricsTwo = new ListeningAPI(getContext(), mMockPreferences, "SAME TOKEN"); metricsTwo.track("eventname", null); metricsTwo.getPeople().set("people prop name", "Indeed"); assertEquals(2, messages.size()); eventMessage = (AnalyticsMessages.EventDescription) messages.get(0); JSONObject peopleMessage = (JSONObject) messages.get(1); try { JSONObject eventProps = eventMessage.getProperties(); String sentId = eventProps.getString("distinct_id"); String sentA = eventProps.getString("a"); String sentB = eventProps.getString("b"); assertEquals("Expected Events Identity", sentId); assertEquals("value of a", sentA); assertEquals("value of b", sentB); } catch (JSONException e) { fail("Event message has an unexpected shape " + e); } try { String sentId = peopleMessage.getString("$distinct_id"); assertEquals("Expected People Identity", sentId); } catch (JSONException e) { fail("Event message has an unexpected shape: " + peopleMessage.toString()); } }
public void testHTTPFailures() { final List<Object> flushResults = new ArrayList<Object>(); final BlockingQueue<String> performRequestCalls = new LinkedBlockingQueue<String>(); final ServerMessage mockPoster = new ServerMessage() { @Override public byte[] performRequest(String endpointUrl, List<NameValuePair> nameValuePairs) throws IOException { if (null == nameValuePairs) { assertEquals( "DECIDE ENDPOINT?version=1&lib=android&token=Test+Message+Queuing&distinct_id=new+person", endpointUrl); return TestUtils.bytes("{}"); } Object obj = flushResults.remove(0); try { assertEquals(nameValuePairs.get(0).getName(), "data"); final String jsonData = Base64Coder.decodeString(nameValuePairs.get(0).getValue()); JSONArray msg = new JSONArray(jsonData); JSONObject event = msg.getJSONObject(0); performRequestCalls.put(event.getString("event")); if (obj instanceof IOException) { throw (IOException) obj; } else if (obj instanceof MalformedURLException) { throw (MalformedURLException) obj; } } catch (JSONException e) { throw new RuntimeException("Malformed data passed to test mock", e); } catch (InterruptedException e) { throw new RuntimeException( "Could not write message to reporting queue for tests.", e); } return (byte[]) obj; } }; final MPConfig config = new MPConfig(new Bundle()) { public String getDecideEndpoint() { return "DECIDE ENDPOINT"; } public String getEventsEndpoint() { return "EVENTS ENDPOINT"; } public boolean getDisableFallback() { return false; } }; final List<String> cleanupCalls = new ArrayList<String>(); final MPDbAdapter mockAdapter = new MPDbAdapter(getContext()) { @Override public void cleanupEvents(String last_id, Table table) { cleanupCalls.add("called"); super.cleanupEvents(last_id, table); } }; final AnalyticsMessages listener = new AnalyticsMessages(getContext()) { @Override protected MPDbAdapter makeDbAdapter(Context context) { return mockAdapter; } @Override protected ServerMessage getPoster() { return mockPoster; } @Override protected MPConfig getConfig(Context context) { return config; } }; MixpanelAPI metrics = new TestUtils.CleanMixpanelAPI(getContext(), mMockPreferences, "Test Message Queuing") { @Override protected AnalyticsMessages getAnalyticsMessages() { return listener; } }; try { // Basic succeed on first, non-fallback url cleanupCalls.clear(); flushResults.add(TestUtils.bytes("1\n")); metrics.track("Should Succeed", null); metrics.flush(); Thread.sleep(500); assertEquals("Should Succeed", performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(null, performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(1, cleanupCalls.size()); // Fallback test--first URL throws IOException cleanupCalls.clear(); flushResults.add(new IOException()); flushResults.add(TestUtils.bytes("1\n")); metrics.track("Should Succeed", null); metrics.flush(); Thread.sleep(500); assertEquals("Should Succeed", performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals("Should Succeed", performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(1, cleanupCalls.size()); // Two IOExceptions -- assume temporary network failure, no cleanup should happen until // second flush cleanupCalls.clear(); flushResults.add(new IOException()); flushResults.add(new IOException()); flushResults.add(TestUtils.bytes("1\n")); metrics.track("Should Succeed", null); metrics.flush(); Thread.sleep(500); assertEquals("Should Succeed", performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals("Should Succeed", performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(0, cleanupCalls.size()); metrics.flush(); Thread.sleep(500); assertEquals("Should Succeed", performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(null, performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(1, cleanupCalls.size()); // MalformedURLException -- should dump the events since this will probably never succeed cleanupCalls.clear(); flushResults.add(new MalformedURLException()); metrics.track("Should Fail", null); metrics.flush(); Thread.sleep(500); assertEquals("Should Fail", performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(null, performRequestCalls.poll(2, TimeUnit.SECONDS)); assertEquals(1, cleanupCalls.size()); } catch (InterruptedException e) { throw new RuntimeException("Test was interrupted."); } }
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); } }