Formats a SearchRequest into a JSON POST to be sent to Elasticsearch.
        public static async void NonSuccessfulHttpRequestThrows()
        {
            var client = Substitute.For<IElasticsearchClient>();

            client.SearchAsync<string>(
                    "_all",
                    "docType",
                    @"{""timeout"":""10s""}",
                    Arg.Any<Func<SearchRequestParameters, SearchRequestParameters>>())
                .Returns(Task.FromResult(ElasticsearchResponse<string>.Create(
                    new ConnectionConfiguration(),
                    404,
                    "_search",
                    "_all",
                    new byte[0])));

            var localConnection = new ElasticNetConnection(client);
            var request = new SearchRequest { DocumentType = "docType" };
            var formatter = new SearchRequestFormatter(localConnection, mapping, request);

            var ex = await Record.ExceptionAsync(() => localConnection.SearchAsync(
                formatter.Body,
                request,
                CancellationToken.None,
                log));

            Assert.IsType<HttpRequestException>(ex);
            Assert.Equal("Response status code does not indicate success: 404 (Not Found).", ex.Message);
        }
        public void BodyContainsFromWhenSpecified()
        {
            const int expectedFrom = 1024;

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", From = expectedFrom });
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("from");
            Assert.Equal(expectedFrom, result);
        }
        public void BodyContainsMinScoreWhenSpecified()
        {
            var searchRequest = new SearchRequest { MinScore = 1.3 };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("min_score");
            Assert.Equal(searchRequest.MinScore.ToString(), result);
        }
        public void BodyContainsStatisticalFacet()
        {
            var expectedFacet = new StatisticalFacet("TotalSales", "OrderTotal");
            var searchRequest = new SearchRequest { Facets = new List<IFacet>(new[] { expectedFacet }) };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("facets", expectedFacet.Name, expectedFacet.Type, "field");
            Assert.Equal(expectedFacet.Fields[0], result.ToString());
        }
        public void BodyContainsQueryString()
        {
            const string expectedQuery = "this is my query string";
            var queryString = new QueryStringCriteria(expectedQuery);

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Query = queryString });
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("query", "query_string", "query");
            Assert.Equal(expectedQuery, result.ToString());
        }
        public void BodyContainsFieldSelections()
        {
            var expectedFields = new List<string> { "first", "second", "third" };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Fields = expectedFields });
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("fields");
            foreach (var field in expectedFields)
                Assert.Contains(field, result);
        }
        public void BodyContainsFilterExists()
        {
            const string expectedFieldName = "fieldShouldExist";
            var existsCriteria = new ExistsCriteria(expectedFieldName);

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Filter = existsCriteria });
            var body = JObject.Parse(formatter.Body);

            var field = body.TraverseWithAssert("query", "filtered", "filter", "exists", "field");
            Assert.Equal(expectedFieldName, field);
        }
        public void BodyContainsBoolMustQuery()
        {
            var rangeCriteria = new RangeCriteria("ranged", memberInfo, RangeComparison.GreaterThanOrEqual, 88);
            var boolMust = new BoolCriteria(new[] { rangeCriteria }, null, null);

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Query = boolMust });
            var body = JObject.Parse(formatter.Body);

            var mustItems = body.TraverseWithAssert("query", "bool", "must");
            Assert.Equal(1, mustItems.Count());
            mustItems[0].TraverseWithAssert("range");
        }
        public void BodyContainsFilterTerm()
        {
            var termCriteria = TermsCriteria.Build(TermsExecutionMode.@bool, "term1", memberInfo, "singlecriteria");

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Filter = termCriteria });
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("query", "filtered", "filter", "term");
            Assert.Equal(1, result.Count());
            Assert.Equal("!!! singlecriteria !!!", result[termCriteria.Field].ToString());
            Assert.Null(result["execution"]);  // Only applicable to "terms" filters
        }
        public void BodyContainsTermsFacetWithNoSizeWhenNotSpecified()
        {
            var expectedFacet = new TermsFacet("Totals", null, "OrderTotal");
            var searchRequest = new SearchRequest { Facets = new List<IFacet>(new[] { expectedFacet }) };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("facets", expectedFacet.Name, expectedFacet.Type);

            Assert.False(result.Contains("size"));
        }
        public void BodyContainsFilterFacet()
        {
            var expectedFilter = new ExistsCriteria("IsLocal");
            var expectedFacet = new FilterFacet("LocalSales", expectedFilter);
            var searchRequest = new SearchRequest { Facets = new List<IFacet>(new[] { expectedFacet }) };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("facets", expectedFacet.Name, expectedFacet.Type, expectedFilter.Name, "field");
            Assert.Equal(expectedFilter.Field, result.ToString());
        }
        public void BodyContainsQueryStringWithFields()
        {
            const string expectedQuery = "this is my query string";
            var expectedFields = new[] { "green", "brown", "yellow" };
            var queryString = new QueryStringCriteria(expectedQuery, expectedFields);

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Query = queryString });
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("query", "query_string");
            Assert.Equal(expectedQuery, result.TraverseWithAssert("query").ToString());
            Assert.Equal(expectedFields, result.TraverseWithAssert("fields").Select(f => f.ToString()).ToArray());
        }
        public void BodyContainsFilterTerms()
        {
            var termCriteria = TermsCriteria.Build("term1", memberInfo, "criteria1", "criteria2");

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Filter = termCriteria });
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("query", "filtered", "filter", "terms");
            var actualTerms = result.TraverseWithAssert(termCriteria.Field);
            foreach (var criteria in termCriteria.Values)
                Assert.Contains("!!! " + criteria + " !!!", actualTerms.Select(t => t.ToString()).ToArray());
            Assert.Null(result["execution"]);
        }
        public static async void SearchAsyncCapturesRequestInfoOnFailure()
        {
            var spyLog = new SpyLog();
            var brokenConnection = new ElasticConnection(new Uri("http://localhost:12"), index: "MyIndex");
            var processor = new ElasticRequestProcessor(brokenConnection, mapping, spyLog, new RetryPolicy(spyLog, 100, 1));
            var searchRequest = new SearchRequest { DocumentType = "docType" };
            var formatter = new SearchRequestFormatter(brokenConnection, mapping, searchRequest);

            var ex = await Record.ExceptionAsync(() => processor.SearchAsync(searchRequest, CancellationToken.None));

            Assert.IsType<RetryFailedException>(ex);
            var retryLogEntry = Assert.Single(spyLog.Entries, s => s.AdditionalInfo.ContainsKey("category") && s.AdditionalInfo["category"].Equals("retry"));
            Assert.Equal("MyIndex", retryLogEntry.AdditionalInfo["index"]);
            Assert.Equal(brokenConnection.GetSearchUri(searchRequest), retryLogEntry.AdditionalInfo["uri"]);
            Assert.Equal(formatter.Body, retryLogEntry.AdditionalInfo["query"]);
        }
        public void BodyContainsFilterFacetAndedWithRequestFilter()
        {
            var expectedFacet = new FilterFacet("LocalSales", new ExistsCriteria("IsLocal"));
            var searchRequest = new SearchRequest
            {
                Filter = new MissingCriteria("Country"),
                Query = new PrefixCriteria("Field", "Prefix"),
                Facets = new List<IFacet>(new[] { expectedFacet })
            };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var andFilter = body.TraverseWithAssert("facets", expectedFacet.Name, expectedFacet.Type, "and");
            Assert.Equal(2, andFilter.Count());
        }
        public void BodyContainsTermsFacet()
        {
            const int expectedSize = 1234;
            var expectedFacet = new TermsFacet("Totals", expectedSize, "OrderTotal", "OrderCost");
            var searchRequest = new SearchRequest { Facets = new List<IFacet>(new[] { expectedFacet }) };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("facets", expectedFacet.Name, expectedFacet.Type);

            Assert.Equal(expectedSize.ToString(CultureInfo.InvariantCulture), result.TraverseWithAssert("size").ToString());

            var actualFields = result.TraverseWithAssert("fields").ToArray();
            foreach (var expectedField in expectedFacet.Fields)
                Assert.Contains(expectedField, actualFields);
        }
        public void BodyContainsQueryRange()
        {
            var rangeCriteria = new RangeCriteria("someField", memberInfo,
                new[]
                {
                    new RangeSpecificationCriteria(RangeComparison.LessThan, 100),
                    new RangeSpecificationCriteria(RangeComparison.GreaterThan, 200)
                });

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Query = rangeCriteria });
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("query", "range");
            var actualRange = result.TraverseWithAssert(rangeCriteria.Field);
            Assert.Equal("!!! 100 !!!", actualRange["lt"]);
            Assert.Equal("!!! 200 !!!", actualRange["gt"]);
        }
        public void BodyContainsMultipleFacets()
        {
            var expectedFacets = new List<IFacet>
            {
                new FilterFacet("LocalSales", new ExistsCriteria("IsLocal")),
                new StatisticalFacet("TotalSales", "OrderTotal")
            };

            var searchRequest = new SearchRequest { Facets = expectedFacets };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var facetResults = body.TraverseWithAssert("facets");
            foreach (var expectedFacet in expectedFacets)
                facetResults.TraverseWithAssert(expectedFacet.Name, expectedFacet.Type);
        }
        public Task<ElasticResponse> SearchAsync(SearchRequest searchRequest, CancellationToken cancellationToken)
        {
            var formatter = new SearchRequestFormatter(connection, mapping, searchRequest);

            return retryPolicy.ExecuteAsync(
                async token => await connection.SearchAsync(
                    formatter.Body,
                    searchRequest,
                    token,
                    log),
                (response, exception) => !cancellationToken.IsCancellationRequested && exception != null,
                (response, additionalInfo) =>
                {
                    additionalInfo["index"] = connection.Index;
                    additionalInfo["uri"] = connection.GetSearchUri(searchRequest);
                    additionalInfo["query"] = formatter.Body;
                }, cancellationToken);
        }
        public void BodyContainsBoolShouldQuery()
        {
            var range1 = new RangeCriteria("range1", memberInfo, RangeComparison.GreaterThanOrEqual, 88);
            var range2 = new RangeCriteria("range2", memberInfo, RangeComparison.GreaterThanOrEqual, 88);
            var boolMust = new BoolCriteria(null, new[] { range1, range2 }, null);

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Query = boolMust });
            var body = JObject.Parse(formatter.Body);

            var boolBody = body.TraverseWithAssert("query", "bool");

            var minMatch = boolBody.TraverseWithAssert("minimum_should_match");
            Assert.Equal(1, minMatch.Value<int>());

            var mustNotItems = boolBody.TraverseWithAssert("should");
            Assert.Equal(2, mustNotItems.Count());
            mustNotItems[0].TraverseWithAssert("range");
        }
        public Task<ElasticResponse> SearchAsync(SearchRequest searchRequest, CancellationToken cancellationToken)
        {
            var formatter = new SearchRequestFormatter(connection, mapping, searchRequest);
            log.Debug(null, null, "Request: POST {0}", formatter.Uri);
            log.Debug(null, null, "Body:\n{0}", formatter.Body);

            return retryPolicy.ExecuteAsync(
                async token =>
                {
                    using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, formatter.Uri) { Content = new StringContent(formatter.Body) })
                    using (var response = await SendRequestAsync(connection.HttpClient, requestMessage, token))
                    using (var responseStream = await response.Content.ReadAsStreamAsync())
                        return ParseResponse(responseStream, log);
                },
                (response, exception) => !cancellationToken.IsCancellationRequested && exception != null,
                (response, additionalInfo) =>
                {
                    additionalInfo["index"] = connection.Index;
                    additionalInfo["uri"] = formatter.Uri;
                    additionalInfo["query"] = formatter.Body;
                }, cancellationToken);
        }
        public void BodyContainsMatchAllFilter()
        {
            var matchAllCriteria = MatchAllCriteria.Instance;

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Filter = matchAllCriteria });
            var body = JObject.Parse(formatter.Body);

            body.TraverseWithAssert("query", "filtered", "filter", "match_all");
        }
        public void BodyContainsTermsFacetWithDefaultSizeFromConnection()
        {
            const int expectedSize = 678;
            var sizedConnection = new ElasticConnection(defaultConnection.Endpoint, options:new ElasticConnectionOptions { SearchSizeDefault = expectedSize });
            var expectedFacet = new TermsFacet("Totals", null, "OrderTotal", "OrderCost");
            var searchRequest = new SearchRequest { Facets = new List<IFacet>(new[] { expectedFacet }) };

            var formatter = new SearchRequestFormatter(sizedConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("facets", expectedFacet.Name, expectedFacet.Type);

            Assert.Equal(expectedSize.ToString(CultureInfo.InvariantCulture), result.TraverseWithAssert("size").ToString());
        }
Пример #24
0
        public static async Task ForcesBasicAuthorizationWhenProvidedWithUsernameAndPassword()
        {
            var messageHandler = new SpyMessageHandler();
            var localConnection = new ElasticConnection(messageHandler, new Uri("http://localhost"), "myUser", "myPass");
            var request = new SearchRequest { DocumentType = "docType" };
            var formatter = new SearchRequestFormatter(localConnection, mapping, request);

            await localConnection.SearchAsync(
                formatter.Body,
                request,
                token,
                log);

            var auth = messageHandler.Request.Headers.Authorization;
            Assert.NotNull(auth);
            Assert.Equal("Basic", auth.Scheme);
            Assert.Equal("myUser:myPass", Encoding.ASCII.GetString(Convert.FromBase64String(auth.Parameter)));
        }
Пример #25
0
        public static async Task NoAuthorizationWithEmptyUserName()
        {
            var messageHandler = new SpyMessageHandler();
            var localConnection = new ElasticConnection(messageHandler, new Uri("http://localhost"));
            var request = new SearchRequest { DocumentType = "docType" };
            var formatter = new SearchRequestFormatter(localConnection, mapping, request);

            await localConnection.SearchAsync(
                formatter.Body,
                request,
                token,
                log);

            Assert.Null(messageHandler.Request.Headers.Authorization);
        }
Пример #26
0
        public static async void NonSuccessfulHttpRequestThrows()
        {
            var messageHandler = new SpyMessageHandler();
            messageHandler.Response.StatusCode = HttpStatusCode.NotFound;
            var localConnection = new ElasticConnection(messageHandler, new Uri("http://localhost"), "myUser", "myPass");
            var request = new SearchRequest { DocumentType = "docType" };
            var formatter = new SearchRequestFormatter(localConnection, mapping, request);

            var ex = await Record.ExceptionAsync(() => localConnection.SearchAsync(
                formatter.Body,
                request,
                token,
                log));

            Assert.IsType<HttpRequestException>(ex);
            Assert.Equal("Response status code does not indicate success: 404 (Not Found).", ex.Message);
        }
 public void ParseThrowsInvalidOperationForUnknownCriteriaTypes()
 {
     var facets = new List<IFacet> { new FakeFacet() };
     var formatter = new SearchRequestFormatter(defaultConnection, mapping, new SearchRequest { DocumentType = "type1", Facets = facets });
     Assert.Throws<InvalidOperationException>(() => JObject.Parse(formatter.Body));
 }
        public void BodyContainsTermsStatsFacet()
        {
            const int expectedSize = 101;
            var expectedFacet = new TermsStatsFacet("Name", "Key", "Value", expectedSize);
            var searchRequest = new SearchRequest { Facets = new List<IFacet>(new[] { expectedFacet }) };

            var formatter = new SearchRequestFormatter(defaultConnection, mapping, searchRequest);
            var body = JObject.Parse(formatter.Body);

            var result = body.TraverseWithAssert("facets", expectedFacet.Name, expectedFacet.Type);
            Assert.Equal(expectedFacet.Key, result.TraverseWithAssert("key_field").ToString());
            Assert.Equal(expectedFacet.Value, result.TraverseWithAssert("value_field").ToString());
            Assert.Equal(expectedSize.ToString(CultureInfo.InvariantCulture), result.TraverseWithAssert("size").ToString());
        }
Пример #29
0
        public static async void SearchAsyncThrowsTaskCancelledExceptionWithAlreadyCancelledCancellationToken()
        {
            var spyLog = new SpyLog();
            var localConnection = new ElasticConnection(new Uri("http://localhost"), index: "SearchIndex");
            var request = new SearchRequest { DocumentType = "docType" };
            var formatter = new SearchRequestFormatter(localConnection, mapping, request);

            var ex = await Record.ExceptionAsync(() => localConnection.SearchAsync(
                formatter.Body,
                request,
                new CancellationToken(true),
                spyLog));

            Assert.IsType<TaskCanceledException>(ex);
        }
Пример #30
0
        public static async Task LogsDebugMessagesDuringExecution()
        {
            var responseString = BuildResponseString(2, 1, 1, 0.3141, "testIndex", "testType", "testId");
            var messageHandler = new SpyMessageHandler();
            var spyLog = new SpyLog();
            messageHandler.Response.Content = new StringContent(responseString);
            var localConnection = new ElasticConnection(messageHandler, new Uri("http://localhost"), "myUser", "myPass", index: "SearchIndex");
            var request = new SearchRequest { DocumentType = "abc123", Size = 2112 };
            var formatter = new SearchRequestFormatter(localConnection, mapping, request);

            await localConnection.SearchAsync(
                formatter.Body,
                request,
                token,
                spyLog);

            Assert.Equal(4, spyLog.Entries.Count);
            Assert.Equal(@"Request: POST http://localhost/SearchIndex/abc123/_search", spyLog.Entries[0].Message);
            Assert.Equal(@"Body:" + '\n' + @"{""size"":2112,""timeout"":""10s""}", spyLog.Entries[1].Message);
            Assert.True(new Regex(@"Response: 200 OK \(in \d+ms\)").Match(spyLog.Entries[2].Message).Success);
            Assert.True(new Regex(@"Deserialized \d+ bytes into 1 hits in \d+ms").Match(spyLog.Entries[3].Message).Success);
        }