@@ -143,6 +143,42 @@ public void addChangeListener_notifiesOnRefresh() throws IOException {
143143 assertEquals (2 , listener .callCount );
144144 }
145145
146+ @ Test
147+ public void removeChangeListener_unregisters_observer () throws IOException {
148+ final String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2" ;
149+ final String accessToken2 = "2/MkSJoj1xsli0AccessToken_NKPY2" ;
150+ MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory ();
151+ transportFactory .transport .addClient (CLIENT_ID , CLIENT_SECRET );
152+ transportFactory .transport .addRefreshToken (REFRESH_TOKEN , accessToken1 );
153+ OAuth2Credentials userCredentials = UserCredentials .newBuilder ()
154+ .setClientId (CLIENT_ID )
155+ .setClientSecret (CLIENT_SECRET )
156+ .setRefreshToken (REFRESH_TOKEN )
157+ .setHttpTransportFactory (transportFactory )
158+ .build ();
159+ // Use a fixed clock so tokens don't expire
160+ userCredentials .clock = new TestClock ();
161+ TestChangeListener listener = new TestChangeListener ();
162+ userCredentials .addChangeListener (listener );
163+ assertEquals (0 , listener .callCount );
164+
165+ // Get a first token
166+ userCredentials .getRequestMetadata (CALL_URI );
167+ assertEquals (1 , listener .callCount );
168+
169+ // Change server to a different token and refresh
170+ transportFactory .transport .addRefreshToken (REFRESH_TOKEN , accessToken2 );
171+ // Refresh to force getting next token
172+ userCredentials .refresh ();
173+ assertEquals (2 , listener .callCount );
174+
175+ // Remove the listener and refresh the credential again
176+ userCredentials .removeChangeListener (listener );
177+ transportFactory .transport .addRefreshToken (REFRESH_TOKEN , accessToken2 );
178+ userCredentials .refresh ();
179+ assertEquals (2 , listener .callCount );
180+ }
181+
146182 @ Test
147183 public void getRequestMetadata_blocking_cachesExpiringToken () throws IOException {
148184 final String accessToken1 = "1/MkSJoj1xsli0AccessToken_NKPY2" ;
0 commit comments