1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/tests/background/junit3/src/healthreport/TestHealthReportProvider.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,253 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +package org.mozilla.gecko.background.healthreport; 1.8 + 1.9 +import org.mozilla.gecko.background.helpers.DBHelpers; 1.10 +import org.mozilla.gecko.background.helpers.DBProviderTestCase; 1.11 + 1.12 +import android.content.ContentResolver; 1.13 +import android.content.ContentValues; 1.14 +import android.database.Cursor; 1.15 +import android.net.Uri; 1.16 +import android.test.mock.MockContentResolver; 1.17 + 1.18 +public class TestHealthReportProvider extends DBProviderTestCase<HealthReportProvider> { 1.19 + protected static final int MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000; 1.20 + 1.21 + public TestHealthReportProvider() { 1.22 + super(HealthReportProvider.class, HealthReportProvider.HEALTH_AUTHORITY); 1.23 + } 1.24 + 1.25 + public TestHealthReportProvider(Class<HealthReportProvider> providerClass, 1.26 + String providerAuthority) { 1.27 + super(providerClass, providerAuthority); 1.28 + } 1.29 + 1.30 + private Uri getCompleteUri(String rest) { 1.31 + return Uri.parse("content://" + HealthReportProvider.HEALTH_AUTHORITY + rest + 1.32 + (rest.indexOf('?') == -1 ? "?" : "&") + 1.33 + "profilePath=" + Uri.encode(fakeProfileDirectory.getAbsolutePath())); 1.34 + } 1.35 + 1.36 + private void ensureCount(int expected, Uri uri) { 1.37 + final MockContentResolver resolver = getMockContentResolver(); 1.38 + Cursor cursor = resolver.query(uri, null, null, null, null); 1.39 + assertNotNull(cursor); 1.40 + assertEquals(expected, cursor.getCount()); 1.41 + cursor.close(); 1.42 + } 1.43 + 1.44 + private void ensureMeasurementCount(int expected) { 1.45 + final Uri measurements = getCompleteUri("/measurements/"); 1.46 + ensureCount(expected, measurements); 1.47 + } 1.48 + 1.49 + private void ensureFieldCount(int expected) { 1.50 + final Uri fields = getCompleteUri("/fields/"); 1.51 + ensureCount(expected, fields); 1.52 + } 1.53 + 1.54 + public void testNonExistentMeasurement() { 1.55 + assertNotNull(getContext()); 1.56 + Uri u = getCompleteUri("/events/" + 0 + "/" + "testm" + "/" + 3 + "/" + "testf"); 1.57 + ContentValues v = new ContentValues(); 1.58 + v.put("value", 5); 1.59 + ContentResolver r = getMockContentResolver(); 1.60 + assertNotNull(r); 1.61 + try { 1.62 + r.insert(u, v); 1.63 + fail("Should throw."); 1.64 + } catch (IllegalStateException e) { 1.65 + assertTrue(e.getMessage().contains("No field with name testf")); 1.66 + } 1.67 + } 1.68 + 1.69 + public void testEnsureMeasurements() { 1.70 + ensureMeasurementCount(0); 1.71 + 1.72 + final MockContentResolver resolver = getMockContentResolver(); 1.73 + 1.74 + // Note that we insert no fields. These are empty measurements. 1.75 + ContentValues values = new ContentValues(); 1.76 + resolver.insert(getCompleteUri("/fields/testm1/1"), values); 1.77 + ensureMeasurementCount(1); 1.78 + 1.79 + resolver.insert(getCompleteUri("/fields/testm1/1"), values); 1.80 + ensureMeasurementCount(1); 1.81 + 1.82 + resolver.insert(getCompleteUri("/fields/testm1/3"), values); 1.83 + ensureMeasurementCount(2); 1.84 + 1.85 + resolver.insert(getCompleteUri("/fields/testm2/1"), values); 1.86 + ensureMeasurementCount(3); 1.87 + 1.88 + Cursor cursor = resolver.query(getCompleteUri("/measurements/"), null, null, null, null); 1.89 + 1.90 + assertTrue(cursor.moveToFirst()); 1.91 + assertEquals("testm1", cursor.getString(1)); // 'id' is column 0. 1.92 + assertEquals(1, cursor.getInt(2)); 1.93 + 1.94 + assertTrue(cursor.moveToNext()); 1.95 + assertEquals("testm1", cursor.getString(1)); 1.96 + assertEquals(3, cursor.getInt(2)); 1.97 + 1.98 + assertTrue(cursor.moveToNext()); 1.99 + assertEquals("testm2", cursor.getString(1)); 1.100 + assertEquals(1, cursor.getInt(2)); 1.101 + assertFalse(cursor.moveToNext()); 1.102 + 1.103 + cursor.close(); 1.104 + 1.105 + resolver.delete(getCompleteUri("/measurements/"), null, null); 1.106 + } 1.107 + 1.108 + /** 1.109 + * Return true if the two times occur on the same UTC day. 1.110 + */ 1.111 + private static boolean sameDay(long start, long end) { 1.112 + return Math.floor(start / MILLISECONDS_PER_DAY) == 1.113 + Math.floor(end / MILLISECONDS_PER_DAY); 1.114 + } 1.115 + 1.116 + private static int getDay(long time) { 1.117 + return (int) Math.floor(time / MILLISECONDS_PER_DAY); 1.118 + } 1.119 + 1.120 + 1.121 + public void testRealData() { 1.122 + ensureMeasurementCount(0); 1.123 + long start = System.currentTimeMillis(); 1.124 + int day = getDay(start); 1.125 + 1.126 + final MockContentResolver resolver = getMockContentResolver(); 1.127 + 1.128 + // Register a provider with four fields. 1.129 + ContentValues values = new ContentValues(); 1.130 + values.put("counter1", 1); 1.131 + values.put("counter2", 4); 1.132 + values.put("last1", 7); 1.133 + values.put("discrete1", 11); 1.134 + 1.135 + resolver.insert(getCompleteUri("/fields/testm1/1"), values); 1.136 + ensureMeasurementCount(1); 1.137 + ensureFieldCount(4); 1.138 + 1.139 + final Uri envURI = resolver.insert(getCompleteUri("/environments/"), getTestEnvContentValues()); 1.140 + String envHash = null; 1.141 + Cursor envCursor = resolver.query(envURI, null, null, null, null); 1.142 + try { 1.143 + assertTrue(envCursor.moveToFirst()); 1.144 + envHash = envCursor.getString(2); // id, version, hash, ... 1.145 + } finally { 1.146 + envCursor.close(); 1.147 + } 1.148 + 1.149 + final Uri eventURI = HealthReportUtils.getEventURI(envURI); 1.150 + 1.151 + Uri discrete1 = eventURI.buildUpon().appendEncodedPath("testm1/1/discrete1").build(); 1.152 + Uri counter1 = eventURI.buildUpon().appendEncodedPath("testm1/1/counter1/counter").build(); 1.153 + Uri counter2 = eventURI.buildUpon().appendEncodedPath("testm1/1/counter2/counter").build(); 1.154 + Uri last1 = eventURI.buildUpon().appendEncodedPath("testm1/1/last1/last").build(); 1.155 + 1.156 + ContentValues discreteS = new ContentValues(); 1.157 + ContentValues discreteI = new ContentValues(); 1.158 + 1.159 + discreteS.put("value", "Some string"); 1.160 + discreteI.put("value", 9); 1.161 + resolver.insert(discrete1, discreteS); 1.162 + resolver.insert(discrete1, discreteI); 1.163 + 1.164 + ContentValues counter = new ContentValues(); 1.165 + resolver.update(counter1, counter, null, null); // Defaults to 1. 1.166 + resolver.update(counter2, counter, null, null); // Defaults to 1. 1.167 + counter.put("value", 3); 1.168 + resolver.update(counter2, counter, null, null); // Increment by 3. 1.169 + 1.170 + // Interleaving. 1.171 + discreteS.put("value", "Some other string"); 1.172 + discreteI.put("value", 3); 1.173 + resolver.insert(discrete1, discreteS); 1.174 + resolver.insert(discrete1, discreteI); 1.175 + 1.176 + // Note that we explicitly do not support last-values transitioning between types. 1.177 + ContentValues last = new ContentValues(); 1.178 + last.put("value", 123); 1.179 + resolver.update(last1, last, null, null); 1.180 + last.put("value", 245); 1.181 + resolver.update(last1, last, null, null); 1.182 + 1.183 + int expectedRows = 2 + 1 + 4; // Two counters, one last, four entries for discrete. 1.184 + 1.185 + // Now let's see what comes up in the query! 1.186 + // We'll do "named" first -- the results include strings. 1.187 + Cursor cursor = resolver.query(getCompleteUri("/events/?time=" + start), null, null, null, null); 1.188 + assertEquals(expectedRows, cursor.getCount()); 1.189 + assertTrue(cursor.moveToFirst()); 1.190 + 1.191 + // Let's be safe in case someone runs this test at midnight. 1.192 + long end = System.currentTimeMillis(); 1.193 + if (!sameDay(start, end)) { 1.194 + System.out.println("Aborting testAddData: spans midnight."); 1.195 + cursor.close(); 1.196 + return; 1.197 + } 1.198 + 1.199 + // "date", "env", m, mv, f, f_flags, "value" 1.200 + Object[][] expected = { 1.201 + {day, envHash, "testm1", 1, "counter1", null, 1}, 1.202 + {day, envHash, "testm1", 1, "counter2", null, 4}, 1.203 + 1.204 + // Discrete values don't preserve order of insertion across types, but 1.205 + // this actually isn't really permitted -- fields have a single type. 1.206 + {day, envHash, "testm1", 1, "discrete1", null, 9}, 1.207 + {day, envHash, "testm1", 1, "discrete1", null, 3}, 1.208 + {day, envHash, "testm1", 1, "discrete1", null, "Some string"}, 1.209 + {day, envHash, "testm1", 1, "discrete1", null, "Some other string"}, 1.210 + {day, envHash, "testm1", 1, "last1", null, 245}, 1.211 + }; 1.212 + 1.213 + 1.214 + DBHelpers.assertCursorContains(expected, cursor); 1.215 + cursor.close(); 1.216 + 1.217 + resolver.delete(getCompleteUri("/measurements/"), null, null); 1.218 + ensureMeasurementCount(0); 1.219 + ensureFieldCount(0); 1.220 + } 1.221 + 1.222 + private ContentValues getTestEnvContentValues() { 1.223 + ContentValues v = new ContentValues(); 1.224 + v.put("profileCreation", 0); 1.225 + v.put("cpuCount", 0); 1.226 + v.put("memoryMB", 0); 1.227 + 1.228 + v.put("isBlocklistEnabled", 0); 1.229 + v.put("isTelemetryEnabled", 0); 1.230 + v.put("extensionCount", 0); 1.231 + v.put("pluginCount", 0); 1.232 + v.put("themeCount", 0); 1.233 + 1.234 + v.put("architecture", ""); 1.235 + v.put("sysName", ""); 1.236 + v.put("sysVersion", ""); 1.237 + v.put("vendor", ""); 1.238 + v.put("appName", ""); 1.239 + v.put("appID", ""); 1.240 + v.put("appVersion", ""); 1.241 + v.put("appBuildID", ""); 1.242 + v.put("platformVersion", ""); 1.243 + v.put("platformBuildID", ""); 1.244 + v.put("os", ""); 1.245 + v.put("xpcomabi", ""); 1.246 + v.put("updateChannel", ""); 1.247 + 1.248 + // v2. 1.249 + v.put("distribution", ""); 1.250 + v.put("osLocale", "en_us"); 1.251 + v.put("appLocale", "en_us"); 1.252 + v.put("acceptLangSet", 0); 1.253 + 1.254 + return v; 1.255 + } 1.256 +}