1 #region Copyright notice and license 2 3 // Copyright 2015 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System; 20 using System.Diagnostics; 21 using System.Linq; 22 using System.Runtime.InteropServices; 23 using System.Text; 24 using System.Threading; 25 using System.Threading.Tasks; 26 using Grpc.Core; 27 using Grpc.Core.Internal; 28 using Grpc.Core.Utils; 29 using NUnit.Framework; 30 31 namespace Grpc.Core.Tests 32 { 33 public class MetadataTest 34 { 35 [Test] AsciiEntry()36 public void AsciiEntry() 37 { 38 var entry = new Metadata.Entry("ABC", "XYZ"); 39 Assert.IsFalse(entry.IsBinary); 40 Assert.AreEqual("abc", entry.Key); // key is in lowercase. 41 Assert.AreEqual("XYZ", entry.Value); 42 CollectionAssert.AreEqual(new[] { (byte)'X', (byte)'Y', (byte)'Z' }, entry.ValueBytes); 43 44 Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc-bin", "xyz")); 45 46 Assert.AreEqual("[Entry: key=abc, value=XYZ]", entry.ToString()); 47 } 48 49 [Test] BinaryEntry()50 public void BinaryEntry() 51 { 52 var bytes = new byte[] { 1, 2, 3 }; 53 var entry = new Metadata.Entry("ABC-BIN", bytes); 54 Assert.IsTrue(entry.IsBinary); 55 Assert.AreEqual("abc-bin", entry.Key); // key is in lowercase. 56 Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; }); 57 CollectionAssert.AreEqual(bytes, entry.ValueBytes); 58 59 Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc", bytes)); 60 61 Assert.AreEqual("[Entry: key=abc-bin, valueBytes=System.Byte[]]", entry.ToString()); 62 } 63 64 [Test] AsciiEntry_KeyValidity()65 public void AsciiEntry_KeyValidity() 66 { 67 new Metadata.Entry("ABC", "XYZ"); 68 new Metadata.Entry("0123456789abc", "XYZ"); 69 new Metadata.Entry("-abc", "XYZ"); 70 new Metadata.Entry("a_bc_", "XYZ"); 71 new Metadata.Entry("abc.xyz", "XYZ"); 72 new Metadata.Entry("abc.xyz-bin", new byte[] {1, 2, 3}); 73 Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc[", "xyz")); 74 Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc/", "xyz")); 75 } 76 77 [Test] KeysAreNormalized_UppercaseKey()78 public void KeysAreNormalized_UppercaseKey() 79 { 80 var uppercaseKey = "ABC"; 81 var entry = new Metadata.Entry(uppercaseKey, "XYZ"); 82 Assert.AreEqual("abc", entry.Key); 83 } 84 85 [Test] KeysAreNormalized_LowercaseKey()86 public void KeysAreNormalized_LowercaseKey() 87 { 88 var lowercaseKey = "abc"; 89 var entry = new Metadata.Entry(lowercaseKey, "XYZ"); 90 // no allocation if key already lowercase 91 Assert.AreSame(lowercaseKey, entry.Key); 92 } 93 94 [Test] Entry_ConstructionPreconditions()95 public void Entry_ConstructionPreconditions() 96 { 97 Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry(null, "xyz")); 98 Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry("abc", (string)null)); 99 Assert.Throws(typeof(ArgumentNullException), () => new Metadata.Entry("abc-bin", (byte[])null)); 100 } 101 102 [Test] Entry_Immutable()103 public void Entry_Immutable() 104 { 105 var origBytes = new byte[] { 1, 2, 3 }; 106 var bytes = new byte[] { 1, 2, 3 }; 107 var entry = new Metadata.Entry("ABC-BIN", bytes); 108 bytes[0] = 255; // changing the array passed to constructor should have any effect. 109 CollectionAssert.AreEqual(origBytes, entry.ValueBytes); 110 111 entry.ValueBytes[0] = 255; 112 CollectionAssert.AreEqual(origBytes, entry.ValueBytes); 113 } 114 115 [Test] Entry_CreateUnsafe_Ascii()116 public unsafe void Entry_CreateUnsafe_Ascii() 117 { 118 var bytes = new byte[] { (byte)'X', (byte)'y' }; 119 fixed (byte* ptr = bytes) 120 { 121 var entry = Metadata.Entry.CreateUnsafe("abc", new IntPtr(ptr), bytes.Length); 122 Assert.IsFalse(entry.IsBinary); 123 Assert.AreEqual("abc", entry.Key); 124 Assert.AreEqual("Xy", entry.Value); 125 CollectionAssert.AreEqual(bytes, entry.ValueBytes); 126 } 127 } 128 129 [Test] Entry_CreateUnsafe_Binary()130 public unsafe void Entry_CreateUnsafe_Binary() 131 { 132 var bytes = new byte[] { 1, 2, 3 }; 133 fixed (byte* ptr = bytes) 134 { 135 var entry = Metadata.Entry.CreateUnsafe("abc-bin", new IntPtr(ptr), bytes.Length); 136 Assert.IsTrue(entry.IsBinary); 137 Assert.AreEqual("abc-bin", entry.Key); 138 Assert.Throws(typeof(InvalidOperationException), () => { var v = entry.Value; }); 139 CollectionAssert.AreEqual(bytes, entry.ValueBytes); 140 } 141 } 142 143 [Test] IndexOf()144 public void IndexOf() 145 { 146 var metadata = CreateMetadata(); 147 Assert.AreEqual(0, metadata.IndexOf(metadata[0])); 148 Assert.AreEqual(1, metadata.IndexOf(metadata[1])); 149 } 150 151 [Test] Insert()152 public void Insert() 153 { 154 var metadata = CreateMetadata(); 155 metadata.Insert(0, new Metadata.Entry("new-key", "new-value")); 156 Assert.AreEqual(3, metadata.Count); 157 Assert.AreEqual("new-key", metadata[0].Key); 158 Assert.AreEqual("abc", metadata[1].Key); 159 } 160 161 [Test] RemoveAt()162 public void RemoveAt() 163 { 164 var metadata = CreateMetadata(); 165 metadata.RemoveAt(0); 166 Assert.AreEqual(1, metadata.Count); 167 Assert.AreEqual("xyz", metadata[0].Key); 168 } 169 170 [Test] Remove()171 public void Remove() 172 { 173 var metadata = CreateMetadata(); 174 metadata.Remove(metadata[0]); 175 Assert.AreEqual(1, metadata.Count); 176 Assert.AreEqual("xyz", metadata[0].Key); 177 } 178 179 [Test] Indexer_Set()180 public void Indexer_Set() 181 { 182 var metadata = CreateMetadata(); 183 var entry = new Metadata.Entry("new-key", "new-value"); 184 185 metadata[1] = entry; 186 Assert.AreEqual(entry, metadata[1]); 187 } 188 189 [Test] Clear()190 public void Clear() 191 { 192 var metadata = CreateMetadata(); 193 metadata.Clear(); 194 Assert.AreEqual(0, metadata.Count); 195 } 196 197 [Test] Contains()198 public void Contains() 199 { 200 var metadata = CreateMetadata(); 201 Assert.IsTrue(metadata.Contains(metadata[0])); 202 Assert.IsFalse(metadata.Contains(new Metadata.Entry("new-key", "new-value"))); 203 } 204 205 [Test] CopyTo()206 public void CopyTo() 207 { 208 var metadata = CreateMetadata(); 209 var array = new Metadata.Entry[metadata.Count + 1]; 210 211 metadata.CopyTo(array, 1); 212 Assert.AreEqual(default(Metadata.Entry), array[0]); 213 Assert.AreEqual(metadata[0], array[1]); 214 } 215 216 [Test] IEnumerableGetEnumerator()217 public void IEnumerableGetEnumerator() 218 { 219 var metadata = CreateMetadata(); 220 var enumerator = (metadata as System.Collections.IEnumerable).GetEnumerator(); 221 222 int i = 0; 223 while (enumerator.MoveNext()) 224 { 225 Assert.AreEqual(metadata[i], enumerator.Current); 226 i++; 227 } 228 } 229 230 [Test] FreezeMakesReadOnly()231 public void FreezeMakesReadOnly() 232 { 233 var entry = new Metadata.Entry("new-key", "new-value"); 234 var metadata = CreateMetadata().Freeze(); 235 236 Assert.IsTrue(metadata.IsReadOnly); 237 Assert.Throws<InvalidOperationException>(() => metadata.Insert(0, entry)); 238 Assert.Throws<InvalidOperationException>(() => metadata.RemoveAt(0)); 239 Assert.Throws<InvalidOperationException>(() => metadata[0] = entry); 240 Assert.Throws<InvalidOperationException>(() => metadata.Add(entry)); 241 Assert.Throws<InvalidOperationException>(() => metadata.Add("new-key", "new-value")); 242 Assert.Throws<InvalidOperationException>(() => metadata.Add("new-key-bin", new byte[] { 0xaa })); 243 Assert.Throws<InvalidOperationException>(() => metadata.Clear()); 244 Assert.Throws<InvalidOperationException>(() => metadata.Remove(metadata[0])); 245 } 246 247 [Test] GetAll()248 public void GetAll() 249 { 250 var metadata = new Metadata 251 { 252 { "abc", "abc-value1" }, 253 { "abc", "abc-value2" }, 254 { "xyz", "xyz-value1" }, 255 }; 256 257 var abcEntries = metadata.GetAll("abc").ToList(); 258 Assert.AreEqual(2, abcEntries.Count); 259 Assert.AreEqual("abc-value1", abcEntries[0].Value); 260 Assert.AreEqual("abc-value2", abcEntries[1].Value); 261 262 var xyzEntries = metadata.GetAll("xyz").ToList(); 263 Assert.AreEqual(1, xyzEntries.Count); 264 Assert.AreEqual("xyz-value1", xyzEntries[0].Value); 265 } 266 267 [Test] Get()268 public void Get() 269 { 270 var metadata = new Metadata 271 { 272 { "abc", "abc-value1" }, 273 { "abc", "abc-value2" }, 274 { "xyz", "xyz-value1" }, 275 }; 276 277 var abcEntry = metadata.Get("abc"); 278 Assert.AreEqual("abc-value2", abcEntry.Value); 279 280 var xyzEntry = metadata.Get("xyz"); 281 Assert.AreEqual("xyz-value1", xyzEntry.Value); 282 283 var notFound = metadata.Get("not-found"); 284 Assert.AreEqual(null, notFound); 285 } 286 287 [Test] GetValue()288 public void GetValue() 289 { 290 var metadata = new Metadata 291 { 292 { "abc", "abc-value1" }, 293 { "abc", "abc-value2" }, 294 { "xyz", "xyz-value1" }, 295 { "xyz-bin", Encoding.ASCII.GetBytes("xyz-value1") }, 296 }; 297 298 var abcValue = metadata.GetValue("abc"); 299 Assert.AreEqual("abc-value2", abcValue); 300 301 var xyzValue = metadata.GetValue("xyz"); 302 Assert.AreEqual("xyz-value1", xyzValue); 303 304 var notFound = metadata.GetValue("not-found"); 305 Assert.AreEqual(null, notFound); 306 } 307 308 [Test] GetValue_BytesValue()309 public void GetValue_BytesValue() 310 { 311 var metadata = new Metadata 312 { 313 { "xyz-bin", Encoding.ASCII.GetBytes("xyz-value1") }, 314 }; 315 316 Assert.Throws<InvalidOperationException>(() => metadata.GetValue("xyz-bin")); 317 } 318 319 [Test] GetValueBytes()320 public void GetValueBytes() 321 { 322 var metadata = new Metadata 323 { 324 { "abc-bin", Encoding.ASCII.GetBytes("abc-value1") }, 325 { "abc-bin", Encoding.ASCII.GetBytes("abc-value2") }, 326 { "xyz-bin", Encoding.ASCII.GetBytes("xyz-value1") }, 327 }; 328 329 var abcValue = metadata.GetValueBytes("abc-bin"); 330 Assert.AreEqual(Encoding.ASCII.GetBytes("abc-value2"), abcValue); 331 332 var xyzValue = metadata.GetValueBytes("xyz-bin"); 333 Assert.AreEqual(Encoding.ASCII.GetBytes("xyz-value1"), xyzValue); 334 335 var notFound = metadata.GetValueBytes("not-found"); 336 Assert.AreEqual(null, notFound); 337 } 338 339 [Test] GetValueBytes_StringValue()340 public void GetValueBytes_StringValue() 341 { 342 var metadata = new Metadata 343 { 344 { "xyz", "xyz-value1" }, 345 }; 346 347 var xyzValue = metadata.GetValueBytes("xyz"); 348 Assert.AreEqual(Encoding.ASCII.GetBytes("xyz-value1"), xyzValue); 349 } 350 CreateMetadata()351 private Metadata CreateMetadata() 352 { 353 return new Metadata 354 { 355 { "abc", "abc-value" }, 356 { "xyz", "xyz-value" }, 357 }; 358 } 359 } 360 } 361