blob: 68cb251cf87e9e501bca563917bc5748df39f12d [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 {
80 mThread.quit();
81 }
82
Hugo Benichicbb13672017-04-24 11:35:06 +090083 @Test
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090084 public void testClientsCanConnectAndDisconnect() {
Hugo Benichi1fac3192017-04-24 16:19:58 +090085 when(mSettings.isEnabled()).thenReturn(true);
86
Hugo Benichicbb13672017-04-24 11:35:06 +090087 NsdService service = makeService();
Hugo Benichi1fac3192017-04-24 16:19:58 +090088
Hugo Benichicbb13672017-04-24 11:35:06 +090089 NsdManager client1 = connectClient(service);
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090090 verify(mDaemon, timeout(100).times(1)).start();
Hugo Benichi1fac3192017-04-24 16:19:58 +090091
Hugo Benichicbb13672017-04-24 11:35:06 +090092 NsdManager client2 = connectClient(service);
93
Hugo Benichiab5bdbf2017-04-28 15:31:10 +090094 client1.disconnect();
95 client2.disconnect();
96
97 verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
98 }
99
100 @Test
101 public void testClientRequestsAreGCedAtDisconnection() {
102 when(mSettings.isEnabled()).thenReturn(true);
103 when(mDaemon.execute(any())).thenReturn(true);
104
105 NsdService service = makeService();
106 NsdManager client = connectClient(service);
107
108 verify(mDaemon, timeout(100).times(1)).start();
109
110 NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
111 request.setPort(2201);
112
113 // Client registration request
114 NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
115 client.registerService(request, PROTOCOL, listener1);
116 verifyDaemonCommand("register 2 a_name a_type 2201");
117
118 // Client discovery request
119 NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
120 client.discoverServices("a_type", PROTOCOL, listener2);
121 verifyDaemonCommand("discover 3 a_type");
122
123 // Client resolve request
124 NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
125 client.resolveService(request, listener3);
126 verifyDaemonCommand("resolve 4 a_name a_type local.");
127
128 // Client disconnects
129 client.disconnect();
130 verify(mDaemon, timeout(mTimeoutMs).times(1)).stop();
131
132 // checks that request are cleaned
133 verifyDaemonCommands("stop-register 2", "stop-discover 3", "stop-resolve 4");
Hugo Benichicbb13672017-04-24 11:35:06 +0900134 }
135
136 NsdService makeService() {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900137 DaemonConnectionSupplier supplier = (callback) -> {
138 mDaemonCallback = callback;
139 return mDaemon;
140 };
141 NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
142 verify(mDaemon, never()).execute(any(String.class));
143 return service;
Hugo Benichicbb13672017-04-24 11:35:06 +0900144 }
145
146 NsdManager connectClient(NsdService service) {
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900147 return new NsdManager(mContext, service);
148 }
149
150 void verifyDaemonCommands(String... wants) {
151 verifyDaemonCommand(String.join(" ", wants), wants.length);
152 }
153
154 void verifyDaemonCommand(String want) {
155 verifyDaemonCommand(want, 1);
156 }
157
158 void verifyDaemonCommand(String want, int n) {
159 ArgumentCaptor<Object> argumentsCaptor = ArgumentCaptor.forClass(Object.class);
160 verify(mDaemon, timeout(mTimeoutMs).times(n)).execute(argumentsCaptor.capture());
161 String got = "";
162 for (Object o : argumentsCaptor.getAllValues()) {
163 got += o + " ";
164 }
165 assertEquals(want, got.trim());
166 // rearm deamon for next command verification
167 reset(mDaemon);
168 when(mDaemon.execute(any())).thenReturn(true);
Hugo Benichicbb13672017-04-24 11:35:06 +0900169 }
170
171 public static class TestHandler extends Handler {
172 public Message lastMessage;
173
174 TestHandler(Looper looper) {
175 super(looper);
176 }
177
178 @Override
179 public void handleMessage(Message msg) {
180 lastMessage = obtainMessage();
181 lastMessage.copyFrom(msg);
182 }
183 }
184}