static void Main(string[] args) { var ct = new CancellationToken(); var cfg = new LazyLoadingConfiguration(10000, ct); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetEndPoint("https://cloud.51degrees.com/api/v4/json") // Obtain a resource key from https://configure.51degrees.com .SetResourceKey("AQS5HKcyHJbECm6E10g") .SetLazyLoading(cfg) .Build(); using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data = pipeline.CreateFlowData(); data.AddEvidence("query.User-Agent", "iPhone"); data.Process(); var result = data.GetFromElement(engine).JsonResponse; Console.WriteLine(result); } Console.ReadKey(); }
public void Endpoint_Config_Precedence_EnvironmentVariable() { var expectedUrl = "http://localhost/test_env/"; Environment.SetEnvironmentVariable(Constants.FOD_CLOUD_API_URL, expectedUrl); var cloudRequestsEngine = new CloudRequestEngineBuilder(new LoggerFactory(), new HttpClient(_handlerMock.Object)) .SetResourceKey("abcdefgh") .Build(); _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Get && // we expected a GET request req.RequestUri.GetLeftPart(UriPartial.Path) == expectedUrl + Constants.PROPERTIES_FILENAME // to this uri ), ItExpr.IsAny <CancellationToken>() ); _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Get && // we expected a GET request req.RequestUri.GetLeftPart(UriPartial.Path) == expectedUrl + Constants.EVIDENCE_KEYS_FILENAME // to this uri ), ItExpr.IsAny <CancellationToken>() ); }
public void ValidateCacheHitOrMiss_SameUserAgent() { string resourceKey = "resource_key"; string userAgent = "iPhone"; _jsonResponse = @"{ ""device"": { ""ismobile"": true } }"; ConfigureMockedClient(r => true); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .SetCacheSize(10) .SetCacheHitOrMiss(true) .Build(); using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data1 = pipeline.CreateFlowData(); data1.AddEvidence("query.User-Agent", userAgent); data1.Process(); Assert.IsFalse(data1.GetFromElement(engine).CacheHit, "cache miss should occur."); var data2 = pipeline.CreateFlowData(); data2.AddEvidence("query.User-Agent", userAgent); data2.Process(); Assert.IsTrue(data2.GetFromElement(engine).CacheHit, "cache hit should occur."); } }
public void OriginHeader() { string resourceKey = "resource_key"; string origin = "51degrees.com"; string userAgent = "test"; ConfigureMockedClient(r => true); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .SetCloudRequestOrigin(origin) .Build(); using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data = pipeline.CreateFlowData(); data.AddEvidence("query.User-Agent", userAgent); data.Process(); } _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Post // we expected a POST request // The origin header must contain the expected value && ((req.Content.Headers.Contains(Constants.ORIGIN_HEADER_NAME) && req.Content.Headers.GetValues(Constants.ORIGIN_HEADER_NAME).Contains(origin)) || (req.Headers.Contains(Constants.ORIGIN_HEADER_NAME) && req.Headers.GetValues(Constants.ORIGIN_HEADER_NAME).Contains(origin))) ), ItExpr.IsAny <CancellationToken>() ); }
public void Endpoint_Config_Precedence_Default() { var cloudRequestsEngine = new CloudRequestEngineBuilder(new LoggerFactory(), new HttpClient(_handlerMock.Object)) .SetResourceKey("abcdefgh") .Build(); _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Get && // we expected a GET request req.RequestUri.GetLeftPart(UriPartial.Path) == Constants.PROPERTIES_ENDPOINT_DEFAULT // to this uri ), ItExpr.IsAny <CancellationToken>() ); _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Get && // we expected a GET request req.RequestUri.GetLeftPart(UriPartial.Path) == Constants.EVIDENCE_KEYS_ENDPOINT_DEFAULT // to this uri ), ItExpr.IsAny <CancellationToken>() ); }
public void RunExample() { //! [usage] // Construct a cloud request engine using the example endpoint for // the example engine to use. var cloudRequestEngine = new CloudRequestEngineBuilder(_loggerFactory, new HttpClient()) .SetEndPoint("http://51degrees.com/starsign/api/") .SetResourceKey("cloudexample") .Build(); // Construct the example engine. var starSignEngine = new SimpleCloudEngineBuilder(_loggerFactory, cloudRequestEngine) .Build(); // Construct the pipeline with the example engine and the cloud // request engine it requires. var pipeline = new PipelineBuilder(_loggerFactory) .AddFlowElement(cloudRequestEngine) .AddFlowElement(starSignEngine) .Build(); var dob = "18/12/1992"; // Create a new flow data. var flowData = pipeline.CreateFlowData(); // Add the evidence and process the data. flowData .AddEvidence("date-of-birth", dob) .Process(); // Now get the result of the processing. Console.WriteLine($"With a date of birth of {dob}, " + $"your star sign is {flowData.Get<IStarSignData>().StarSign}."); //! [usage] }
public void ValidateErrorHandling_InvalidResourceKey() { string resourceKey = "resource_key"; string userAgent = "iPhone"; _accessiblePropertiesResponse = @"{ ""errors"":[""resource_key not a valid resource key""]}"; _accessiblePropertiesResponseStatus = HttpStatusCode.BadRequest; ConfigureMockedClient(r => r.Content.ReadAsStringAsync().Result.Contains($"resource={resourceKey}") && // content contains resource key r.Content.ReadAsStringAsync().Result.Contains($"User-Agent={userAgent}") // content contains licenseKey ); Exception exception = null; try { var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .Build(); } catch (Exception ex) { exception = ex; } Assert.IsNotNull(exception, "Expected exception to occur"); Assert.IsInstanceOfType(exception, typeof(CloudRequestException)); var cloudEx = exception as CloudRequestException; Assert.IsTrue(cloudEx.Message.Contains( "resource_key not a valid resource key"), "Exception message did not contain the expected text."); }
public void EvidencePrecedence(bool warn, string evidence1, string evidence2) { var evidence1Parts = evidence1.Split("="); var evidence2Parts = evidence2.Split("="); string resourceKey = "resource_key"; ConfigureMockedClient(r => r.Content.ReadAsStringAsync().Result.Contains(evidence1.Split('.').Last()) ); var loggerFactory = new TestLoggerFactory(); var engine = new CloudRequestEngineBuilder(loggerFactory, _httpClient) .SetResourceKey(resourceKey) .Build(); using (var pipeline = new PipelineBuilder(loggerFactory).AddFlowElement(engine).Build()) { var data = pipeline.CreateFlowData(); data.AddEvidence(evidence1Parts[0], evidence1Parts[1]); data.AddEvidence(evidence2Parts[0], evidence2Parts[1]); data.Process(); } // Get loggers. var loggers = loggerFactory.Loggers .Where(l => l.GetType().IsAssignableFrom(typeof(TestLogger <FlowElements.CloudRequestEngine>))); var logger = loggers.FirstOrDefault(); // If warn is expected then check for warnings from cloud request // engine. if (warn) { logger.AssertMaxWarnings(1); logger.AssertMaxErrors(0); Assert.AreEqual(1, logger.WarningsLogged.Count); var warning = logger.WarningsLogged.Single(); Assert.IsTrue(warning.Contains($"'{evidence1}' evidence conflicts with '{evidence2}'")); } else { logger.AssertMaxWarnings(0); logger.AssertMaxErrors(0); } _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Post && // we expected a POST request req.RequestUri == expectedUri // to this uri ), ItExpr.IsAny <CancellationToken>() ); }
public void ValidateErrorHandling_MultipleErrors() { string resourceKey = "resource_key"; string userAgent = "iPhone"; _jsonResponse = @"{ ""errors"": [""This resource key is not authorized for use with this domain: . Please visit https://configure.51degrees.com to update your resource key."",""Some other error""] }"; ConfigureMockedClient(r => r.Content.ReadAsStringAsync().Result.Contains($"resource={resourceKey}") && // content contains resource key r.Content.ReadAsStringAsync().Result.Contains($"User-Agent={userAgent}") // content contains licenseKey ); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .Build(); Exception exception = null; try { using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data = pipeline.CreateFlowData(); data.AddEvidence("query.User-Agent", userAgent); data.Process(); } } catch (Exception ex) { exception = ex; } Assert.IsNotNull(exception, "Expected exception to occur"); Assert.IsInstanceOfType(exception, typeof(AggregateException)); var aggEx = (exception as AggregateException).Flatten(); Assert.AreEqual(aggEx.InnerExceptions.Count, 2); Assert.IsInstanceOfType(aggEx.InnerExceptions[0], typeof(PipelineException)); Assert.IsInstanceOfType(aggEx.InnerExceptions[1], typeof(PipelineException)); Assert.IsTrue(aggEx.InnerExceptions.Any(e => e.Message.Contains( "This resource key is not authorized for use with this domain")), "Exception message did not contain the expected text."); Assert.IsTrue(aggEx.InnerExceptions.Any(e => e.Message.Contains( "Some other error")), "Exception message did not contain the expected text."); }
public void Run(string resourceKey, string cloudEndPoint = "") { Console.WriteLine("This example shows the details of devices " + "associated with a given 'native model name'."); Console.WriteLine($"The native model name can be retrieved by " + $"code running on the device (For example, a mobile app)."); Console.WriteLine($"For Android devices, see " + $"https://developer.android.com/reference/android/os/Build#MODEL"); Console.WriteLine($"For iOS devices, see " + $"https://gist.github.com/soapyigu/c99e1f45553070726f14c1bb0a54053b#file-machinename-swift"); Console.WriteLine("----------------------------------------"); ILoggerFactory loggerFactory = new LoggerFactory(); HttpClient httpClient = new HttpClient(); // Create a cloud request engine builder var cloudRequestEngineBuilder = new CloudRequestEngineBuilder(loggerFactory, httpClient) .SetResourceKey(resourceKey); // If a cloud endpoint has been provided then set the // cloud pipeline endpoint. if (string.IsNullOrWhiteSpace(cloudEndPoint) == false) { cloudRequestEngineBuilder.SetEndPoint(cloudEndPoint); } // Create the cloud request engine. using (var cloudEngine = cloudRequestEngineBuilder.Build()) // Create the property-keyed engine to process the // response from the request engine. using (var propertyKeyedEngine = new HardwareProfileCloudEngineBuilder(loggerFactory) .Build()) // Create the pipeline using the engines. using (var pipeline = new PipelineBuilder(loggerFactory) .AddFlowElement(cloudEngine) .AddFlowElement(propertyKeyedEngine) .Build()) { // Pass an iOS native model into the pipeline and // list the matching devices. AnalyseTac(nativemodel1, pipeline); // Repeat for an Android native model name. AnalyseTac(nativemodel2, pipeline); } }
public void Process_LicenseKey() { string resourceKey = "resource_key"; string userAgent = "iPhone"; string licenseKey = "ABCDEFG"; ConfigureMockedClient(r => r.Content.ReadAsStringAsync().Result.Contains($"resource={resourceKey}") && // content contains resource key r.Content.ReadAsStringAsync().Result.Contains($"license={licenseKey}") && // content contains licenseKey r.Content.ReadAsStringAsync().Result.Contains($"User-Agent={userAgent}") // content contains user agent ); #pragma warning disable CS0618 // Type or member is obsolete // SetLicensekey is obsolete but we still want to test that // it works as intended. var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .SetLicenseKey(licenseKey) #pragma warning restore CS0618 // Type or member is obsolete .Build(); using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data = pipeline.CreateFlowData(); data.AddEvidence("query.User-Agent", userAgent); data.Process(); var result = data.GetFromElement(engine).JsonResponse; Assert.AreEqual("{'device':{'value':'1'}}", result); dynamic obj = JValue.Parse(result); Assert.AreEqual(1, (int)obj.device.value); } _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Post && // we expected a POST request req.RequestUri == expectedUri // to this uri ), ItExpr.IsAny <CancellationToken>() ); }
public void ValidateErrorHandling_HttpDataSetInException() { string resourceKey = "resource_key"; try { var engine = new CloudRequestEngineBuilder(_loggerFactory, new HttpClient()) .SetResourceKey(resourceKey) .Build(); Assert.Fail("Expected exception did not occur"); } catch (CloudRequestException ex) { Assert.IsTrue(ex.HttpStatusCode > 0, "Status code should not be 0"); Assert.IsNotNull(ex.ResponseHeaders, "Response headers not populated"); Assert.IsTrue(ex.ResponseHeaders.Count > 0, "Response headers not populated"); } }
public void Run(string resourceKey, string cloudEndPoint = "") { Console.WriteLine("This example shows the details of devices " + "associated with a given 'Type Allocation Code' or 'TAC'."); Console.WriteLine("More background information on TACs can be " + "found through various online sources such as Wikipedia: " + "https://en.wikipedia.org/wiki/Type_Allocation_Code"); Console.WriteLine("----------------------------------------"); ILoggerFactory loggerFactory = new LoggerFactory(); HttpClient httpClient = new HttpClient(); // Create a cloud request engine builder var cloudRequestEngineBuilder = new CloudRequestEngineBuilder(loggerFactory, httpClient) .SetResourceKey(resourceKey); // If a cloud endpoint has been provided then set the // cloud pipeline endpoint. if (string.IsNullOrWhiteSpace(cloudEndPoint) == false) { cloudRequestEngineBuilder.SetEndPoint(cloudEndPoint); } // Create the cloud request engine using (var cloudEngine = cloudRequestEngineBuilder.Build()) // Create the property-keyed engine to process the // response from the request engine. using (var propertyKeyedEngine = new HardwareProfileCloudEngineBuilder(loggerFactory) .Build()) // Create the pipeline using the engines. using (var pipeline = new PipelineBuilder(loggerFactory) .AddFlowElement(cloudEngine) .AddFlowElement(propertyKeyedEngine) .Build()) { // Pass a TAC into the pipeline and list the matching devices. AnalyseTac(TAC, pipeline); AnalyseTac(TAC2, pipeline); } }
public void ValidateCacheHitOrMiss_DifferentUserAgent_SameLocation(bool hit, params string[] evidenceKeys) { string resourceKey = "resource_key"; string userAgent1 = "iPhone"; string userAgent2 = "Samsung"; string latlon = "51"; _evidenceKeysResponse = $"[ '{string.Join("', '", evidenceKeys)}' ]"; _jsonResponse = @"{ ""device"": { ""ismobile"": true } }"; ConfigureMockedClient(r => true); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .SetCacheSize(10) .SetCacheHitOrMiss(true) .Build(); using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data1 = pipeline.CreateFlowData(); data1.AddEvidence("query.User-Agent", userAgent1); data1.AddEvidence("query.51d_pos_latitude", latlon); data1.AddEvidence("query.51d_pos_longitude", latlon); data1.Process(); Assert.IsFalse(data1.GetFromElement(engine).CacheHit, "cache miss should occur."); var data2 = pipeline.CreateFlowData(); data2.AddEvidence("query.User-Agent", userAgent2); data2.AddEvidence("query.51d_pos_latitude", latlon); data2.AddEvidence("query.51d_pos_longitude", latlon); data2.Process(); Assert.AreEqual(hit, data2.GetFromElement(engine).CacheHit, $"cache hit {(hit ? "should" : "shouldn't")} occur."); } }
public void ValidateCacheHitOrMiss_SameUserAgent_AdditionalHeaders() { string resourceKey = "resource_key"; string userAgent = "iPhone"; string xOperaMiniUA1 = "SonyEricsson/W810i"; string xOperaMiniUA2 = "Nokia/3310"; _evidenceKeysResponse = "[ 'query.User-Agent', 'header.X-OperaMini-Phone-UA' ]"; _jsonResponse = @"{ ""device"": { ""ismobile"": true } }"; ConfigureMockedClient(r => true); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .SetCacheSize(10) .SetCacheHitOrMiss(true) .Build(); using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data1 = pipeline.CreateFlowData(); data1.AddEvidence("query.User-Agent", userAgent); data1.AddEvidence("header.X-OperaMini-Phone-UA", xOperaMiniUA1); data1.Process(); Assert.IsFalse(data1.GetFromElement(engine).CacheHit, "cache miss should occur."); var data2 = pipeline.CreateFlowData(); data2.AddEvidence("query.User-Agent", userAgent); data2.AddEvidence("header.X-OperaMini-Phone-UA", xOperaMiniUA2); data2.Process(); Assert.IsFalse(data2.GetFromElement(engine).CacheHit, "cache miss should occur."); } }
public void ValidateErrorHandling_NoData() { string resourceKey = "resource_key"; string userAgent = "iPhone"; _jsonResponse = @"{ }"; ConfigureMockedClient(r => r.Content.ReadAsStringAsync().Result.Contains($"resource={resourceKey}") && // content contains resource key r.Content.ReadAsStringAsync().Result.Contains($"User-Agent={userAgent}") // content contains licenseKey ); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey(resourceKey) .Build(); using (var pipeline = new PipelineBuilder(_loggerFactory).AddFlowElement(engine).Build()) { var data = pipeline.CreateFlowData(); data.AddEvidence("query.User-Agent", userAgent); data.Process(); } }
public void ValidateDelayedExecutionProperties() { _accessiblePropertiesResponse = "{'Products': {'location': {'DataTier': 'tier','Properties': [" + "{'Name': 'javascript','Type': 'JavaScript','Category': 'Unspecified','DelayExecution':true}," + "{'Name': 'postcode','Type': 'String','Category': 'Unspecified','EvidenceProperties':[ 'location.javascript' ]}]}}}"; ConfigureMockedClient(r => true); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey("key") .Build(); Assert.AreEqual(1, engine.PublicProperties.Count); var locationProperties = engine.PublicProperties["location"]; Assert.AreEqual(2, locationProperties.Properties.Count); var javascript = locationProperties.Properties.Where(p => p.Name.Equals("javascript")).Single(); var postcode = locationProperties.Properties.Where(p => p.Name.Equals("postcode")).Single(); Assert.AreEqual(true, javascript.DelayExecution); Assert.AreEqual(1, postcode.EvidenceProperties.Count); Assert.AreEqual("location.javascript", postcode.EvidenceProperties.Single()); }
public void BuildEngine_ResourceKey_NotSet() { var cloudRequestsEngine = new CloudRequestEngineBuilder(new LoggerFactory(), new HttpClient()) .Build(); }
public void SubProperties() { _accessiblePropertiesResponse = @" { ""Products"": { ""device"": { ""DataTier"": ""CloudV4TAC"", ""Properties"": [ { ""Name"": ""IsMobile"", ""Type"": ""Boolean"", ""Category"": ""Device"" }, { ""Name"": ""IsTablet"", ""Type"": ""Boolean"", ""Category"": ""Device"" } ] }, ""devices"": { ""DataTier"": ""CloudV4TAC"", ""Properties"": [ { ""Name"": ""Devices"", ""Type"": ""Array"", ""Category"": ""Unspecified"", ""ItemProperties"": [ { ""Name"": ""IsMobile"", ""Type"": ""Boolean"", ""Category"": ""Device"" }, { ""Name"": ""IsTablet"", ""Type"": ""Boolean"", ""Category"": ""Device"" } ] } ] } } }"; ConfigureMockedClient(r => true); var engine = new CloudRequestEngineBuilder(_loggerFactory, _httpClient) .SetResourceKey("key") .Build(); Assert.AreEqual(2, engine.PublicProperties.Count); var deviceProperties = engine.PublicProperties["device"]; Assert.AreEqual(2, deviceProperties.Properties.Count); Assert.IsTrue(deviceProperties.Properties.Any(p => p.Name.Equals("IsMobile"))); Assert.IsTrue(deviceProperties.Properties.Any(p => p.Name.Equals("IsTablet"))); var devicesProperties = engine.PublicProperties["devices"]; Assert.AreEqual(1, devicesProperties.Properties.Count); Assert.AreEqual("Devices", devicesProperties.Properties[0].Name); Assert.IsTrue(devicesProperties.Properties[0].ItemProperties.Any(p => p.Name.Equals("IsMobile"))); Assert.IsTrue(devicesProperties.Properties[0].ItemProperties.Any(p => p.Name.Equals("IsTablet"))); }
public void EvidencePrecedenceMultipleConflicts(params string[] evidence) { string resourceKey = "resource_key"; // Get a list of evidence that should not be in the result. var excludedEvidence = evidence .Select(e => e.Split('.').Last()) .Distinct() .Where(e => e != evidence[0].Split('.').Last()); ConfigureMockedClient(r => { var valid = true || excludedEvidence.Count() > 0; // Check that excluded evidence is not in the result. foreach (var item in excludedEvidence) { valid = r.Content.ReadAsStringAsync().Result.Contains(item) == false; if (valid == false) { break; } } // Check that the expected evidence is in the result. return(r.Content.ReadAsStringAsync().Result.Contains(evidence[0].Split('.').Last()) && valid); }); var loggerFactory = new TestLoggerFactory(); var engine = new CloudRequestEngineBuilder(loggerFactory, _httpClient) .SetResourceKey(resourceKey) .Build(); using (var pipeline = new PipelineBuilder(loggerFactory).AddFlowElement(engine).Build()) { var data = pipeline.CreateFlowData(); foreach (var item in evidence) { var evidenceParts = item.Split("="); data.AddEvidence(evidenceParts[0], evidenceParts[1]); } data.Process(); } // Get loggers. var loggers = loggerFactory.Loggers .Where(l => l.GetType().IsAssignableFrom(typeof(TestLogger <FlowElements.CloudRequestEngine>))); var logger = loggers.FirstOrDefault(); // Check that the expected number of warnings has been logged. logger.AssertMaxWarnings(evidence.Length - 1); logger.AssertMaxErrors(0); Assert.AreEqual(evidence.Length - 1, logger.WarningsLogged.Count); // Check that only conflict warnings have been logged. foreach (var warning in logger.WarningsLogged) { Assert.IsTrue(warning.Contains("evidence conflicts")); } _handlerMock.Protected().Verify( "SendAsync", Times.Exactly(1), // we expected a single external request ItExpr.Is <HttpRequestMessage>(req => req.Method == HttpMethod.Post && // we expected a POST request req.RequestUri == expectedUri // to this uri ), ItExpr.IsAny <CancellationToken>() ); }