1 /**
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telephony.imsmedia;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.fail;
21 import static org.mockito.Mockito.any;
22 import static org.mockito.Mockito.anyInt;
23 import static org.mockito.Mockito.doAnswer;
24 import static org.mockito.Mockito.doReturn;
25 import static org.mockito.Mockito.eq;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.ServiceConnection;
33 import android.os.IBinder;
34 import android.os.IInterface;
35 import android.os.Parcel;
36 
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.mockito.Mock;
40 import org.mockito.MockitoAnnotations;
41 import org.mockito.invocation.InvocationOnMock;
42 import org.mockito.stubbing.Answer;
43 
44 import java.net.DatagramSocket;
45 import java.util.concurrent.Executor;
46 import java.util.concurrent.Executors;
47 
48 public class ImsMediaManagerTest {
49     private Executor mExecutor;
50     private final Object mLock = new Object();
51 
52     @Mock
53     Context mMockContext;
54     @Mock
55     DatagramSocket mMockRtpSocket, mMockRtcpSocket;
56     @Mock
57     ImsMediaManager.OnConnectedCallback mMockConnectedCallback;
58     @Mock
59     RtpConfig mMockRtpConfig;
60     @Mock
61     ImsMediaSession mMockImsMediaSession;
62     @Mock
63     ImsMediaManager.SessionCallback mMockSessionCallback;
64     @Mock
65     IMediaStubTest mMockImsMedia;
66 
67     @Before
setUp()68     public void setUp() throws Exception {
69         mExecutor = Executors.newSingleThreadExecutor();
70 
71         MockitoAnnotations.initMocks(this);
72         doReturn(mMockImsMedia).when(mMockImsMediaSession).getBinder();
73         doReturn(mMockImsMedia).when(mMockImsMedia).queryLocalInterface(any(String.class));
74         doReturn(true).when(mMockImsMedia).transact(anyInt(), any(Parcel.class), any(), anyInt());
75 
76         doAnswer(new Answer<Boolean>() {
77             @Override
78             public Boolean answer(InvocationOnMock invocation) throws Throwable {
79                 Object[] args = invocation.getArguments();
80                 boolean bServiceConnectionFound = false;
81                 boolean bIntentFound = false;
82                 for (Object arg : args) {
83                     if (arg instanceof ServiceConnection) {
84                         synchronized (arg) {
85                             bServiceConnectionFound = true;
86                             ((ServiceConnection) arg).onServiceConnected(null,
87                                     (IBinder) mMockImsMedia);
88                             arg.notify();
89                         }
90                     } else if (arg instanceof Intent) {
91                         bIntentFound = true;
92                         Intent intent = (Intent) arg;
93                         assertEquals(intent.getAction(), IImsMedia.class.getName());
94                         assertEquals(intent.getComponent(), ComponentName.createRelative(
95                                 ImsMediaManager.MEDIA_SERVICE_PACKAGE,
96                                 ImsMediaManager.MEDIA_SERVICE_CLASS));
97                     }
98                 }
99 
100                 assertEquals(bServiceConnectionFound, true);
101                 assertEquals(bIntentFound, true);
102                 return true;
103             }
104         }).when(mMockContext).bindService(any(Intent.class), any(ServiceConnection.class),
105                 eq(Context.BIND_AUTO_CREATE));
106 
107         doAnswer(new Answer() {
108             @Override
109             public Object answer(InvocationOnMock invocation) throws Throwable {
110                 Object[] args = invocation.getArguments();
111                 for (Object arg : args) {
112                     if (arg instanceof ServiceConnection) {
113                         synchronized (arg) {
114                             ((ServiceConnection) arg).onServiceDisconnected(null);
115                             arg.notify();
116                         }
117                     }
118                 }
119                 return null;
120             }
121         }).when(mMockContext).unbindService(any(ServiceConnection.class));
122     }
123 
124     @Test
testServiceBindingAndUnbinding()125     public void testServiceBindingAndUnbinding() {
126         ImsMediaManager imsMediaManager =
127                 new ImsMediaManager(mMockContext, mExecutor, mMockConnectedCallback);
128 
129         synchronized (mLock) {
130             try {
131                 //Wait for connection callback
132                 Thread.sleep(1000);
133 
134                 //Unbind from service
135                 imsMediaManager.release();
136 
137                 //Wait for disconnect callback
138                 Thread.sleep(1000);
139             } catch (Exception e) {
140                 fail(e.getMessage());
141             }
142         }
143 
144         verify(mMockConnectedCallback).onConnected();
145         verify(mMockConnectedCallback).onDisconnected();
146     }
147 
148     @Test
testOpenAndCloseSession()149     public void testOpenAndCloseSession() {
150         ImsMediaManager imsMediaManager =
151                 new ImsMediaManager(mMockContext, mExecutor, mMockConnectedCallback);
152 
153         synchronized (mLock) {
154             try {
155                 //Wait for connection callback
156                 Thread.sleep(1000);
157 
158                 imsMediaManager.openSession(mMockRtpSocket, mMockRtcpSocket,
159                         ImsMediaSession.SESSION_TYPE_AUDIO, mMockRtpConfig, mExecutor,
160                         mMockSessionCallback);
161 
162                 imsMediaManager.closeSession(mMockImsMediaSession);
163 
164                 //Unbind from service
165                 imsMediaManager.release();
166 
167                 //Wait for disconnect callback
168                 Thread.sleep(1000);
169 
170             } catch (Exception e) {
171                 fail(e.getMessage());
172             }
173         }
174 
175         try {
176             verify(mMockConnectedCallback).onConnected();
177             verify(mMockImsMedia, times(2)).transact(anyInt(), any(Parcel.class), any(), anyInt());
178             verify(mMockConnectedCallback).onDisconnected();
179         } catch (Exception e) {
180             fail(e.getMessage());
181         }
182     }
183 
184     public abstract static class IMediaStubBase implements IBinder {
185     }
186 
187     public abstract static class IMediaStubTest extends IMediaStubBase implements IInterface {
transact(int code, Parcel data, Parcel reply, int flags)188         public abstract boolean transact(int code, Parcel data, Parcel reply, int flags);
189     }
190 }
191