blob: b88c784bed5d671d573208264f848bcce6d9689d [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;
25import static org.mockito.Mockito.times;
26import static org.mockito.Mockito.verify;
Hugo Benichicbb13672017-04-24 11:35:06 +090027import static org.mockito.Mockito.when;
28
29import android.os.Handler;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090030import android.os.HandlerThread;
Hugo Benichicbb13672017-04-24 11:35:06 +090031import android.os.Looper;
32import android.os.Message;
Hugo Benichicbb13672017-04-24 11:35:06 +090033import android.content.Context;
34import android.content.ContentResolver;
35import android.net.nsd.NsdManager;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090036import android.net.nsd.NsdServiceInfo;
Hugo Benichi1fac3192017-04-24 16:19:58 +090037import com.android.server.NsdService.DaemonConnection;
38import com.android.server.NsdService.DaemonConnectionSupplier;
39import com.android.server.NsdService.NativeCallbackReceiver;
Hugo Benichicbb13672017-04-24 11:35:06 +090040import android.support.test.filters.SmallTest;
41import android.support.test.runner.AndroidJUnit4;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090042import org.junit.After;
Hugo Benichicbb13672017-04-24 11:35:06 +090043import org.junit.Before;
44import org.junit.Test;
45import org.junit.runner.RunWith;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090046import org.mockito.ArgumentCaptor;
Hugo Benichicbb13672017-04-24 11:35:06 +090047import org.mockito.Mock;
48import org.mockito.MockitoAnnotations;
49
50// TODOs:
Hugo Benichicbb13672017-04-24 11:35:06 +090051// - test client can send requests and receive replies
52// - test NSD_ON ENABLE/DISABLED listening
53@RunWith(AndroidJUnit4.class)
54@SmallTest
55public class NsdServiceTest {
56
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090057 static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
58
59 long mTimeoutMs = 100; // non-final so that tests can adjust the value.
60
Hugo Benichicbb13672017-04-24 11:35:06 +090061 @Mock Context mContext;
62 @Mock ContentResolver mResolver;
63 @Mock NsdService.NsdSettings mSettings;
Hugo Benichi1fac3192017-04-24 16:19:58 +090064 @Mock DaemonConnection mDaemon;
65 NativeCallbackReceiver mDaemonCallback;
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090066 HandlerThread mThread;
Hugo Benichicbb13672017-04-24 11:35:06 +090067 TestHandler mHandler;
68
69 @Before
70 public void setUp() throws Exception {
71 MockitoAnnotations.initMocks(this);
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090072 mThread = new HandlerThread("mock-service-handler");
73 mThread.start();
74 mHandler = new TestHandler(mThread.getLooper());
Hugo Benichicbb13672017-04-24 11:35:06 +090075 when(mContext.getContentResolver()).thenReturn(mResolver);
76 }
77
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090078 @After
79 public void tearDown() throws Exception {
Hugo Benichid9e55192017-09-26 14:51:11 +090080 if (mThread != null) {
81 mThread.quit();
82 mThread = null;
83 }
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090084 }
85
Hugo Benichicbb13672017-04-24 11:35:06 +090086 @Test
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090087 public void testClientsCanConnectAndDisconnect() {
Hugo Benichi1fac3192017-04-24 16:19:58 +090088 when(mSettings.isEnabled()).thenReturn(true);
89
Hugo Benichicbb13672017-04-24 11:35:06 +090090 NsdService service = makeService();
Hugo Benichi1fac3192017-04-24 16:19:58 +090091
Hugo Benichicbb13672017-04-24 11:35:06 +090092 NsdManager client1 = connectClient(service);
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090093 verify(mDaemon, timeout(100).times(1)).start();
Hugo Benichi1fac3192017-04-24 16:19:58 +090094
Hugo Benichicbb13672017-04-24 11:35:06 +090095 NsdManager client2 = connectClient(service);
96
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090097 client1.disconnect();
98 client2.disconnect();
99
100 verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
Hugo Benichie062ae02017-07-31 20:35:58 +0900101
102 client1.disconnect();
103 client2.disconnect();
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900104 }
105
106 @Test
107 public void testClientRequestsAreGCedAtDisconnection() {
108 when(mSettings.isEnabled()).thenReturn(true);
109 when(mDaemon.execute(any())).thenReturn(true);
110
111 NsdService service = makeService();
112 NsdManager client = connectClient(service);
113
114 verify(mDaemon, timeout(100).times(1)).start();
115
116 NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
117 request.setPort(2201);
118
119 // Client registration request
120 NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
121 client.registerService(request, PROTOCOL, listener1);
122 verifyDaemonCommand("register 2 a_name a_type 2201");
123
124 // Client discovery request
125 NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
126 client.discoverServices("a_type", PROTOCOL, listener2);
127 verifyDaemonCommand("discover 3 a_type");
128
129 // Client resolve request
130 NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
131 client.resolveService(request, listener3);
132 verifyDaemonCommand("resolve 4 a_name a_type local.");
133
134 // Client disconnects
135 client.disconnect();
136 verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
137
138 // checks that request are cleaned
139 verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
Hugo Benichie062ae02017-07-31 20:35:58 +0900140
141 client.disconnect();
Hugo Benichicbb13672017-04-24 11:35:06 +0900142 }
143
144 NsdService makeService() {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900145 DaemonConnectionSupplier supplier = (callback) -> {
146 mDaemonCallback = callback;
147 return mDaemon;
148 };
149 NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
150 verify(mDaemon, never()).execute(any(String.class));
151 return service;
Hugo Benichicbb13672017-04-24 11:35:06 +0900152 }
153
154 NsdManager connectClient(NsdService service) {
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900155 return new NsdManager(mContext, service);
156 }
157
158 void verifyDaemonCommands(String... wants) {
159 verifyDaemonCommand(String.join(" ", wants), wants.length);
160 }
161
162 void verifyDaemonCommand(String want) {
163 verifyDaemonCommand(want, 1);
164 }
165
166 void verifyDaemonCommand(String want, int n) {
167 ArgumentCaptor<Object> argumentsCaptor = ArgumentCaptor.forClass(Object.class);
168 verify(mDaemon, timeout(mTimeoutMs).times(n)).execute(argumentsCaptor.capture());
169 String got = "";
170 for (Object o : argumentsCaptor.getAllValues()) {
171 got += o + " ";
172 }
173 assertEquals(want, got.trim());
174 // rearm deamon for next command verification
175 reset(mDaemon);
176 when(mDaemon.execute(any())).thenReturn(true);
Hugo Benichicbb13672017-04-24 11:35:06 +0900177 }
178
179 public static class TestHandler extends Handler {
180 public Message lastMessage;
181
182 TestHandler(Looper looper) {
183 super(looper);
184 }
185
186 @Override
187 public void handleMessage(Message msg) {
188 lastMessage = obtainMessage();
189 lastMessage.copyFrom(msg);
190 }
191 }
192}