1package com.android.bluetooth.tests;
2
3import java.io.IOException;
4import java.util.concurrent.CountDownLatch;
5
6import javax.obex.ClientSession;
7import javax.obex.HeaderSet;
8import javax.obex.Operation;
9import javax.obex.ResponseCodes;
10import javax.obex.ServerSession;
11
12import com.android.bluetooth.BluetoothObexTransport;
13import com.android.bluetooth.sdp.SdpManager;
14
15import android.annotation.TargetApi;
16import android.bluetooth.BluetoothAdapter;
17import android.bluetooth.BluetoothDevice;
18import android.bluetooth.BluetoothServerSocket;
19import android.bluetooth.BluetoothSocket;
20import android.bluetooth.BluetoothUuid;
21import android.graphics.Paint.Join;
22import android.os.Build;
23import android.test.AndroidTestCase;
24import android.util.Log;
25
26import junit.framework.Assert;
27
28@TargetApi(Build.VERSION_CODES.KITKAT)
29public class SdpManagerTest extends AndroidTestCase {
30
31    protected static String TAG = "SdpManagerTest";
32    protected static final boolean D = true;
33
34    public static final int SDP_RECORD_COUNT = 12; /* Maximum number of records to create */
35    public static final int SDP_ITERATIONS = 2000;
36
37    public static final String SDP_SERVER_NAME = "SDP test server";
38    public static final String SDP_CLIENT_NAME = "SDP test client";
39
40    public static final long SDP_FEATURES   = 0x87654321L;  /* 32 bit */
41    public static final int  SDP_MSG_TYPES  = 0xf1;         /*  8 bit */
42    public static final int  SDP_MAS_ID     = 0xCA;         /*  8 bit */
43    public static final int  SDP_VERSION    = 0xF0C0;       /* 16 bit */
44    public static final int  SDP_REPOS      = 0xCf;         /*  8 bit */
45
46    SdpManager mManager = null;
47
48    public void testSdpRemove() {
49        BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
50        if(bt == null) {
51            Log.e(TAG,"No Bluetooth Device!");
52            assertTrue(false);
53        }
54        BluetoothTestUtils.enableBt(bt);
55        mManager = SdpManager.getDefaultManager();
56        addRemoveRecords(SDP_RECORD_COUNT);
57    }
58
59    public void testSdpAdd() {
60        BluetoothAdapter bt = BluetoothAdapter.getDefaultAdapter();
61        if(bt == null) {
62            Log.e(TAG,"No Bluetooth Device!");
63            assertTrue(false);
64        }
65        BluetoothTestUtils.enableBt(bt);
66        mManager = SdpManager.getDefaultManager();
67
68        int handles[] = new int[SDP_RECORD_COUNT];
69        addRecords(handles, 1);
70
71        try {
72            Log.i(TAG, "\n\n\nRecords added - waiting 5 minutes...\n\n\n");
73            Thread.sleep(300000);
74        } catch (InterruptedException e) {
75            Log.e(TAG, "Interrupted", e);
76        }
77        Log.i(TAG, "All done - over and out!;-)");
78    }
79
80
81    private void addRecords(int handles[], int iteration) {
82        /* Create the records */
83        int record_id = -1; /* first index is 0 */
84        int count = handles.length-1; // Break condition
85        for(int c = 0; ; c++) {
86            Log.i(TAG, "Create c=" + c);
87            handles[++record_id] = mManager.createMapMasRecord(SDP_SERVER_NAME,
88                    SDP_MAS_ID, record_id, record_id+iteration, SDP_VERSION,
89                    SDP_MSG_TYPES, (int)SDP_FEATURES);
90            Log.i(TAG, "  Added record_handle=" + handles[record_id]);
91            assertTrue(handles[record_id]>=0);
92            if(record_id == count) break;
93
94            handles[++record_id] = mManager.createMapMnsRecord(SDP_SERVER_NAME,
95                    record_id, record_id+iteration, SDP_VERSION,
96                    (int)SDP_FEATURES);
97            Log.i(TAG, "  Added record_handle=" + handles[record_id]);
98            assertTrue(handles[record_id]>=0);
99            if(record_id == count) break;
100
101            handles[++record_id] = mManager.createOppOpsRecord(SDP_SERVER_NAME,
102                    record_id, record_id+iteration, SDP_VERSION, SdpManager.OPP_FORMAT_ALL);
103            Log.i(TAG, "  Added record_handle=" + handles[record_id]);
104            assertTrue(handles[record_id]>=0);
105            if(record_id == count) break;
106
107            handles[++record_id] = mManager.createPbapPseRecord(SDP_SERVER_NAME,
108                    record_id, record_id+iteration, SDP_VERSION, SDP_REPOS,
109                    (int)SDP_FEATURES);
110            Log.i(TAG, "  Added record_handle=" + handles[record_id]);
111            assertTrue(handles[record_id]>=0);
112            if(record_id == count) break;
113
114            handles[++record_id] = mManager.createSapsRecord(SDP_SERVER_NAME,
115                    record_id, SDP_VERSION);
116            Log.i(TAG, "  Added record_handle=" + handles[record_id]);
117            assertTrue(handles[record_id]>=0);
118            if (record_id == count) break;
119        }
120    }
121
122    void removeRecords(int handles[], int record_count) {
123        int record_id;
124        /* Remove the records */
125        for(record_id = 0; record_id < record_count; record_id++) {
126            Log.i(TAG, "remove id=" + record_id);
127            assertTrue(mManager.removeSdpRecord(handles[record_id]));
128        }
129    }
130
131    private void addRemoveRecords(int count) {
132        int record_count = count;
133        int handles[] = new int[record_count];
134        int iteration;
135        for(iteration = 0; iteration < SDP_ITERATIONS; iteration++) {
136
137            addRecords(handles, iteration);
138
139            try {
140                Thread.sleep(500);
141            } catch (InterruptedException e) {
142                Log.e(TAG, "Interrupted", e);
143            }
144
145            removeRecords(handles, record_count);
146        }
147    }
148
149    /**
150     * Client side of SdpSearch test
151     * This test will:
152     *  1) Create a connection to a test server
153     *  2) Create a number of SDP records
154     *  3) Request the test server to read the records
155     *  4) Remove the records
156     *  5) Iterate over 2) to 4) SDP_ITERATIONS number of times
157     */
158    public void testSdpSearchClient() {
159        int count = SDP_RECORD_COUNT;
160        int record_count = count;
161        int handles[] = new int[record_count];
162        int iteration;
163        final BluetoothSocket clientSock;
164        final ClientSession mClientSession;
165        final String[] uuids = {BluetoothUuid.MAS.toString(),
166                                BluetoothUuid.MNS.toString(),
167                                BluetoothUuid.PBAP_PSE.toString(),
168                                BluetoothUuid.ObexObjectPush.toString(),
169                                BluetoothUuid.SAP.toString()};
170        final String uuids_str;
171        final StringBuilder sb = new StringBuilder(uuids.length*2-1);
172        for(String str : uuids) {
173            sb.append(str).append(";");
174        }
175        uuids_str = sb.toString();
176
177        try {
178            /* This will turn on BT and connect */
179            clientSock = ObexTest.connectClientSocket(BluetoothSocket.TYPE_L2CAP, true, mContext);
180            mManager = SdpManager.getDefaultManager();
181            BluetoothObexTransport clientTransport = new BluetoothObexTransport(clientSock);
182            mClientSession = new ClientSession(clientTransport);
183            { // Connect
184                HeaderSet reqHeaders = new HeaderSet();
185                reqHeaders.setHeader(TestSequencer.STEP_INDEX_HEADER, (long)0);
186                HeaderSet response = mClientSession.connect(reqHeaders);
187                assertEquals(response.responseCode, ResponseCodes.OBEX_HTTP_OK);
188            }
189
190            for(iteration = 0; iteration < SDP_ITERATIONS; iteration++) {
191                // Add the records
192                addRecords(handles, iteration);
193
194                { // get operation to trigger SDP search on peer device
195                    HeaderSet reqHeaders = new HeaderSet();
196                    reqHeaders.setHeader(TestSequencer.STEP_INDEX_HEADER, (long)iteration);
197                    reqHeaders.setHeader(HeaderSet.COUNT, (long)count);
198                    reqHeaders.setHeader(HeaderSet.NAME, uuids_str);
199                    Operation op = mClientSession.get(reqHeaders);
200                    op.noBodyHeader();
201                    int response = op.getResponseCode();
202                    op.close();
203                    assertEquals(response, ResponseCodes.OBEX_HTTP_OK);
204                }
205
206                // Cleanup
207                removeRecords(handles, record_count);
208            }
209            { // disconnect to end test
210                HeaderSet reqHeaders = new HeaderSet();
211                reqHeaders.setHeader(TestSequencer.STEP_INDEX_HEADER, 0L); // signals end of test
212                HeaderSet response = mClientSession.disconnect(reqHeaders);
213                assertEquals(response.responseCode, ResponseCodes.OBEX_HTTP_OK);
214            }
215        } catch (IOException e) {
216            Log.e(TAG,"IOException in testSdpSearch",e);
217        }
218
219    }
220
221    /**
222     * Server side of SdpSearch test
223     * This test will start a
224     *  1) Create a connection to a test server
225     *  2) Create a number of SDP records
226     *  3) Request the test server to read the records
227     *  4) Remove the records
228     *  5) Iterate over 2) to 4) SDP_ITERATIONS number of times
229     */
230    public void testSdpSearchServer() {
231        mManager = SdpManager.getDefaultManager();
232        try {
233            CountDownLatch stopLatch = new CountDownLatch(1);
234            BluetoothDevice clientDevice;
235            /* This will turn on BT and create a server socket on which accept can be called. */
236            BluetoothServerSocket serverSocket=ObexTest.createServerSocket(BluetoothSocket.TYPE_L2CAP, true);
237            mManager = SdpManager.getDefaultManager();
238
239            Log.i(TAG, "Waiting for client to connect...");
240            BluetoothSocket socket = serverSocket.accept();
241            Log.i(TAG, "Client connected...");
242
243            BluetoothObexTransport serverTransport = new BluetoothObexTransport(socket);
244            clientDevice = socket.getRemoteDevice();
245            ServerSession serverSession = new ServerSession(serverTransport,
246                    new SdpManagerTestServer(stopLatch, mContext, clientDevice), null);
247
248            boolean interrupted = false;
249            do {
250                try {
251                    interrupted = false;
252                    Log.i(TAG,"Waiting for stopLatch signal...");
253                    stopLatch.await();
254                } catch (InterruptedException e) {
255                    Log.w(TAG,e);
256                    interrupted = true;
257                }
258            } while (interrupted == true);
259            Log.i(TAG,"stopLatch signal received closing down...");
260            /* Give a little time to transfer the disconnect response before closing the socket */
261            try {
262                Thread.sleep(1000);
263            } catch (InterruptedException e) {}
264
265            // Cleanup
266            serverSession.close();
267            socket.close();
268            serverSocket.close();
269        } catch (IOException e) {
270            Log.e(TAG, "IOException", e);
271        }
272        Log.i(TAG, "\n\n\nTest done - please fetch logs within 30 seconds...\n\n\n");
273        try {
274            Thread.sleep(30000);
275        } catch (InterruptedException e) {}
276        Log.i(TAG, "Test done.");
277}
278
279
280/*
281 * Tests we need:
282 * - Single threaded test:
283 *      * Add a large number of records and remove them again.
284 * - Multi-threaded rests:
285 *      * Let two or more threads perform the test above, each tasking a n-threads fraction of the RECORD_COUNT
286 *
287 * - Client/server
288 *      * Create a control connection - it might be easiest to use OBEX.
289 *      1) Add a number of records
290 *      2) Trigger read of the records
291 *      3) Remove the records
292 *      4) Validate they are gone (if they are not cached)
293 *      5) Multi thread the test on both sides?
294 *  */
295
296}
297