1 /* 2 * Copyright (C) 2014 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 17 package android.net.nsd; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import android.net.Network; 25 import android.os.Build; 26 import android.os.Bundle; 27 import android.os.Parcel; 28 import android.os.StrictMode; 29 30 import androidx.test.filters.SmallTest; 31 32 import com.android.testutils.DevSdkIgnoreRule; 33 import com.android.testutils.DevSdkIgnoreRunner; 34 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.net.InetAddress; 39 import java.net.UnknownHostException; 40 import java.util.Arrays; 41 import java.util.Map; 42 43 @RunWith(DevSdkIgnoreRunner.class) 44 @SmallTest 45 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) 46 public class NsdServiceInfoTest { 47 48 public final static InetAddress LOCALHOST; 49 static { 50 // Because test. 51 StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); 52 StrictMode.setThreadPolicy(policy); 53 54 InetAddress _host = null; 55 try { 56 _host = InetAddress.getLocalHost(); 57 } catch (UnknownHostException e) { } 58 LOCALHOST = _host; 59 } 60 61 @Test testLimits()62 public void testLimits() throws Exception { 63 NsdServiceInfo info = new NsdServiceInfo(); 64 65 // Non-ASCII keys. 66 boolean exceptionThrown = false; 67 try { 68 info.setAttribute("猫", "meow"); 69 } catch (IllegalArgumentException e) { 70 exceptionThrown = true; 71 } 72 assertTrue(exceptionThrown); 73 assertEmptyServiceInfo(info); 74 75 // ASCII keys with '=' character. 76 exceptionThrown = false; 77 try { 78 info.setAttribute("kitten=", "meow"); 79 } catch (IllegalArgumentException e) { 80 exceptionThrown = true; 81 } 82 assertTrue(exceptionThrown); 83 assertEmptyServiceInfo(info); 84 85 // Single key + value length too long. 86 exceptionThrown = false; 87 try { 88 String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + 89 "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + 90 "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + 91 "ooooooooooooooooooooooooooooong"; // 248 characters. 92 info.setAttribute("longcat", longValue); // Key + value == 255 characters. 93 } catch (IllegalArgumentException e) { 94 exceptionThrown = true; 95 } 96 assertTrue(exceptionThrown); 97 assertEmptyServiceInfo(info); 98 99 // Total TXT record length too long. 100 exceptionThrown = false; 101 int recordsAdded = 0; 102 try { 103 for (int i = 100; i < 300; ++i) { 104 // 6 char key + 5 char value + 2 bytes overhead = 13 byte record length. 105 String key = String.format("key%d", i); 106 info.setAttribute(key, "12345"); 107 recordsAdded++; 108 } 109 } catch (IllegalArgumentException e) { 110 exceptionThrown = true; 111 } 112 assertTrue(exceptionThrown); 113 assertTrue(100 == recordsAdded); 114 assertTrue(info.getTxtRecord().length == 1300); 115 } 116 117 @Test testParcel()118 public void testParcel() throws Exception { 119 NsdServiceInfo emptyInfo = new NsdServiceInfo(); 120 checkParcelable(emptyInfo); 121 122 NsdServiceInfo fullInfo = new NsdServiceInfo(); 123 fullInfo.setServiceName("kitten"); 124 fullInfo.setServiceType("_kitten._tcp"); 125 fullInfo.setPort(4242); 126 fullInfo.setHost(LOCALHOST); 127 fullInfo.setNetwork(new Network(123)); 128 fullInfo.setInterfaceIndex(456); 129 checkParcelable(fullInfo); 130 131 NsdServiceInfo noHostInfo = new NsdServiceInfo(); 132 noHostInfo.setServiceName("kitten"); 133 noHostInfo.setServiceType("_kitten._tcp"); 134 noHostInfo.setPort(4242); 135 checkParcelable(noHostInfo); 136 137 NsdServiceInfo attributedInfo = new NsdServiceInfo(); 138 attributedInfo.setServiceName("kitten"); 139 attributedInfo.setServiceType("_kitten._tcp"); 140 attributedInfo.setPort(4242); 141 attributedInfo.setHost(LOCALHOST); 142 attributedInfo.setAttribute("color", "pink"); 143 attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8")); 144 attributedInfo.setAttribute("adorable", (String) null); 145 attributedInfo.setAttribute("sticky", "yes"); 146 attributedInfo.setAttribute("siblings", new byte[] {}); 147 attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128}); 148 attributedInfo.removeAttribute("sticky"); 149 checkParcelable(attributedInfo); 150 151 // Sanity check that we actually wrote attributes to attributedInfo. 152 assertTrue(attributedInfo.getAttributes().keySet().contains("adorable")); 153 String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8"); 154 assertTrue(sound.equals("にゃあ")); 155 byte[] edgeCases = attributedInfo.getAttributes().get("edge cases"); 156 assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128})); 157 assertFalse(attributedInfo.getAttributes().keySet().contains("sticky")); 158 } 159 checkParcelable(NsdServiceInfo original)160 public void checkParcelable(NsdServiceInfo original) { 161 // Write to parcel. 162 Parcel p = Parcel.obtain(); 163 Bundle writer = new Bundle(); 164 writer.putParcelable("test_info", original); 165 writer.writeToParcel(p, 0); 166 167 // Extract from parcel. 168 p.setDataPosition(0); 169 Bundle reader = p.readBundle(); 170 reader.setClassLoader(NsdServiceInfo.class.getClassLoader()); 171 NsdServiceInfo result = reader.getParcelable("test_info"); 172 173 // Assert equality of base fields. 174 assertEquals(original.getServiceName(), result.getServiceName()); 175 assertEquals(original.getServiceType(), result.getServiceType()); 176 assertEquals(original.getHost(), result.getHost()); 177 assertTrue(original.getPort() == result.getPort()); 178 assertEquals(original.getNetwork(), result.getNetwork()); 179 assertEquals(original.getInterfaceIndex(), result.getInterfaceIndex()); 180 181 // Assert equality of attribute map. 182 Map<String, byte[]> originalMap = original.getAttributes(); 183 Map<String, byte[]> resultMap = result.getAttributes(); 184 assertEquals(originalMap.keySet(), resultMap.keySet()); 185 for (String key : originalMap.keySet()) { 186 assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key))); 187 } 188 } 189 assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty)190 public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) { 191 byte[] txtRecord = shouldBeEmpty.getTxtRecord(); 192 if (txtRecord == null || txtRecord.length == 0) { 193 return; 194 } 195 fail("NsdServiceInfo.getTxtRecord did not return null but " + Arrays.toString(txtRecord)); 196 } 197 } 198