1/*
2 * Copyright (C) 2011 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.nfc.snep;
18
19import com.android.nfc.MockLlcpSocket;
20
21import android.nfc.NdefMessage;
22import android.nfc.NdefRecord;
23import android.test.AndroidTestCase;
24import android.util.Log;
25
26import java.io.IOException;
27
28/**
29 * Tests the SNEP cleint/server interfaces using a mock LLCP socket.
30 */
31public class SnepBasicTests extends AndroidTestCase {
32    private static final String TAG = "snepBasicTests";
33    private static final int MIU = 250;
34    private static final int ACCEPTABLE_LENGTH = 2*1024;
35
36    public void testGetSmallNdef() throws IOException {
37        MockLlcpSocket clientSocket = new MockLlcpSocket();
38        MockLlcpSocket serverSocket = new MockLlcpSocket();
39        MockLlcpSocket.bind(clientSocket, serverSocket);
40
41        final SnepMessenger client = new SnepMessenger(true, clientSocket, MIU);
42        final SnepMessenger server = new SnepMessenger(false, serverSocket, MIU);
43
44        new Thread() {
45            @Override
46            public void run() {
47                try {
48                    SnepServer.handleRequest(server, mCallback);
49                } catch (Exception e) {
50                    Log.e(TAG, "error getting message", e);
51                }
52            };
53        }.start();
54
55        SnepMessage response = null;
56        try {
57            client.sendMessage(SnepMessage.getGetRequest(ACCEPTABLE_LENGTH, getSmallNdef()));
58            response = client.getMessage();
59        } catch (SnepException e) {
60            throw new IOException("Failed to retrieve SNEP message", e);
61        }
62
63        assertNotNull(response);
64        assertEquals(SnepMessage.RESPONSE_SUCCESS, response.getField());
65    }
66
67    public void testGetLargeNdef() throws IOException {
68        MockLlcpSocket clientSocket = new MockLlcpSocket();
69        MockLlcpSocket serverSocket = new MockLlcpSocket();
70        MockLlcpSocket.bind(clientSocket, serverSocket);
71
72        final SnepMessenger client = new SnepMessenger(true, clientSocket, MIU);
73        final SnepMessenger server = new SnepMessenger(false, serverSocket, MIU);
74
75        new Thread() {
76            @Override
77            public void run() {
78                try {
79                    SnepServer.handleRequest(server, mCallback);
80                } catch (Exception e) {
81                    Log.e(TAG, "error getting message", e);
82                }
83            };
84        }.start();
85
86        SnepMessage response = null;
87        try {
88            client.sendMessage(SnepMessage.getGetRequest(ACCEPTABLE_LENGTH, getNdef(900)));
89            response = client.getMessage();
90        } catch (SnepException e) {
91            throw new IOException("Failed to retrieve SNEP message", e);
92        }
93
94        assertNotNull(response);
95        assertEquals(SnepMessage.RESPONSE_SUCCESS, response.getField());
96    }
97
98    public void testGetExcessiveNdef() throws IOException {
99        MockLlcpSocket clientSocket = new MockLlcpSocket();
100        MockLlcpSocket serverSocket = new MockLlcpSocket();
101        MockLlcpSocket.bind(clientSocket, serverSocket);
102
103        final SnepMessenger client = new SnepMessenger(true, clientSocket, MIU);
104        final SnepMessenger server = new SnepMessenger(false, serverSocket, MIU);
105
106        new Thread() {
107            @Override
108            public void run() {
109                try {
110                    SnepServer.handleRequest(server, mCallback);
111                } catch (Exception e) {
112                    Log.e(TAG, "error getting message", e);
113                }
114            };
115        }.start();
116
117        SnepMessage response = null;
118        try {
119            client.sendMessage(SnepMessage.getGetRequest(10, getSmallNdef()));
120            response = client.getMessage();
121        } catch (SnepException e) {
122            throw new IOException("Failed to retrieve SNEP message", e);
123        }
124
125        assertNotNull(response);
126        assertEquals(SnepMessage.RESPONSE_EXCESS_DATA, response.getField());
127    }
128
129    public void testPutSmallNdef() throws IOException {
130        MockLlcpSocket clientSocket = new MockLlcpSocket();
131        MockLlcpSocket serverSocket = new MockLlcpSocket();
132        MockLlcpSocket.bind(clientSocket, serverSocket);
133
134        final SnepMessenger client = new SnepMessenger(true, clientSocket, MIU);
135        final SnepMessenger server = new SnepMessenger(false, serverSocket, MIU);
136
137        new Thread() {
138            @Override
139            public void run() {
140                try {
141                    SnepServer.handleRequest(server, mCallback);
142                } catch (Exception e) {
143                    Log.e(TAG, "error getting message", e);
144                }
145            };
146        }.start();
147
148        SnepMessage response = null;
149        try {
150            client.sendMessage(SnepMessage.getPutRequest(getSmallNdef()));
151            response = client.getMessage();
152        } catch (SnepException e) {
153            throw new IOException("Failed to retrieve SNEP message", e);
154        }
155
156        assertNotNull(response);
157        assertEquals(SnepMessage.RESPONSE_SUCCESS, response.getField());
158    }
159
160    public void testPutLargeNdef() throws IOException {
161        MockLlcpSocket clientSocket = new MockLlcpSocket();
162        MockLlcpSocket serverSocket = new MockLlcpSocket();
163        MockLlcpSocket.bind(clientSocket, serverSocket);
164
165        final SnepMessenger client = new SnepMessenger(true, clientSocket, MIU);
166        final SnepMessenger server = new SnepMessenger(false, serverSocket, MIU);
167
168        new Thread() {
169            @Override
170            public void run() {
171                try {
172                    SnepServer.handleRequest(server, mCallback);
173                } catch (Exception e) {
174                    Log.e(TAG, "error getting message", e);
175                }
176            };
177        }.start();
178
179        SnepMessage response = null;
180        try {
181            client.sendMessage(SnepMessage.getPutRequest(getNdef(900)));
182            response = client.getMessage();
183        } catch (SnepException e) {
184            throw new IOException("Failed to retrieve SNEP message", e);
185        }
186
187        assertNotNull(response);
188        assertEquals(SnepMessage.RESPONSE_SUCCESS, response.getField());
189    }
190
191    public void testUnsupportedVersion() throws IOException {
192        MockLlcpSocket clientSocket = new MockLlcpSocket();
193        MockLlcpSocket serverSocket = new MockLlcpSocket();
194        MockLlcpSocket.bind(clientSocket, serverSocket);
195
196        final SnepMessenger client = new SnepMessenger(true, clientSocket, MIU);
197        final SnepMessenger server = new SnepMessenger(false, serverSocket, MIU);
198
199        new Thread() {
200            @Override
201            public void run() {
202                try {
203                    SnepServer.handleRequest(server, mCallback);
204                } catch (Exception e) {
205                    Log.e(TAG, "error getting message", e);
206                }
207            };
208        }.start();
209
210        SnepMessage response = null;
211        try {
212            NdefMessage ndef = getSmallNdef();
213            SnepMessage request = new SnepMessage(
214                    (byte)2, SnepMessage.REQUEST_PUT, ndef.toByteArray().length, 0, ndef);
215            client.sendMessage(request);
216            response = client.getMessage();
217        } catch (SnepException e) {
218            throw new IOException("Failed to retrieve SNEP message", e);
219        }
220
221        assertNotNull(response);
222        assertEquals(SnepMessage.RESPONSE_UNSUPPORTED_VERSION, response.getField());
223    }
224
225    public void testDifferentMinorVersion() throws IOException {
226        MockLlcpSocket clientSocket = new MockLlcpSocket();
227        MockLlcpSocket serverSocket = new MockLlcpSocket();
228        MockLlcpSocket.bind(clientSocket, serverSocket);
229
230        final SnepMessenger client = new SnepMessenger(true, clientSocket, MIU);
231        final SnepMessenger server = new SnepMessenger(false, serverSocket, MIU);
232
233        new Thread() {
234            @Override
235            public void run() {
236                try {
237                    SnepServer.handleRequest(server, mCallback);
238                } catch (Exception e) {
239                    Log.e(TAG, "error getting message", e);
240                }
241            };
242        }.start();
243
244        byte version = (0xF0 & (SnepMessage.VERSION_MAJOR << 4)) |
245                (0x0F & (SnepMessage.VERSION_MINOR + 1));
246        SnepMessage response = null;
247        try {
248            NdefMessage ndef = getSmallNdef();
249            SnepMessage request = new SnepMessage(
250                    version, SnepMessage.REQUEST_PUT, ndef.toByteArray().length, 0, ndef);
251            client.sendMessage(request);
252            response = client.getMessage();
253        } catch (SnepException e) {
254            throw new IOException("Failed to retrieve SNEP message", e);
255        }
256
257        assertNotNull(response);
258        assertEquals(SnepMessage.RESPONSE_SUCCESS, response.getField());
259    }
260
261    NdefMessage getSmallNdef() {
262        NdefRecord rec = new NdefRecord(NdefRecord.TNF_ABSOLUTE_URI, NdefRecord.RTD_URI,
263                new byte[0], "http://android.com".getBytes());
264        return new NdefMessage(new NdefRecord[] { rec });
265    }
266
267    NdefMessage getNdef(int size) {
268        StringBuffer string = new StringBuffer(size);
269        for (int i = 0; i < size; i++) {
270            string.append('A' + (i % 26));
271        }
272        NdefRecord rec = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, "text/plain".getBytes(),
273                new byte[0], string.toString().getBytes());
274        return new NdefMessage(new NdefRecord[] { rec });
275    }
276
277    /**
278     * A SNEP Server implementation that accepts PUT requests for all ndef
279     * messages and responds to GET requests with acceptable length greater
280     * than or equal to 1024.
281     */
282    final SnepServer.Callback mCallback = new SnepServer.Callback() {
283        private static final int GET_LENGTH = 1024;
284
285        @Override
286        public SnepMessage doPut(NdefMessage msg) {
287            return SnepMessage.getSuccessResponse(null);
288        }
289
290        @Override
291        public SnepMessage doGet(int acceptableLength, NdefMessage msg) {
292            if (GET_LENGTH <= acceptableLength) {
293                return SnepMessage.getSuccessResponse(getSmallNdef());
294            } else {
295                return SnepMessage.getMessage(SnepMessage.RESPONSE_EXCESS_DATA);
296            }
297        }
298    };
299}