Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
4 package org.mozilla.gecko.background.healthreport;
6 import org.mozilla.gecko.background.helpers.DBHelpers;
7 import org.mozilla.gecko.background.helpers.DBProviderTestCase;
9 import android.content.ContentResolver;
10 import android.content.ContentValues;
11 import android.database.Cursor;
12 import android.net.Uri;
13 import android.test.mock.MockContentResolver;
15 public class TestHealthReportProvider extends DBProviderTestCase<HealthReportProvider> {
16 protected static final int MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
18 public TestHealthReportProvider() {
19 super(HealthReportProvider.class, HealthReportProvider.HEALTH_AUTHORITY);
20 }
22 public TestHealthReportProvider(Class<HealthReportProvider> providerClass,
23 String providerAuthority) {
24 super(providerClass, providerAuthority);
25 }
27 private Uri getCompleteUri(String rest) {
28 return Uri.parse("content://" + HealthReportProvider.HEALTH_AUTHORITY + rest +
29 (rest.indexOf('?') == -1 ? "?" : "&") +
30 "profilePath=" + Uri.encode(fakeProfileDirectory.getAbsolutePath()));
31 }
33 private void ensureCount(int expected, Uri uri) {
34 final MockContentResolver resolver = getMockContentResolver();
35 Cursor cursor = resolver.query(uri, null, null, null, null);
36 assertNotNull(cursor);
37 assertEquals(expected, cursor.getCount());
38 cursor.close();
39 }
41 private void ensureMeasurementCount(int expected) {
42 final Uri measurements = getCompleteUri("/measurements/");
43 ensureCount(expected, measurements);
44 }
46 private void ensureFieldCount(int expected) {
47 final Uri fields = getCompleteUri("/fields/");
48 ensureCount(expected, fields);
49 }
51 public void testNonExistentMeasurement() {
52 assertNotNull(getContext());
53 Uri u = getCompleteUri("/events/" + 0 + "/" + "testm" + "/" + 3 + "/" + "testf");
54 ContentValues v = new ContentValues();
55 v.put("value", 5);
56 ContentResolver r = getMockContentResolver();
57 assertNotNull(r);
58 try {
59 r.insert(u, v);
60 fail("Should throw.");
61 } catch (IllegalStateException e) {
62 assertTrue(e.getMessage().contains("No field with name testf"));
63 }
64 }
66 public void testEnsureMeasurements() {
67 ensureMeasurementCount(0);
69 final MockContentResolver resolver = getMockContentResolver();
71 // Note that we insert no fields. These are empty measurements.
72 ContentValues values = new ContentValues();
73 resolver.insert(getCompleteUri("/fields/testm1/1"), values);
74 ensureMeasurementCount(1);
76 resolver.insert(getCompleteUri("/fields/testm1/1"), values);
77 ensureMeasurementCount(1);
79 resolver.insert(getCompleteUri("/fields/testm1/3"), values);
80 ensureMeasurementCount(2);
82 resolver.insert(getCompleteUri("/fields/testm2/1"), values);
83 ensureMeasurementCount(3);
85 Cursor cursor = resolver.query(getCompleteUri("/measurements/"), null, null, null, null);
87 assertTrue(cursor.moveToFirst());
88 assertEquals("testm1", cursor.getString(1)); // 'id' is column 0.
89 assertEquals(1, cursor.getInt(2));
91 assertTrue(cursor.moveToNext());
92 assertEquals("testm1", cursor.getString(1));
93 assertEquals(3, cursor.getInt(2));
95 assertTrue(cursor.moveToNext());
96 assertEquals("testm2", cursor.getString(1));
97 assertEquals(1, cursor.getInt(2));
98 assertFalse(cursor.moveToNext());
100 cursor.close();
102 resolver.delete(getCompleteUri("/measurements/"), null, null);
103 }
105 /**
106 * Return true if the two times occur on the same UTC day.
107 */
108 private static boolean sameDay(long start, long end) {
109 return Math.floor(start / MILLISECONDS_PER_DAY) ==
110 Math.floor(end / MILLISECONDS_PER_DAY);
111 }
113 private static int getDay(long time) {
114 return (int) Math.floor(time / MILLISECONDS_PER_DAY);
115 }
118 public void testRealData() {
119 ensureMeasurementCount(0);
120 long start = System.currentTimeMillis();
121 int day = getDay(start);
123 final MockContentResolver resolver = getMockContentResolver();
125 // Register a provider with four fields.
126 ContentValues values = new ContentValues();
127 values.put("counter1", 1);
128 values.put("counter2", 4);
129 values.put("last1", 7);
130 values.put("discrete1", 11);
132 resolver.insert(getCompleteUri("/fields/testm1/1"), values);
133 ensureMeasurementCount(1);
134 ensureFieldCount(4);
136 final Uri envURI = resolver.insert(getCompleteUri("/environments/"), getTestEnvContentValues());
137 String envHash = null;
138 Cursor envCursor = resolver.query(envURI, null, null, null, null);
139 try {
140 assertTrue(envCursor.moveToFirst());
141 envHash = envCursor.getString(2); // id, version, hash, ...
142 } finally {
143 envCursor.close();
144 }
146 final Uri eventURI = HealthReportUtils.getEventURI(envURI);
148 Uri discrete1 = eventURI.buildUpon().appendEncodedPath("testm1/1/discrete1").build();
149 Uri counter1 = eventURI.buildUpon().appendEncodedPath("testm1/1/counter1/counter").build();
150 Uri counter2 = eventURI.buildUpon().appendEncodedPath("testm1/1/counter2/counter").build();
151 Uri last1 = eventURI.buildUpon().appendEncodedPath("testm1/1/last1/last").build();
153 ContentValues discreteS = new ContentValues();
154 ContentValues discreteI = new ContentValues();
156 discreteS.put("value", "Some string");
157 discreteI.put("value", 9);
158 resolver.insert(discrete1, discreteS);
159 resolver.insert(discrete1, discreteI);
161 ContentValues counter = new ContentValues();
162 resolver.update(counter1, counter, null, null); // Defaults to 1.
163 resolver.update(counter2, counter, null, null); // Defaults to 1.
164 counter.put("value", 3);
165 resolver.update(counter2, counter, null, null); // Increment by 3.
167 // Interleaving.
168 discreteS.put("value", "Some other string");
169 discreteI.put("value", 3);
170 resolver.insert(discrete1, discreteS);
171 resolver.insert(discrete1, discreteI);
173 // Note that we explicitly do not support last-values transitioning between types.
174 ContentValues last = new ContentValues();
175 last.put("value", 123);
176 resolver.update(last1, last, null, null);
177 last.put("value", 245);
178 resolver.update(last1, last, null, null);
180 int expectedRows = 2 + 1 + 4; // Two counters, one last, four entries for discrete.
182 // Now let's see what comes up in the query!
183 // We'll do "named" first -- the results include strings.
184 Cursor cursor = resolver.query(getCompleteUri("/events/?time=" + start), null, null, null, null);
185 assertEquals(expectedRows, cursor.getCount());
186 assertTrue(cursor.moveToFirst());
188 // Let's be safe in case someone runs this test at midnight.
189 long end = System.currentTimeMillis();
190 if (!sameDay(start, end)) {
191 System.out.println("Aborting testAddData: spans midnight.");
192 cursor.close();
193 return;
194 }
196 // "date", "env", m, mv, f, f_flags, "value"
197 Object[][] expected = {
198 {day, envHash, "testm1", 1, "counter1", null, 1},
199 {day, envHash, "testm1", 1, "counter2", null, 4},
201 // Discrete values don't preserve order of insertion across types, but
202 // this actually isn't really permitted -- fields have a single type.
203 {day, envHash, "testm1", 1, "discrete1", null, 9},
204 {day, envHash, "testm1", 1, "discrete1", null, 3},
205 {day, envHash, "testm1", 1, "discrete1", null, "Some string"},
206 {day, envHash, "testm1", 1, "discrete1", null, "Some other string"},
207 {day, envHash, "testm1", 1, "last1", null, 245},
208 };
211 DBHelpers.assertCursorContains(expected, cursor);
212 cursor.close();
214 resolver.delete(getCompleteUri("/measurements/"), null, null);
215 ensureMeasurementCount(0);
216 ensureFieldCount(0);
217 }
219 private ContentValues getTestEnvContentValues() {
220 ContentValues v = new ContentValues();
221 v.put("profileCreation", 0);
222 v.put("cpuCount", 0);
223 v.put("memoryMB", 0);
225 v.put("isBlocklistEnabled", 0);
226 v.put("isTelemetryEnabled", 0);
227 v.put("extensionCount", 0);
228 v.put("pluginCount", 0);
229 v.put("themeCount", 0);
231 v.put("architecture", "");
232 v.put("sysName", "");
233 v.put("sysVersion", "");
234 v.put("vendor", "");
235 v.put("appName", "");
236 v.put("appID", "");
237 v.put("appVersion", "");
238 v.put("appBuildID", "");
239 v.put("platformVersion", "");
240 v.put("platformBuildID", "");
241 v.put("os", "");
242 v.put("xpcomabi", "");
243 v.put("updateChannel", "");
245 // v2.
246 v.put("distribution", "");
247 v.put("osLocale", "en_us");
248 v.put("appLocale", "en_us");
249 v.put("acceptLangSet", 0);
251 return v;
252 }
253 }