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