addedEvents = new HashSet<>();
242 | addedEvents.add(GeoQueryEventTestListener.keyEntered("1", 37, -122));
243 | addedEvents.add(GeoQueryEventTestListener.keyEntered("2", 37.0001, -122.0001));
244 | addedEvents.add(GeoQueryEventTestListener.keyEntered("4", 37.0002, -121.9998));
245 |
246 | testListenerRemained.expectEvents(addedEvents);
247 | testListenerRemained.expectEvents(addedEvents);
248 |
249 | query.removeGeoQueryEventListener(testListenerRemoved);
250 | query.removeAllListeners();
251 |
252 | geoFireTestingRule.setLocation(geoFire, "0", 37, -122); // entered
253 | geoFireTestingRule.setLocation(geoFire, "1", 0, 0); // exited
254 | geoFireTestingRule.setLocation(geoFire, "2", 37, -122.0001, true); // moved
255 |
256 | testListenerRemained.expectEvents(addedEvents);
257 | testListenerRemoved.expectEvents(addedEvents);
258 | }
259 |
260 | @Test
261 | public void readyListener() throws InterruptedException {
262 | GeoFire geoFire = geoFireTestingRule.newTestGeoFire();
263 | geoFireTestingRule.setLocation(geoFire, "0", 0, 0);
264 | geoFireTestingRule.setLocation(geoFire, "1", 37.0000, -122.0000);
265 | geoFireTestingRule.setLocation(geoFire, "2", 37.0001, -122.0001);
266 | geoFireTestingRule.setLocation(geoFire, "3", 37.1000, -122.0000);
267 | geoFireTestingRule.setLocation(geoFire, "4", 37.0002, -121.9998, true);
268 |
269 | GeoQuery query = geoFire.queryAtLocation(new GeoLocation(37.0, -122), 1);
270 | final boolean[] done = new boolean[1];
271 | final boolean[] failed = new boolean[1];
272 | final Semaphore semaphore = new Semaphore(0);
273 | query.addGeoQueryEventListener(new GeoQueryEventListener() {
274 | @Override
275 | public void onKeyEntered(String key, GeoLocation location) {
276 | if (done[0]) {
277 | failed[0] = true;
278 | }
279 | }
280 |
281 | @Override
282 | public void onKeyExited(String key) {
283 | }
284 |
285 | @Override
286 | public void onKeyMoved(String key, GeoLocation location) {
287 | }
288 |
289 | @Override
290 | public void onGeoQueryReady() {
291 | done[0] = true;
292 | semaphore.release();
293 | }
294 |
295 | @Override
296 | public void onGeoQueryError(DatabaseError error) {
297 | fail("onGeoQueryError: " + error.toString());
298 | }
299 | });
300 |
301 | assertTrue(semaphore.tryAcquire(geoFireTestingRule.timeout, TimeUnit.SECONDS));
302 | assertTrue("GeoQuery not ready, test timed out.", done[0]);
303 | // wait for any further events to fire
304 | Thread.sleep(250);
305 | assertFalse("Key entered after ready event occurred!", failed[0]);
306 | }
307 |
308 | @Test
309 | public void readyListenerAfterReady() throws InterruptedException {
310 | GeoFire geoFire = geoFireTestingRule.newTestGeoFire();
311 | geoFireTestingRule.setLocation(geoFire, "0", 0, 0);
312 | geoFireTestingRule.setLocation(geoFire, "1", 37.0000, -122.0000);
313 | geoFireTestingRule.setLocation(geoFire, "2", 37.0001, -122.0001);
314 | geoFireTestingRule.setLocation(geoFire, "3", 37.1000, -122.0000);
315 | geoFireTestingRule.setLocation(geoFire, "4", 37.0002, -121.9998, true);
316 |
317 | GeoQuery query = geoFire.queryAtLocation(new GeoLocation(37.0, -122), 1);
318 |
319 | final Semaphore semaphore = new Semaphore(0);
320 | query.addGeoQueryEventListener(new GeoQueryEventListener() {
321 | @Override
322 | public void onKeyEntered(String key, GeoLocation location) {
323 | }
324 |
325 | @Override
326 | public void onKeyExited(String key) {
327 | }
328 |
329 | @Override
330 | public void onKeyMoved(String key, GeoLocation location) {
331 | }
332 |
333 | @Override
334 | public void onGeoQueryReady() {
335 | semaphore.release();
336 | }
337 |
338 | @Override
339 | public void onGeoQueryError(DatabaseError error) {
340 | }
341 | });
342 |
343 | assertTrue(semaphore.tryAcquire(geoFireTestingRule.timeout, TimeUnit.SECONDS));
344 |
345 | query.addGeoQueryEventListener(new GeoQueryEventListener() {
346 | @Override
347 | public void onKeyEntered(String key, GeoLocation location) {
348 | }
349 |
350 | @Override
351 | public void onKeyExited(String key) {
352 | }
353 |
354 | @Override
355 | public void onKeyMoved(String key, GeoLocation location) {
356 | }
357 |
358 | @Override
359 | public void onGeoQueryReady() {
360 | semaphore.release();
361 | }
362 |
363 | @Override
364 | public void onGeoQueryError(DatabaseError error) {
365 | }
366 | });
367 | assertTrue(semaphore.tryAcquire(10, TimeUnit.MILLISECONDS));
368 | }
369 |
370 | @Test
371 | public void readyAfterUpdateCriteria() throws InterruptedException {
372 | GeoFire geoFire = geoFireTestingRule.newTestGeoFire();
373 | geoFireTestingRule.setLocation(geoFire, "0", 0, 0);
374 | geoFireTestingRule.setLocation(geoFire, "1", 37.0000, -122.0000);
375 | geoFireTestingRule.setLocation(geoFire, "2", 37.0001, -122.0001);
376 | geoFireTestingRule.setLocation(geoFire, "3", 37.1000, -122.0000);
377 | geoFireTestingRule.setLocation(geoFire, "4", 37.0002, -121.9998, true);
378 |
379 | GeoQuery query = geoFire.queryAtLocation(new GeoLocation(37.0, -122), 1);
380 | final boolean[] done = new boolean[1];
381 | final Semaphore semaphore = new Semaphore(0);
382 | final int[] readyCount = new int[1];
383 | query.addGeoQueryEventListener(new GeoQueryEventListener() {
384 | @Override
385 | public void onKeyEntered(String key, GeoLocation location) {
386 | if (key.equals("0")) {
387 | done[0] = true;
388 | }
389 | }
390 |
391 | @Override
392 | public void onKeyExited(String key) {
393 | }
394 |
395 | @Override
396 | public void onKeyMoved(String key, GeoLocation location) {
397 | }
398 |
399 | @Override
400 | public void onGeoQueryReady() {
401 | semaphore.release();
402 | readyCount[0]++;
403 | }
404 |
405 | @Override
406 | public void onGeoQueryError(DatabaseError error) {
407 |
408 | }
409 | });
410 |
411 | assertTrue(semaphore.tryAcquire(geoFireTestingRule.timeout, TimeUnit.SECONDS));
412 | query.setCenter(new GeoLocation(0,0));
413 | assertTrue(semaphore.tryAcquire(geoFireTestingRule.timeout, TimeUnit.SECONDS));
414 | assertTrue(done[0]);
415 | }
416 | }
417 |
--------------------------------------------------------------------------------
/java/src/test/java/com/firebase/geofire/GeoUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.firebase.geofire;
2 |
3 | import com.firebase.geofire.util.GeoUtils;
4 | import org.junit.Assert;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.junit.runners.JUnit4;
8 |
9 | @RunWith(JUnit4.class)
10 | public class GeoUtilsTest {
11 |
12 | @Test
13 | public void wrapLongitude() {
14 | Assert.assertEquals(1, GeoUtils.wrapLongitude(1), 1e-6);
15 | Assert.assertEquals(0, GeoUtils.wrapLongitude(0), 1e-6);
16 | Assert.assertEquals(180, GeoUtils.wrapLongitude(180), 1e-6);
17 | Assert.assertEquals(-180, GeoUtils.wrapLongitude(-180), 1e-6);
18 | Assert.assertEquals(-178, GeoUtils.wrapLongitude(182), 1e-6);
19 | Assert.assertEquals(-90, GeoUtils.wrapLongitude(270), 1e-6);
20 | Assert.assertEquals(0, GeoUtils.wrapLongitude(360), 1e-6);
21 | Assert.assertEquals(-180, GeoUtils.wrapLongitude(540), 1e-6);
22 | Assert.assertEquals(-90, GeoUtils.wrapLongitude(630), 1e-6);
23 | Assert.assertEquals(0, GeoUtils.wrapLongitude(720), 1e-6);
24 | Assert.assertEquals(90, GeoUtils.wrapLongitude(810), 1e-6);
25 | Assert.assertEquals(0, GeoUtils.wrapLongitude(-360), 1e-6);
26 | Assert.assertEquals(178, GeoUtils.wrapLongitude(-182), 1e-6);
27 | Assert.assertEquals(90, GeoUtils.wrapLongitude(-270), 1e-6);
28 | Assert.assertEquals(0, GeoUtils.wrapLongitude(-360), 1e-6);
29 | Assert.assertEquals(-90, GeoUtils.wrapLongitude(-450), 1e-6);
30 | Assert.assertEquals(180, GeoUtils.wrapLongitude(-540), 1e-6);
31 | Assert.assertEquals(90, GeoUtils.wrapLongitude(-630), 1e-6);
32 | Assert.assertEquals(0, GeoUtils.wrapLongitude(1080), 1e-6);
33 | Assert.assertEquals(0, GeoUtils.wrapLongitude(-1080), 1e-6);
34 | }
35 |
36 | @Test
37 | public void distanceToLongitudeDegrees() {
38 | Assert.assertEquals(0.008983, GeoUtils.distanceToLongitudeDegrees(1000, 0), 1e-5);
39 | Assert.assertEquals(1, GeoUtils.distanceToLongitudeDegrees(111320, 0), 1e-5);
40 | Assert.assertEquals(1, GeoUtils.distanceToLongitudeDegrees(107550, 15), 1e-5);
41 | Assert.assertEquals(1, GeoUtils.distanceToLongitudeDegrees(96486, 30), 1e-5);
42 | Assert.assertEquals(1, GeoUtils.distanceToLongitudeDegrees(78847, 45), 1e-5);
43 | Assert.assertEquals(1, GeoUtils.distanceToLongitudeDegrees(55800, 60), 1e-5);
44 | Assert.assertEquals(1, GeoUtils.distanceToLongitudeDegrees(28902, 75), 1e-5);
45 | Assert.assertEquals(0, GeoUtils.distanceToLongitudeDegrees(0, 90), 1e-5);
46 | Assert.assertEquals(360, GeoUtils.distanceToLongitudeDegrees(1000, 90), 1e-5);
47 | Assert.assertEquals(360, GeoUtils.distanceToLongitudeDegrees(1000, 89.9999), 1e-5);
48 | Assert.assertEquals(102.594208, GeoUtils.distanceToLongitudeDegrees(1000, 89.995), 1e-5);
49 | }
50 |
51 | @Test
52 | public void capRadius() {
53 | Assert.assertEquals(1.0d, GeoUtils.capRadius(1.0d), 0.1d);
54 | Assert.assertEquals(100.0d, GeoUtils.capRadius(100.0d), 0.1d);
55 | Assert.assertEquals(813.0d, GeoUtils.capRadius(813.0d), 0.1d);
56 | Assert.assertEquals(8586.0d, GeoUtils.capRadius(8586.0d), 0.1d);
57 | Assert.assertEquals(8587.0d, GeoUtils.capRadius(8587.0d), 0.1d);
58 |
59 | Assert.assertEquals(8587.0d, GeoUtils.capRadius(8588.0d), 0.1d);
60 | Assert.assertEquals(8587.0d, GeoUtils.capRadius(10000.0d), 0.1d);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.firebase
6 | geofire
7 | 3.0.1-SNAPSHOT
8 | pom
9 |
10 | geofire
11 | GeoFire is an open-source library for Android/Java that allows you to store and query a set of keys based on their geographic location.
12 |
13 | Firebase
14 | https://www.firebase.com/
15 |
16 | https://github.com/firebase/geofire-java
17 |
18 | scm:git:git@github.com:firebase/geofire-java.git
19 | scm:git:git@github.com:firebase/geofire-java.git
20 | https://github.com/firebase/geofire-java
21 | HEAD
22 |
23 |
24 |
25 |
26 | samtstern
27 | Sam Stern
28 | samstern@google.com
29 | Firebase
30 | https://firebase.google.com
31 |
32 | Project-Administrator
33 | Developer
34 |
35 | -8
36 |
37 |
38 |
39 |
40 |
41 | MIT
42 | http://firebase.mit-license.org
43 |
44 |
45 |
46 | UTF-8
47 |
48 |
49 |
50 | common
51 | java
52 | testing
53 |
54 |
55 |
56 |
57 | geofire
58 | https://api.bintray.com/maven/firebase/geofire/geofire
59 |
60 |
61 |
62 |
63 |
66 |
67 |
68 | co.leantechniques
69 | maven-buildtime-extension
70 | 2.0.3
71 |
72 |
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-compiler-plugin
78 | 3.1
79 |
80 | 1.7
81 | 1.7
82 |
83 |
84 |
85 |
86 | org.apache.maven.plugins
87 | maven-javadoc-plugin
88 | 2.9.1
89 |
90 |
91 | attach-javadocs
92 |
93 | jar
94 |
95 |
96 |
97 |
98 | com.firebase.geofire.*
99 | public
100 |
101 |
102 |
103 |
104 | org.apache.maven.plugins
105 | maven-source-plugin
106 | 2.3
107 |
108 |
109 | add-sources
110 |
111 | jar
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | org.apache.maven.plugins
121 | maven-release-plugin
122 | 2.5.3
123 |
124 |
125 |
126 |
127 | maven-surefire-plugin
128 | 2.19.1
129 |
130 |
131 |
132 |
133 | org.apache.maven.plugins
134 | maven-failsafe-plugin
135 | 2.20.1
136 |
137 |
138 |
139 | integration-test
140 | verify
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | cd $(dirname $0)
5 |
6 | ###########################
7 | # VALIDATE GEOFIRE REPO #
8 | ###########################
9 | # Ensure the checked out geofire branch is master
10 | CHECKED_OUT_BRANCH="$(git branch | grep "*" | awk -F ' ' '{print $2}')"
11 | if [[ $CHECKED_OUT_BRANCH != "master" ]]; then
12 | echo "Error: Your geofire repo is not on the master branch."
13 | exit 1
14 | fi
15 |
16 | # Make sure the geofire branch does not have existing changes
17 | if ! git --git-dir=".git" diff --quiet; then
18 | echo "Error: Your geofire repo has existing changes on the master branch. Make sure you commit and push the new version before running this release script."
19 | exit 1
20 | fi
21 |
22 | ##############################
23 | # VALIDATE CLIENT VERSIONS #
24 | ##############################
25 |
26 | VERSION=$(grep version pom.xml |head -2|tail -1|awk -F '>' '{print $2}'|awk -F '<' '{print $1}'|awk -F '-' '{print $1}')
27 | read -p "We are releasing $VERSION, is this correct? (press enter to continue) " DERP
28 | if [[ ! -z $DERP ]]; then
29 | echo "Cancelling release, please update pom.xml to desired version"
30 | fi
31 |
32 | # Ensure there is not an existing git tag for the new version
33 | # XXX this is wrong; needs to be semver sorted as my other scripts are
34 | LAST_GIT_TAG="$(git tag --list | tail -1 | awk -F 'v' '{print $2}')"
35 | if [[ $VERSION == $LAST_GIT_TAG ]]; then
36 | echo "Error: git tag v${VERSION} already exists. Make sure you are not releasing an already-released version."
37 | exit 1
38 | fi
39 |
40 | # Create docs
41 | ./create-docs.sh
42 | if [[ $? -ne 0 ]]; then
43 | echo "error: There was an error creating the docs."
44 | exit 1
45 | fi
46 |
47 | ###################
48 | # DEPLOY TO MAVEN #
49 | ###################
50 | read -p "Next, make sure this repo is clean and up to date. We will be kicking off a deploy to maven." DERP
51 | mvn clean
52 | mvn -s settings.xml release:clean release:prepare release:perform -Darguments="-DskipTests" -Dtag=v$VERSION
53 |
54 | if [[ $? -ne 0 ]]; then
55 | echo "error: Error building and releasing to maven."
56 | exit 1
57 | fi
58 |
59 | ##############
60 | # UPDATE GIT #
61 | ##############
62 |
63 | # Push the new git tag created by Maven
64 | git push --tags
65 | if [[ $? -ne 0 ]]; then
66 | echo "Error: Failed to do 'git push --tags' from geofire repo."
67 | exit 1
68 | fi
69 |
70 | ################
71 | # MANUAL STEPS #
72 | ################
73 |
74 | echo "Manual steps:"
75 | echo " 1) Release all draft artifacts on Bintray at https://bintray.com/firebase/geofire"
76 | echo " 2) On bintray, initiate Maven Central sync for latest version"
77 | echo " 3) Deply new docs: $> firebase deploy"
78 | echo " 4) Update the release notes for GeoFire version ${VERSION} on GitHub and add jars for downloading"
79 | echo " 5) Update firebase-versions.json in the firebase-clients repo with the changelog information"
80 | echo " 6) Tweet @FirebaseRelease: 'v${VERSION} of @Firebase GeoFire for Java is available https://github.com/firebase/geofire-java"
81 | echo ---
82 | echo "Done! Woo!"
83 |
--------------------------------------------------------------------------------
/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 | geofire
10 | ${env.BINTRAY_USER}
11 | ${env.BINTRAY_KEY}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | false
21 |
22 | central
23 | bintray
24 | http://jcenter.bintray.com
25 |
26 |
27 |
28 |
29 |
30 | false
31 |
32 | central
33 | bintray-plugins
34 | http://jcenter.bintray.com
35 |
36 |
37 | bintray
38 |
39 |
40 |
41 |
42 | bintray
43 |
44 |
45 |
--------------------------------------------------------------------------------
/site/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | GeoFire for Java
5 |
6 |
7 |
8 | GeoFire for iOS
9 |
10 | API Reference
11 |
12 | A full API reference for GeoFire for Java is available here.
13 |
14 |
15 | Quick Start
16 |
17 | Check out GitHub for a quick start guide and examples.
18 |
19 |
20 | Source Code
21 |
22 | GeoFire for Java is open source and available on GitHub
23 |
24 |
25 | Other version
26 |
27 | Other versions of GeoFire are available fore JavaScript and iOS.
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/testing/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 |
7 | com.firebase
8 | geofire
9 | 3.0.1-SNAPSHOT
10 | ../
11 |
12 |
13 | geofire-testing
14 | jar
15 |
16 | geofire-testing
17 | GeoFire is an open-source library for Android/Java that allows you to store and query a set of keys based on their geographic location.
18 |
19 | Firebase
20 | https://www.firebase.com/
21 |
22 | https://github.com/firebase/geofire-java
23 |
24 | scm:git:git@github.com:firebase/geofire-java.git
25 | scm:git:git@github.com:firebase/geofire-java.git
26 | https://github.com/firebase/geofire-java
27 | HEAD
28 |
29 |
30 |
31 | MIT
32 | http://firebase.mit-license.org
33 |
34 |
35 |
36 | UTF-8
37 |
38 |
39 |
40 |
41 | geofire
42 | https://api.bintray.com/maven/firebase/geofire/geofire-testing
43 |
44 |
45 |
46 |
47 | src/main/java
48 |
49 |
50 |
51 |
52 | com.firebase
53 | geofire-common
54 | ${project.version}
55 |
56 |
57 | junit
58 | junit
59 | 4.12
60 |
61 |
62 | org.slf4j
63 | slf4j-simple
64 | 1.7.25
65 |
66 |
67 |
68 |
69 | com.google.firebase
70 | firebase-admin
71 | [6.0.0,)
72 | provided
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/testing/src/main/java/com/firebase/geofire/testing/GeoFireTestingRule.java:
--------------------------------------------------------------------------------
1 | package com.firebase.geofire.testing;
2 |
3 | import static org.junit.Assert.assertNull;
4 | import static org.junit.Assert.assertTrue;
5 | import static org.junit.Assert.fail;
6 |
7 | import com.firebase.geofire.GeoFire;
8 | import com.firebase.geofire.GeoLocation;
9 | import com.google.auth.oauth2.GoogleCredentials;
10 | import com.google.firebase.FirebaseApp;
11 | import com.google.firebase.FirebaseOptions;
12 | import com.google.firebase.database.DataSnapshot;
13 | import com.google.firebase.database.DatabaseError;
14 | import com.google.firebase.database.DatabaseReference;
15 | import com.google.firebase.database.FirebaseDatabase;
16 | import com.google.firebase.database.ValueEventListener;
17 | import java.io.FileInputStream;
18 | import java.io.IOException;
19 | import java.util.Random;
20 | import java.util.concurrent.Semaphore;
21 | import java.util.concurrent.TimeUnit;
22 | import java.util.concurrent.TimeoutException;
23 | import org.junit.rules.TestWatcher;
24 | import org.junit.runner.Description;
25 | import org.slf4j.impl.SimpleLogger;
26 |
27 | /**
28 | * This is a JUnit rule that can be used for hooking up Geofire with a real database instance.
29 | */
30 | public final class GeoFireTestingRule extends TestWatcher {
31 |
32 | static final long DEFAULT_TIMEOUT_SECONDS = 5;
33 |
34 | private static final String ALPHA_NUM_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
35 |
36 | private static final String SERVICE_ACCOUNT_CREDENTIALS = "service-account.json";
37 |
38 | private DatabaseReference databaseReference;
39 |
40 | public final String databaseUrl;
41 |
42 | /** Timeout in seconds. */
43 | public final long timeout;
44 |
45 | public GeoFireTestingRule(final String databaseUrl) {
46 | this(databaseUrl, DEFAULT_TIMEOUT_SECONDS);
47 | }
48 |
49 | public GeoFireTestingRule(final String databaseUrl, final long timeout) {
50 | this.databaseUrl = databaseUrl;
51 | this.timeout = timeout;
52 | }
53 |
54 | @Override
55 | public void starting(Description description) {
56 | if (FirebaseApp.getApps().isEmpty()) {
57 | final GoogleCredentials credentials;
58 |
59 | try {
60 | credentials = GoogleCredentials.fromStream(new FileInputStream(SERVICE_ACCOUNT_CREDENTIALS));
61 | } catch (IOException e) {
62 | throw new RuntimeException(e);
63 | }
64 |
65 | FirebaseOptions firebaseOptions = new FirebaseOptions.Builder()
66 | .setDatabaseUrl(databaseUrl)
67 | .setCredentials(credentials)
68 | .build();
69 | FirebaseApp.initializeApp(firebaseOptions);
70 |
71 | System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "DEBUG");
72 | }
73 | this.databaseReference = FirebaseDatabase.getInstance().getReferenceFromUrl(databaseUrl);
74 | }
75 |
76 | /** This will return you a new Geofire instance that can be used for testing. */
77 | public GeoFire newTestGeoFire() {
78 | return new GeoFire(databaseReference.child(randomAlphaNumericString(16)));
79 | }
80 |
81 | /**
82 | * Sets a given location key from the latitude and longitude on the provided Geofire instance.
83 | * This operation will run asychronously.
84 | */
85 | public void setLocation(GeoFire geoFire, String key, double latitude, double longitude) {
86 | setLocation(geoFire, key, latitude, longitude, false);
87 | }
88 |
89 | /**
90 | * Removes a location on the provided Geofire instance.
91 | * This operation will run asychronously.
92 | */
93 | public void removeLocation(GeoFire geoFire, String key) {
94 | removeLocation(geoFire, key, false);
95 | }
96 |
97 | /** Sets the value on the given databaseReference and waits until the operation has successfully finished. */
98 | public void setValueAndWait(DatabaseReference databaseReference, Object value) {
99 | final SimpleFuture futureError = new SimpleFuture();
100 | databaseReference.setValue(value, new DatabaseReference.CompletionListener() {
101 | @Override
102 | public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
103 | futureError.put(databaseError);
104 | }
105 | });
106 | try {
107 | assertNull(futureError.get(timeout, TimeUnit.SECONDS));
108 | } catch (InterruptedException e) {
109 | throw new RuntimeException(e);
110 | } catch (TimeoutException e) {
111 | fail("Timeout occured!");
112 | }
113 | }
114 |
115 | /**
116 | * Sets a given location key from the latitude and longitude on the provided Geofire instance.
117 | * This operation will run asychronously or synchronously depending on the wait boolean.
118 | */
119 | public void setLocation(GeoFire geoFire, String key, double latitude, double longitude, boolean wait) {
120 | final SimpleFuture futureError = new SimpleFuture();
121 | geoFire.setLocation(key, new GeoLocation(latitude, longitude), new GeoFire.CompletionListener() {
122 | @Override
123 | public void onComplete(String key, DatabaseError error) {
124 | futureError.put(error);
125 | }
126 | });
127 | if (wait) {
128 | try {
129 | assertNull(futureError.get(timeout, TimeUnit.SECONDS));
130 | } catch (InterruptedException e) {
131 | throw new RuntimeException(e);
132 | } catch (TimeoutException e) {
133 | fail("Timeout occured!");
134 | }
135 | }
136 | }
137 |
138 | /**
139 | * Removes a location on the provided Geofire instance.
140 | * This operation will run asychronously or synchronously depending on the wait boolean.
141 | */
142 | public void removeLocation(GeoFire geoFire, String key, boolean wait) {
143 | final SimpleFuture futureError = new SimpleFuture();
144 | geoFire.removeLocation(key, new GeoFire.CompletionListener() {
145 | @Override
146 | public void onComplete(String key, DatabaseError error) {
147 | futureError.put(error);
148 | }
149 | });
150 | if (wait) {
151 | try {
152 | assertNull(futureError.get(timeout, TimeUnit.SECONDS));
153 | } catch (InterruptedException e) {
154 | throw new RuntimeException(e);
155 | } catch (TimeoutException e) {
156 | fail("Timeout occured!");
157 | }
158 | }
159 | }
160 |
161 | /** This lets you blockingly wait until the onGeoFireReady was fired on the provided Geofire instance. */
162 | public void waitForGeoFireReady(GeoFire geoFire) throws InterruptedException {
163 | final Semaphore semaphore = new Semaphore(0);
164 | geoFire.getDatabaseReference().addListenerForSingleValueEvent(new ValueEventListener() {
165 | @Override
166 | public void onDataChange(DataSnapshot dataSnapshot) {
167 | semaphore.release();
168 | }
169 |
170 | @Override
171 | public void onCancelled(DatabaseError databaseError) {
172 | fail("Firebase error: " + databaseError);
173 | }
174 | });
175 |
176 | assertTrue("Timeout occured!", semaphore.tryAcquire(timeout, TimeUnit.SECONDS));
177 | }
178 |
179 | @Override
180 | public void finished(Description description) {
181 | this.databaseReference.setValueAsync(null);
182 | this.databaseReference = null;
183 | }
184 |
185 | private static String randomAlphaNumericString(int length) {
186 | StringBuilder sb = new StringBuilder();
187 | Random random = new Random();
188 | for (int i = 0; i < length; i++ ) {
189 | sb.append(ALPHA_NUM_CHARS.charAt(random.nextInt(ALPHA_NUM_CHARS.length())));
190 | }
191 | return sb.toString();
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/testing/src/main/java/com/firebase/geofire/testing/GeoQueryDataEventTestListener.java:
--------------------------------------------------------------------------------
1 | package com.firebase.geofire.testing;
2 |
3 | import static java.util.Locale.US;
4 |
5 | import com.firebase.geofire.GeoLocation;
6 | import com.firebase.geofire.GeoQueryDataEventListener;
7 | import com.google.firebase.database.DatabaseError;
8 | import com.google.firebase.database.DataSnapshot;
9 |
10 | /**
11 | * This listener can be used for testing your Geofire instance and asserting that certain events were sent.
12 | */
13 | public final class GeoQueryDataEventTestListener extends TestListener implements
14 | GeoQueryDataEventListener {
15 | public static String dataEntered(String key, double latitude, double longitude) {
16 | return String.format(US, "DATA_ENTERED(%s,%f,%f)", key, latitude, longitude);
17 | }
18 |
19 | public static String dataExited(String key) {
20 | return String.format("DATA_EXITED(%s)", key);
21 | }
22 |
23 | public static String dataMoved(String key, double latitude, double longitude) {
24 | return String.format(US, "DATA_MOVED(%s,%f,%f)", key, latitude, longitude);
25 | }
26 |
27 | public static String dataChanged(String key, double latitude, double longitude) {
28 | return String.format(US, "DATA_CHANGED(%s,%f,%f)", key, latitude, longitude);
29 | }
30 |
31 | private final boolean recordEntered;
32 | private final boolean recordMoved;
33 | private final boolean recordChanged;
34 | private final boolean recordExited;
35 |
36 | /** This will by default record all of the events. */
37 | public GeoQueryDataEventTestListener() {
38 | this(true, true, true, true);
39 | }
40 |
41 | /** Allows you to specify exactly which of the events you want to record. */
42 | public GeoQueryDataEventTestListener(boolean recordEntered, boolean recordMoved,
43 | boolean recordChanged, boolean recordExited) {
44 | this.recordEntered = recordEntered;
45 | this.recordMoved = recordMoved;
46 | this.recordChanged = recordChanged;
47 | this.recordExited = recordExited;
48 | }
49 |
50 | @Override
51 | public void onDataEntered(DataSnapshot dataSnapshot, GeoLocation location) {
52 | if (recordEntered) {
53 | addEvent(dataEntered(dataSnapshot.getKey(), location.latitude, location.longitude));
54 | }
55 | }
56 |
57 | @Override
58 | public void onDataExited(DataSnapshot dataSnapshot) {
59 | if (recordExited) {
60 | addEvent(dataExited(dataSnapshot.getKey()));
61 | }
62 | }
63 |
64 | @Override
65 | public void onDataMoved(DataSnapshot dataSnapshot, GeoLocation location) {
66 | if (recordMoved) {
67 | addEvent(dataMoved(dataSnapshot.getKey(), location.latitude, location.longitude));
68 | }
69 | }
70 |
71 | @Override
72 | public void onDataChanged(DataSnapshot dataSnapshot, GeoLocation location) {
73 | if (recordChanged) {
74 | addEvent(dataChanged(dataSnapshot.getKey(), location.latitude, location.longitude));
75 | }
76 | }
77 |
78 | @Override
79 | public void onGeoQueryReady() {
80 | // No-op.
81 | }
82 |
83 | @Override
84 | public void onGeoQueryError(DatabaseError error) {
85 | throw error.toException();
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/testing/src/main/java/com/firebase/geofire/testing/GeoQueryEventTestListener.java:
--------------------------------------------------------------------------------
1 | package com.firebase.geofire.testing;
2 |
3 | import com.firebase.geofire.GeoLocation;
4 | import com.firebase.geofire.GeoQueryEventListener;
5 | import com.google.firebase.database.DatabaseError;
6 |
7 | import static java.util.Locale.US;
8 |
9 | /**
10 | * This listener can be used for testing your Geofire instance and asserting that certain events were sent.
11 | */
12 | public final class GeoQueryEventTestListener extends TestListener implements GeoQueryEventListener {
13 | public static String keyEntered(String key, double latitude, double longitude) {
14 | return String.format(US, "KEY_ENTERED(%s,%f,%f)", key, latitude, longitude);
15 | }
16 |
17 | public static String keyMoved(String key, double latitude, double longitude) {
18 | return String.format(US, "KEY_MOVED(%s,%f,%f)", key, latitude, longitude);
19 | }
20 |
21 | public static String keyExited(String key) {
22 | return String.format("KEY_EXITED(%s)", key);
23 | }
24 |
25 | private final boolean recordEntered;
26 | private final boolean recordMoved;
27 | private final boolean recordExited;
28 |
29 | /** This will by default record all of the events. */
30 | public GeoQueryEventTestListener() {
31 | this(true, true, true);
32 | }
33 |
34 | /** Allows you to specify exactly which of the events you want to record. */
35 | public GeoQueryEventTestListener(boolean recordEntered, boolean recordMoved, boolean recordExited) {
36 | this.recordEntered = recordEntered;
37 | this.recordMoved = recordMoved;
38 | this.recordExited = recordExited;
39 | }
40 |
41 | @Override
42 | public void onKeyEntered(String key, GeoLocation location) {
43 | if (recordEntered) {
44 | addEvent(keyEntered(key, location.latitude, location.longitude));
45 | }
46 | }
47 |
48 | @Override
49 | public void onKeyExited(String key) {
50 | if (recordExited) {
51 | addEvent(keyExited(key));
52 | }
53 | }
54 |
55 | @Override
56 | public void onKeyMoved(String key, GeoLocation location) {
57 | if (recordMoved) {
58 | addEvent(keyMoved(key, location.latitude, location.longitude));
59 | }
60 | }
61 |
62 | @Override
63 | public void onGeoQueryReady() {
64 | // No-op.
65 | }
66 |
67 | @Override
68 | public void onGeoQueryError(DatabaseError error) {
69 | throw error.toException();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/testing/src/main/java/com/firebase/geofire/testing/SimpleFuture.java:
--------------------------------------------------------------------------------
1 | package com.firebase.geofire.testing;
2 |
3 | import java.util.concurrent.TimeUnit;
4 | import java.util.concurrent.TimeoutException;
5 | import java.util.concurrent.locks.Condition;
6 | import java.util.concurrent.locks.Lock;
7 | import java.util.concurrent.locks.ReentrantLock;
8 |
9 | /**
10 | * This is a simple version of a future that does not implement the interface.
11 | * It allows you to put a certain value in it and then blockingly getting it.
12 | */
13 | public final class SimpleFuture {
14 | private V value;
15 | private boolean isSet;
16 |
17 | private final Lock lock = new ReentrantLock();
18 | private final Condition condition = lock.newCondition();
19 |
20 | /** Puts the value into the future. */
21 | public synchronized void put(final V valueToPut) {
22 | lock.lock();
23 |
24 | try {
25 | value = valueToPut;
26 | isSet = true;
27 | condition.signalAll();
28 | } finally {
29 | lock.unlock();
30 | }
31 | }
32 |
33 | /** Allows you to get the value that might be set here in a blocking way. */
34 | public V get(final long timeout, final TimeUnit unit) throws InterruptedException, TimeoutException {
35 | lock.lock();
36 |
37 | try {
38 | while (!isSet) {
39 | if (!condition.await(timeout, unit)) {
40 | throw new TimeoutException();
41 | }
42 | }
43 |
44 | return value;
45 | } finally {
46 | lock.unlock();
47 | }
48 | }
49 |
50 | /** If the value is set this method returns true and the get method will return it then. */
51 | public boolean isDone() {
52 | return isSet;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/testing/src/main/java/com/firebase/geofire/testing/TestCallback.java:
--------------------------------------------------------------------------------
1 | package com.firebase.geofire.testing;
2 |
3 | import static java.util.Locale.US;
4 |
5 | import com.firebase.geofire.GeoLocation;
6 | import com.firebase.geofire.LocationCallback;
7 | import com.firebase.geofire.testing.GeoFireTestingRule;
8 | import com.google.firebase.database.DatabaseError;
9 | import java.util.concurrent.ExecutionException;
10 | import java.util.concurrent.TimeUnit;
11 | import java.util.concurrent.TimeoutException;
12 | import org.junit.Assert;
13 |
14 | /**
15 | * This is a test callback for the LocationCallback interface.
16 | * It allows you to verify that a certain value was set on the given location.
17 | */
18 | public final class TestCallback implements LocationCallback {
19 | public static String location(String key, double latitude, double longitude) {
20 | return String.format(US, "LOCATION(%s,%f,%f)", key, latitude, longitude);
21 | }
22 |
23 | public static String noLocation(String key) {
24 | return String.format("NO_LOCATION(%s)", key);
25 | }
26 |
27 | private final SimpleFuture future = new SimpleFuture<>();
28 |
29 | /** Timeout in seconds. */
30 | public final long timeout;
31 |
32 | public TestCallback() {
33 | this(GeoFireTestingRule.DEFAULT_TIMEOUT_SECONDS);
34 | }
35 |
36 | public TestCallback(final long timeout) {
37 | this.timeout = timeout;
38 | }
39 |
40 | /**
41 | * Returns the callback value as a string in a blocking fashion.
42 | * It's one of the values that are returned by the static factory methods above.
43 | */
44 | public String getCallbackValue() throws InterruptedException, ExecutionException, TimeoutException {
45 | return future.get(timeout, TimeUnit.SECONDS);
46 | }
47 |
48 | @Override
49 | public void onLocationResult(String key, GeoLocation location) {
50 | if (future.isDone()) {
51 | throw new IllegalStateException("Already received callback");
52 | }
53 |
54 | if (location != null) {
55 | future.put(location(key, location.latitude, location.longitude));
56 | } else {
57 | future.put(noLocation(key));
58 | }
59 | }
60 |
61 | @Override
62 | public void onCancelled(DatabaseError firebaseError) {
63 | Assert.fail("Firebase synchronization failed: " + firebaseError);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/testing/src/main/java/com/firebase/geofire/testing/TestListener.java:
--------------------------------------------------------------------------------
1 | package com.firebase.geofire.testing;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.fail;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Collection;
8 | import java.util.LinkedHashSet;
9 | import java.util.List;
10 | import java.util.concurrent.TimeUnit;
11 | import java.util.concurrent.locks.Condition;
12 | import java.util.concurrent.locks.ReentrantLock;
13 |
14 | abstract class TestListener {
15 | private final List events = new ArrayList<>();
16 | private final ReentrantLock lock = new ReentrantLock();
17 | private final Condition condition = lock.newCondition();
18 |
19 | void addEvent(String event) {
20 | lock.lock();
21 |
22 | try {
23 | events.add(event);
24 | condition.signal();
25 | } finally {
26 | lock.unlock();
27 | }
28 | }
29 |
30 | /**
31 | * This allows you to assert that certain events were retrieved.
32 | * You can use the static factory methods on {@link GeoQueryDataEventTestListener} or
33 | * {@link GeoQueryEventTestListener} to retrieve the strings.
34 | */
35 | public void expectEvents(Collection events) throws InterruptedException {
36 | boolean stillWaiting = true;
37 | lock.lock();
38 |
39 | try {
40 | while (!contentsEqual(this.events, events)) {
41 | if (!stillWaiting) {
42 | assertEquals(events, new LinkedHashSet<>(this.events));
43 | fail("Timeout occured");
44 | return;
45 | }
46 | stillWaiting = condition.await(10, TimeUnit.SECONDS);
47 | }
48 | } finally {
49 | lock.unlock();
50 | }
51 | }
52 |
53 | private boolean contentsEqual(Collection c1, Collection c2) {
54 | return (new LinkedHashSet<>(c1).equals(new LinkedHashSet<>(c2)));
55 | }
56 | }
57 |
--------------------------------------------------------------------------------