TBR java moments - prohibit bad advertiser usage

Throw exception if advertiser.stop called when
not advertising.

Change-Id: I28ea99bf844608b129d4096e293cc3d65d1740b0
diff --git a/projects/moments/app/src/main/java/io/v/moments/model/AdvertiserImpl.java b/projects/moments/app/src/main/java/io/v/moments/model/AdvertiserImpl.java
index ee08e5b..5db8116 100644
--- a/projects/moments/app/src/main/java/io/v/moments/model/AdvertiserImpl.java
+++ b/projects/moments/app/src/main/java/io/v/moments/model/AdvertiserImpl.java
@@ -136,6 +136,9 @@
 
     @Override
     public void stop() {
+        if (!isAdvertising()) {
+            throw new IllegalStateException("Not advertising.");
+        }
         Log.d(TAG, "Entering stop");
         if (mAdvCtx != null) {
             Log.d(TAG, "Cancelling advertising.");
diff --git a/projects/moments/app/src/test/java/io/v/moments/model/AdvertiserImplTest.java b/projects/moments/app/src/test/java/io/v/moments/model/AdvertiserImplTest.java
index 7ac73fc..485bdf7 100644
--- a/projects/moments/app/src/test/java/io/v/moments/model/AdvertiserImplTest.java
+++ b/projects/moments/app/src/test/java/io/v/moments/model/AdvertiserImplTest.java
@@ -4,6 +4,8 @@
 
 package io.v.moments.model;
 
+import com.google.common.util.concurrent.FutureCallback;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -61,16 +63,36 @@
     ServerStatus mServerStatus;
     @Mock
     VContext mContext;
+    @Mock
+    FutureCallback<Void> mStartupCallback;
+    @Mock
+    FutureCallback<Void> mShutdownCallback;
+    @Mock
+    FutureCallback<Void> mStartupCallback2;
+    @Mock
+    FutureCallback<Void> mShutdownCallback2;
 
     @Captor
     ArgumentCaptor<Service> mAdvertisement;
     @Captor
     ArgumentCaptor<List<BlessingPattern>> mBlessingList;
+    @Captor
+    ArgumentCaptor<FutureCallback<VContext>> mV23StartupCallback;
+    @Captor
+    ArgumentCaptor<FutureCallback<Void>> mV23ShutdownCallback;
+    @Captor
+    ArgumentCaptor<Throwable> mThrowable;
 
     Attributes mAttrs;
 
     AdvertiserImpl mAdvertiser;
 
+    static Map<String, String> makeFakeAttributes() {
+        Map<String, String> result = new HashMap<>();
+        result.put("color", "teal");
+        return result;
+    }
+
     @Before
     public void setup() throws Exception {
         mAttrs = new Attributes(makeFakeAttributes());
@@ -90,11 +112,6 @@
         when(mMoment.toString()).thenReturn(MOMENT_NAME);
         when(mMoment.makeAttributes()).thenReturn(mAttrs);
 
-        List<BlessingPattern> list = any();
-        when(mV23Manager.advertise(
-                any(Service.class),
-                list)).thenReturn(mContext);
-
         mAdvertiser = new AdvertiserImpl(mV23Manager, mMoment);
     }
 
@@ -115,39 +132,56 @@
     @Test
     public void advertiseStartSuccess() {
         assertFalse(mAdvertiser.isAdvertising());
-        mAdvertiser.start();
+        mAdvertiser.start(mStartupCallback, mShutdownCallback);
 
-        verify(mV23Manager).advertise(
-                mAdvertisement.capture(),
-                mBlessingList.capture());
-
-        assertEquals(0, mBlessingList.getValue().size());
+        verifyAdvertiseCall();
 
         Service service = mAdvertisement.getValue();
         assertEquals(ID.toString(), service.getInstanceId());
         assertEquals(MOMENT_NAME, service.getInstanceName());
-        assertEquals(Config.INTERFACE_NAME, service.getInterfaceName());
+        assertEquals(Config.Discovery.INTERFACE_NAME, service.getInterfaceName());
         assertSame(mAttrs, service.getAttrs());
 
         List<String> addresses = service.getAddrs();
         assertTrue(addresses.contains(ADDRESS));
         assertEquals(1, addresses.size());
 
+        assertSame(mV23ShutdownCallback.getValue(), mShutdownCallback);
+
+        assertFalse(mAdvertiser.isAdvertising());
+        activateAdvertising();
         assertTrue(mAdvertiser.isAdvertising());
     }
 
+    private void verifyAdvertiseCall() {
+        verify(mV23Manager).advertise(
+                mAdvertisement.capture(),
+                eq(Config.Discovery.DURATION),
+                mV23StartupCallback.capture(),
+                mV23ShutdownCallback.capture());
+    }
+
+    // Make the transition to advertising by returning a context from V23.
+    private void activateAdvertising() {
+        mV23StartupCallback.getValue().onSuccess(mContext);
+        // Verify that the UX will be impacted.
+        verify(mStartupCallback).onSuccess(null);
+    }
+
     @Test
     public void advertiseStartFailure() {
         assertFalse(mAdvertiser.isAdvertising());
-        mAdvertiser.start();
+        mAdvertiser.start(mStartupCallback, mShutdownCallback);
+        verifyAdvertiseCall();
+        activateAdvertising();
         assertTrue(mAdvertiser.isAdvertising());
-        mThrown.expect(IllegalStateException.class);
-        mThrown.expectMessage("Already advertising.");
-        mAdvertiser.start();
+        mAdvertiser.start(mStartupCallback2, mShutdownCallback2);
+        verify(mStartupCallback2).onFailure(mThrowable.capture());
+        assertEquals("Already advertising.", mThrowable.getValue().getMessage());
     }
 
     @Test
-    public void advertiseStopFailure() {
+    public void advertiseStopDoesNotThrowIfNotAdvertising() {
         mThrown.expect(IllegalStateException.class);
         mThrown.expectMessage("Not advertising.");
         mAdvertiser.stop();
@@ -162,10 +196,4 @@
         verify(mServerContext).cancel();
         assertFalse(mAdvertiser.isAdvertising());
     }
-
-    static Map<String, String> makeFakeAttributes() {
-        Map<String, String> result = new HashMap<>();
-        result.put("color", "teal");
-        return result;
-    }
 }