blob: a90fa6882c257bea12f6129c8932dff162083f2b [file] [log] [blame]
Hugo Benichicbb13672017-04-24 11:35:06 +09001/*
2 * Copyright (C) 2017 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
17package com.android.server;
18
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090019import static org.junit.Assert.assertEquals;
Hugo Benichi1fac3192017-04-24 16:19:58 +090020import static org.mockito.Mockito.any;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090021import static org.mockito.Mockito.mock;
Hugo Benichi1fac3192017-04-24 16:19:58 +090022import static org.mockito.Mockito.never;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090023import static org.mockito.Mockito.reset;
Hugo Benichi1fac3192017-04-24 16:19:58 +090024import static org.mockito.Mockito.timeout;
Hugo Benichi1fac3192017-04-24 16:19:58 +090025import static org.mockito.Mockito.verify;
Hugo Benichicbb13672017-04-24 11:35:06 +090026import static org.mockito.Mockito.when;
27
Brett Chabot1ae2aa62019-03-04 14:14:56 -080028import android.content.ContentResolver;
29import android.content.Context;
30import android.net.nsd.NsdManager;
31import android.net.nsd.NsdServiceInfo;
Hugo Benichicbb13672017-04-24 11:35:06 +090032import android.os.Handler;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090033import android.os.HandlerThread;
Hugo Benichicbb13672017-04-24 11:35:06 +090034import android.os.Looper;
35import android.os.Message;
Brett Chabot1ae2aa62019-03-04 14:14:56 -080036
37import androidx.test.filters.SmallTest;
38import androidx.test.runner.AndroidJUnit4;
39
Hugo Benichi1fac3192017-04-24 16:19:58 +090040import com.android.server.NsdService.DaemonConnection;
41import com.android.server.NsdService.DaemonConnectionSupplier;
42import com.android.server.NsdService.NativeCallbackReceiver;
Brett Chabot1ae2aa62019-03-04 14:14:56 -080043
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090044import org.junit.After;
Hugo Benichicbb13672017-04-24 11:35:06 +090045import org.junit.Before;
46import org.junit.Test;
47import org.junit.runner.RunWith;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090048import org.mockito.ArgumentCaptor;
Hugo Benichicbb13672017-04-24 11:35:06 +090049import org.mockito.Mock;
50import org.mockito.MockitoAnnotations;
51
52// TODOs:
Hugo Benichicbb13672017-04-24 11:35:06 +090053// - test client can send requests and receive replies
54// - test NSD_ON ENABLE/DISABLED listening
55@RunWith(AndroidJUnit4.class)
56@SmallTest
57public class NsdServiceTest {
58
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090059 static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
60
61 long mTimeoutMs = 100; // non-final so that tests can adjust the value.
62
Hugo Benichicbb13672017-04-24 11:35:06 +090063 @Mock Context mContext;
64 @Mock ContentResolver mResolver;
65 @Mock NsdService.NsdSettings mSettings;
Hugo Benichi1fac3192017-04-24 16:19:58 +090066 @Mock DaemonConnection mDaemon;
67 NativeCallbackReceiver mDaemonCallback;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090068 HandlerThread mThread;
Hugo Benichicbb13672017-04-24 11:35:06 +090069 TestHandler mHandler;
70
71 @Before
72 public void setUp() throws Exception {
73 MockitoAnnotations.initMocks(this);
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090074 mThread = new HandlerThread("mock-service-handler");
75 mThread.start();
76 mHandler = new TestHandler(mThread.getLooper());
Hugo Benichicbb13672017-04-24 11:35:06 +090077 when(mContext.getContentResolver()).thenReturn(mResolver);
78 }
79
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090080 @After
81 public void tearDown() throws Exception {
Hugo Benichid9e55192017-09-26 14:51:11 +090082 if (mThread != null) {
83 mThread.quit();
84 mThread = null;
85 }
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090086 }
87
Hugo Benichicbb13672017-04-24 11:35:06 +090088 @Test
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090089 public void testClientsCanConnectAndDisconnect() {
Hugo Benichi1fac3192017-04-24 16:19:58 +090090 when(mSettings.isEnabled()).thenReturn(true);
91
Hugo Benichicbb13672017-04-24 11:35:06 +090092 NsdService service = makeService();
Hugo Benichi1fac3192017-04-24 16:19:58 +090093
Hugo Benichicbb13672017-04-24 11:35:06 +090094 NsdManager client1 = connectClient(service);
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090095 verify(mDaemon, timeout(100).times(1)).start();
Hugo Benichi1fac3192017-04-24 16:19:58 +090096
Hugo Benichicbb13672017-04-24 11:35:06 +090097 NsdManager client2 = connectClient(service);
98
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090099 client1.disconnect();
100 client2.disconnect();
101
102 verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
Hugo Benichie062ae02017-07-31 20:35:58 +0900103
104 client1.disconnect();
105 client2.disconnect();
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900106 }
107
108 @Test
109 public void testClientRequestsAreGCedAtDisconnection() {
110 when(mSettings.isEnabled()).thenReturn(true);
111 when(mDaemon.execute(any())).thenReturn(true);
112
113 NsdService service = makeService();
114 NsdManager client = connectClient(service);
115
116 verify(mDaemon, timeout(100).times(1)).start();
117
118 NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
119 request.setPort(2201);
120
121 // Client registration request
122 NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
123 client.registerService(request, PROTOCOL, listener1);
124 verifyDaemonCommand("register 2 a_name a_type 2201");
125
126 // Client discovery request
127 NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
128 client.discoverServices("a_type", PROTOCOL, listener2);
129 verifyDaemonCommand("discover 3 a_type");
130
131 // Client resolve request
132 NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
133 client.resolveService(request, listener3);
134 verifyDaemonCommand("resolve 4 a_name a_type local.");
135
136 // Client disconnects
137 client.disconnect();
138 verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
139
140 // checks that request are cleaned
141 verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
Hugo Benichie062ae02017-07-31 20:35:58 +0900142
143 client.disconnect();
Hugo Benichicbb13672017-04-24 11:35:06 +0900144 }
145
146 NsdService makeService() {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900147 DaemonConnectionSupplier supplier = (callback) -> {
148 mDaemonCallback = callback;
149 return mDaemon;
150 };
151 NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
152 verify(mDaemon, never()).execute(any(String.class));
153 return service;
Hugo Benichicbb13672017-04-24 11:35:06 +0900154 }
155
156 NsdManager connectClient(NsdService service) {
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900157 return new NsdManager(mContext, service);
158 }
159
160 void verifyDaemonCommands(String... wants) {
161 verifyDaemonCommand(String.join(" ", wants), wants.length);
162 }
163
164 void verifyDaemonCommand(String want) {
165 verifyDaemonCommand(want, 1);
166 }
167
168 void verifyDaemonCommand(String want, int n) {
169 ArgumentCaptor<Object> argumentsCaptor = ArgumentCaptor.forClass(Object.class);
170 verify(mDaemon, timeout(mTimeoutMs).times(n)).execute(argumentsCaptor.capture());
171 String got = "";
172 for (Object o : argumentsCaptor.getAllValues()) {
173 got += o + " ";
174 }
175 assertEquals(want, got.trim());
176 // rearm deamon for next command verification
177 reset(mDaemon);
178 when(mDaemon.execute(any())).thenReturn(true);
Hugo Benichicbb13672017-04-24 11:35:06 +0900179 }
180
181 public static class TestHandler extends Handler {
182 public Message lastMessage;
183
184 TestHandler(Looper looper) {
185 super(looper);
186 }
187
188 @Override
189 public void handleMessage(Message msg) {
190 lastMessage = obtainMessage();
191 lastMessage.copyFrom(msg);
192 }
193 }
194}