public SearchParameters V2Search(V2SearchRequest request, bool isDefaultSearch)
        {
            var searchParameters = NewSearchParameters();

            if (request.CountOnly)
            {
                searchParameters.Skip    = 0;
                searchParameters.Top     = 0;
                searchParameters.OrderBy = null;
            }
            else
            {
                ApplyPaging(searchParameters, request);
                searchParameters.OrderBy = GetOrderBy(request.SortBy);
            }

            if (request.IgnoreFilter)
            {
                // Note that the prerelease flag has no effect when IgnoreFilter is true.

                if (!request.IncludeSemVer2)
                {
                    searchParameters.Filter = $"{IndexFields.SemVerLevel} ne {SemVerLevelKey.SemVer2}";
                }
            }
            else
            {
                ApplySearchIndexFilter(searchParameters, request, isDefaultSearch, packageType: null);
            }

            return(searchParameters);
        }
예제 #2
0
 public V2SearchResponse EmptyV2(V2SearchRequest request)
 {
     return(new V2SearchResponse
     {
         TotalHits = 0,
         Data = new List <V2SearchPackage>(),
         Debug = DebugInformation.CreateFromEmptyOrNull(request),
     });
 }
예제 #3
0
            public void InvalidPackageType()
            {
                var request = new V2SearchRequest
                {
                    PackageType = "something's-weird",
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal("searchFilters eq 'Default'", output.Filter);
            }
예제 #4
0
            public void PackageTypeFiltering(string packageType)
            {
                var request = new V2SearchRequest
                {
                    PackageType = packageType,
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal($"searchFilters eq 'Default' and filterablePackageTypes/any(p: p eq '{packageType.ToLowerInvariant()}')", output.Filter);
            }
            public void NegativeSkip()
            {
                var request = new V2SearchRequest
                {
                    Skip = -10,
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal(0, output.Skip);
            }
            public void TooLargeTake()
            {
                var request = new V2SearchRequest
                {
                    Take = 1001,
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal(20, output.Top);
            }
예제 #7
0
            public void ThrowsWhenTermIsTooBig(string query)
            {
                var request = new V2SearchRequest {
                    Query = query
                };
                var parsed = _target.ParseV2Search(request);

                var e = Assert.Throws <InvalidSearchRequestException>(() => _target.Build(parsed));

                Assert.Equal("Query terms cannot exceed 32768 bytes.", e.Message);
            }
예제 #8
0
 public async Task <V2SearchResponse> V2SearchAsync(V2SearchRequest request)
 {
     if (request.IgnoreFilter)
     {
         return(await UseHijackIndexAsync(request));
     }
     else
     {
         return(await UseSearchIndexAsync(request));
     }
 }
        private V2SearchResponse ToResponse <T>(
            V2SearchRequest request,
            SearchParameters parameters,
            string text,
            string indexName,
            DocumentSearchResult <T> result,
            TimeSpan duration,
            Func <T, V2SearchPackage> toPackage)
            where T : class
        {
            var results = result.Results;

            result.Results = null;

            if (request.CountOnly)
            {
                return(new V2SearchResponse
                {
                    TotalHits = result.Count.Value,
                    Debug = DebugInformation.CreateFromSearchOrNull(
                        request,
                        indexName,
                        parameters,
                        text,
                        result,
                        duration,
                        AuxiliaryData.Metadata),
                });
            }
            else
            {
                return(new V2SearchResponse
                {
                    TotalHits = result.Count.Value,
                    Data = results
                           .Select(x =>
                    {
                        var package = toPackage(x.Document);
                        package.Debug = request.ShowDebug ? x : null;
                        return package;
                    })
                           .ToList(),
                    Debug = DebugInformation.CreateFromSearchOrNull(
                        request,
                        indexName,
                        parameters,
                        text,
                        result,
                        duration,
                        AuxiliaryData.Metadata),
                });
            }
        }
예제 #10
0
        public ParsedQuery ParseV2Search(V2SearchRequest request)
        {
            var query = request.Query;

            // The old V2 search service would treat "id:" queries (~match) in the same way as it did "packageid:" (==match).
            // If "id:" is in the query, replace it.
            if (request.LuceneQuery && !string.IsNullOrEmpty(query) && query.StartsWith("id:", StringComparison.OrdinalIgnoreCase))
            {
                query = "packageid:" + query.Substring(3);
            }

            return(GetParsedQuery(query));
        }
            public void SearchFilters(bool includePrerelease, bool includeSemVer2, string filter)
            {
                var request = new V2SearchRequest
                {
                    IncludePrerelease = includePrerelease,
                    IncludeSemVer2    = includeSemVer2,
                    Query             = "js"
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal(filter, output.Filter);
            }
            public void Paging()
            {
                var request = new V2SearchRequest
                {
                    Skip = 10,
                    Take = 30,
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal(10, output.Skip);
                Assert.Equal(30, output.Top);
            }
            public void Defaults()
            {
                var request = new V2SearchRequest();

                var output = _target.V2Search(request, isDefaultSearch: true);

                Assert.Equal(QueryType.Full, output.QueryType);
                Assert.True(output.IncludeTotalResultCount);
                Assert.Equal(DefaultOrderBy, output.OrderBy.ToArray());
                Assert.Equal(0, output.Skip);
                Assert.Equal(0, output.Top);
                Assert.Equal("searchFilters eq 'Default' and (isExcludedByDefault eq false or isExcludedByDefault eq null)", output.Filter);
            }
            public void SortBy(V2SortBy v2SortBy)
            {
                var request = new V2SearchRequest
                {
                    SortBy = v2SortBy,
                };
                var expectedOrderBy = V2SortByToOrderBy[v2SortBy];

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.NotNull(output.OrderBy);
                Assert.Equal(expectedOrderBy, output.OrderBy.ToArray());
            }
            public void IgnoreFilter(bool includePrerelease, bool includeSemVer2, string filter)
            {
                var request = new V2SearchRequest
                {
                    IgnoreFilter      = true,
                    IncludePrerelease = includePrerelease,
                    IncludeSemVer2    = includeSemVer2,
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal(filter, output.Filter);
            }
예제 #16
0
 public V2SearchResponse V2FromHijackDocument(
     V2SearchRequest request,
     string documentKey,
     HijackDocument.Full document,
     TimeSpan duration)
 {
     return(ToResponse(
                request,
                _options.Value.HijackIndexName,
                documentKey,
                document,
                duration,
                p => ToV2SearchPackage(p, request.IncludeSemVer2)));
 }
예제 #17
0
 public V2SearchResponse V2FromSearchDocument(
     V2SearchRequest request,
     string documentKey,
     SearchDocument.Full document,
     TimeSpan duration)
 {
     return(ToResponse(
                request,
                _options.Value.SearchIndexName,
                documentKey,
                document,
                duration,
                p => ToV2SearchPackage(p)));
 }
예제 #18
0
        private V2SearchResponse ToResponse <T>(
            V2SearchRequest request,
            string indexName,
            string documentKey,
            T document,
            TimeSpan duration,
            Func <T, V2SearchPackage> toPackage)
            where T : class
        {
            var data = new List <V2SearchPackage>();

            if (document != null)
            {
                var package = toPackage(document);
                package.Debug = request.ShowDebug ? new DebugDocumentResult {
                    Document = document
                } : null;
                data.Add(package);
            }

            if (request.CountOnly)
            {
                return(new V2SearchResponse
                {
                    TotalHits = data.Count,
                    Debug = DebugInformation.CreateFromGetOrNull(
                        request,
                        indexName,
                        documentKey,
                        duration,
                        AuxiliaryData.Metadata),
                });
            }
            else
            {
                return(new V2SearchResponse
                {
                    TotalHits = data.Count,
                    Data = data,
                    Debug = DebugInformation.CreateFromGetOrNull(
                        request,
                        indexName,
                        documentKey,
                        duration,
                        AuxiliaryData.Metadata),
                });
            }
        }
예제 #19
0
        public ParsedQuery ParseV2Search(V2SearchRequest request)
        {
            var query = request.Query;

            // The old V2 search service would treat "id:" queries (~match) in the same way as it did "packageid:" (==match).
            // If "id:" is in the query, replace it.
            if (request.LuceneQuery && !string.IsNullOrEmpty(query) && query.StartsWith("id:", StringComparison.OrdinalIgnoreCase))
            {
                query = "packageid:" + query.Substring(3);
            }

            // We must include test data when we are querying the hijack index since the owners field is not
            // available in that index. The hijack index is queried when "ignoreFilter=true". Otherwise, the search
            // index is queried and which means it is possible to filter out test data.
            return(GetParsedQuery(query, request.IncludeTestData || request.IgnoreFilter));
        }
예제 #20
0
 public V2SearchResponse V2FromSearch(
     V2SearchRequest request,
     string text,
     SearchParameters parameters,
     DocumentSearchResult <SearchDocument.Full> result,
     TimeSpan duration)
 {
     return(ToResponse(
                request,
                parameters,
                text,
                _options.Value.SearchIndexName,
                result,
                duration,
                p => ToV2SearchPackage(p)));
 }
예제 #21
0
 public V2SearchResponse V2FromHijack(
     V2SearchRequest request,
     string text,
     SearchParameters searchParameters,
     DocumentSearchResult <HijackDocument.Full> result,
     TimeSpan duration)
 {
     return(ToResponse(
                request,
                searchParameters,
                text,
                _options.Value.HijackIndexName,
                result,
                duration,
                p => ToV2SearchPackage(p, request.IncludeSemVer2)));
 }
예제 #22
0
            public void ThrowsWhenQueryHasTooManyClauses(int nonFieldScopedTerms, int fieldScopedTerms, bool shouldThrow)
            {
                var request = new V2SearchRequest {
                    Query = GenerateQuery(nonFieldScopedTerms, fieldScopedTerms)
                };
                var parsed = _target.ParseV2Search(request);

                if (shouldThrow)
                {
                    var e = Assert.Throws <InvalidSearchRequestException>(() => _target.Build(parsed));
                    Assert.Equal("A query can only have up to 1024 clauses.", e.Message);
                }
                else
                {
                    _target.ParseV2Search(request);
                }
            }
예제 #23
0
            public void CanExcludeTestData(string query, bool ignoreFilter, bool includeTestData, string expected)
            {
                _config.TestOwners = new List <string> {
                    "TestUserA", "TestUserB"
                };
                var request = new V2SearchRequest
                {
                    Query           = query,
                    IgnoreFilter    = ignoreFilter,
                    IncludeTestData = includeTestData,
                };
                var parsed = _target.ParseV2Search(request);

                var actual = _target.Build(parsed);

                Assert.Equal(expected, actual.Value);
            }
예제 #24
0
        private async Task <V2SearchResponse> UseSearchIndexAsync(V2SearchRequest request)
        {
            var operation = _operationBuilder.V2SearchWithSearchIndex(request);

            V2SearchResponse output;

            switch (operation.Type)
            {
            case IndexOperationType.Get:
                var documentResult = await Measure.DurationWithValueAsync(
                    () => _searchIndex.Documents.GetOrNullAsync <SearchDocument.Full>(operation.DocumentKey));

                output = _responseBuilder.V2FromSearchDocument(
                    request,
                    operation.DocumentKey,
                    documentResult.Value,
                    documentResult.Duration);

                _telemetryService.TrackV2GetDocumentWithSearchIndex(documentResult.Duration);
                break;

            case IndexOperationType.Search:
                var result = await Measure.DurationWithValueAsync(() => _searchIndex.Documents.SearchAsync <SearchDocument.Full>(
                                                                      operation.SearchText,
                                                                      operation.SearchParameters));

                output = _responseBuilder.V2FromSearch(
                    request,
                    operation.SearchText,
                    operation.SearchParameters,
                    result.Value,
                    result.Duration);

                _telemetryService.TrackV2SearchQueryWithSearchIndex(result.Duration);
                break;

            case IndexOperationType.Empty:
                output = _responseBuilder.EmptyV2(request);
                break;

            default:
                throw UnsupportedOperation(operation);
            }

            return(output);
        }
            public void CountOnly()
            {
                var request = new V2SearchRequest
                {
                    CountOnly = true,
                    Skip      = 10,
                    Take      = 30,
                    SortBy    = V2SortBy.SortableTitleAsc,
                };

                var output = _target.V2Search(request, It.IsAny <bool>());

                Assert.Equal(QueryType.Full, output.QueryType);
                Assert.True(output.IncludeTotalResultCount);
                Assert.Null(output.OrderBy);
                Assert.Equal(0, output.Skip);
                Assert.Equal(0, output.Top);
            }
            public Facts()
            {
                TextBuilder       = new Mock <ISearchTextBuilder>();
                ParametersBuilder = new Mock <ISearchParametersBuilder>();

                AutocompleteRequest = new AutocompleteRequest {
                    Skip = 0, Take = 20
                };
                V2SearchRequest = new V2SearchRequest {
                    Skip = 0, Take = 20
                };
                V3SearchRequest = new V3SearchRequest {
                    Skip = 0, Take = 20
                };
                Text        = "";
                Parameters  = new SearchParameters();
                ParsedQuery = new ParsedQuery(new Dictionary <QueryField, HashSet <string> >());

                TextBuilder
                .Setup(x => x.Autocomplete(It.IsAny <AutocompleteRequest>()))
                .Returns(() => Text);
                TextBuilder
                .Setup(x => x.ParseV2Search(It.IsAny <V2SearchRequest>()))
                .Returns(() => ParsedQuery);
                TextBuilder
                .Setup(x => x.ParseV3Search(It.IsAny <V3SearchRequest>()))
                .Returns(() => ParsedQuery);
                TextBuilder
                .Setup(x => x.Build(It.IsAny <ParsedQuery>()))
                .Returns(() => Text);
                ParametersBuilder
                .Setup(x => x.Autocomplete(It.IsAny <AutocompleteRequest>(), It.IsAny <bool>()))
                .Returns(() => Parameters);
                ParametersBuilder
                .Setup(x => x.V2Search(It.IsAny <V2SearchRequest>(), It.IsAny <bool>()))
                .Returns(() => Parameters);
                ParametersBuilder
                .Setup(x => x.V3Search(It.IsAny <V3SearchRequest>(), It.IsAny <bool>()))
                .Returns(() => Parameters);

                Target = new IndexOperationBuilder(
                    TextBuilder.Object,
                    ParametersBuilder.Object);
            }
예제 #27
0
        public async Task <V2SearchResponse> V2SearchAsync(V2SearchRequest request)
        {
            if (request.IgnoreFilter)
            {
                if (request.PackageType != null && request.PackageType.Any())
                {
                    throw new InvalidSearchRequestException("Can't apply the packageType filter on the Hijack index");
                }
                else if (request.SortBy == V2SortBy.TotalDownloadsAsc || request.SortBy == V2SortBy.TotalDownloadsDesc)
                {
                    throw new InvalidSearchRequestException("Can't sortBy downloads on the Hijack index");
                }

                return(await UseHijackIndexAsync(request));
            }
            else
            {
                return(await UseSearchIndexAsync(request));
            }
        }
        public IndexOperation V2SearchWithSearchIndex(V2SearchRequest request)
        {
            if (HasInvalidParameters(request, packageType: null))
            {
                return(IndexOperation.Empty());
            }

            var parsed = _textBuilder.ParseV2Search(request);

            IndexOperation indexOperation;

            if (TryGetSearchDocumentByKey(request, parsed, out indexOperation))
            {
                return(indexOperation);
            }

            var text       = _textBuilder.Build(parsed);
            var parameters = _parametersBuilder.V2Search(request, IsEmptySearchQuery(text));

            return(IndexOperation.Search(text, parameters));
        }
        public IndexOperation V2SearchWithHijackIndex(V2SearchRequest request)
        {
            if (HasInvalidParameters(request, packageType: null))
            {
                return(IndexOperation.Empty());
            }

            var parsed = _textBuilder.ParseV2Search(request);

            IndexOperation indexOperation;

            if (TryGetHijackDocumentByKey(request, parsed, out indexOperation))
            {
                return(indexOperation);
            }

            var text       = _textBuilder.Build(parsed);
            var parameters = _parametersBuilder.V2Search(request, text.IsDefaultSearch);

            return(IndexOperation.Search(text.Value, parameters));
        }
            public BaseFacts()
            {
                _operationBuilder = new Mock <IIndexOperationBuilder>();
                _searchIndex      = new Mock <ISearchIndexClientWrapper>();
                _searchOperations = new Mock <IDocumentsOperationsWrapper>();
                _hijackIndex      = new Mock <ISearchIndexClientWrapper>();
                _hijackOperations = new Mock <IDocumentsOperationsWrapper>();
                _responseBuilder  = new Mock <ISearchResponseBuilder>();
                _telemetryService = new Mock <IAzureSearchTelemetryService>();

                _v2Request           = new V2SearchRequest();
                _v3Request           = new V3SearchRequest();
                _autocompleteRequest = new AutocompleteRequest();
                _key                  = "key";
                _text                 = "search";
                _parameters           = new SearchParameters();
                _operation            = IndexOperation.Search(_text, _parameters);
                _searchResult         = new DocumentSearchResult <SearchDocument.Full>();
                _searchDocument       = new SearchDocument.Full();
                _hijackResult         = new DocumentSearchResult <HijackDocument.Full>();
                _hijackDocument       = new HijackDocument.Full();
                _v2Response           = new V2SearchResponse();
                _v3Response           = new V3SearchResponse();
                _autocompleteResponse = new AutocompleteResponse();

                _operationBuilder
                .Setup(x => x.V2SearchWithHijackIndex(It.IsAny <V2SearchRequest>()))
                .Returns(() => _operation);
                _operationBuilder
                .Setup(x => x.V2SearchWithSearchIndex(It.IsAny <V2SearchRequest>()))
                .Returns(() => _operation);
                _operationBuilder
                .Setup(x => x.V3Search(It.IsAny <V3SearchRequest>()))
                .Returns(() => _operation);
                _operationBuilder
                .Setup(x => x.Autocomplete(It.IsAny <AutocompleteRequest>()))
                .Returns(() => _operation);

                // Set up the search to take at least one millisecond. This allows us to test the measured duration.
                _searchOperations
                .Setup(x => x.SearchAsync <SearchDocument.Full>(It.IsAny <string>(), It.IsAny <SearchParameters>()))
                .ReturnsAsync(() => _searchResult)
                .Callback(() => Thread.Sleep(TimeSpan.FromMilliseconds(1)));
                _searchOperations
                .Setup(x => x.GetOrNullAsync <SearchDocument.Full>(It.IsAny <string>()))
                .ReturnsAsync(() => _searchDocument)
                .Callback(() => Thread.Sleep(TimeSpan.FromMilliseconds(1)));
                _hijackOperations
                .Setup(x => x.SearchAsync <HijackDocument.Full>(It.IsAny <string>(), It.IsAny <SearchParameters>()))
                .ReturnsAsync(() => _hijackResult)
                .Callback(() => Thread.Sleep(TimeSpan.FromMilliseconds(1)));
                _hijackOperations
                .Setup(x => x.GetOrNullAsync <HijackDocument.Full>(It.IsAny <string>()))
                .ReturnsAsync(() => _hijackDocument)
                .Callback(() => Thread.Sleep(TimeSpan.FromMilliseconds(1)));

                _responseBuilder
                .Setup(x => x.V2FromHijack(
                           It.IsAny <V2SearchRequest>(),
                           It.IsAny <string>(),
                           It.IsAny <SearchParameters>(),
                           It.IsAny <DocumentSearchResult <HijackDocument.Full> >(),
                           It.IsAny <TimeSpan>()))
                .Returns(() => _v2Response);
                _responseBuilder
                .Setup(x => x.V2FromHijackDocument(
                           It.IsAny <V2SearchRequest>(),
                           It.IsAny <string>(),
                           It.IsAny <HijackDocument.Full>(),
                           It.IsAny <TimeSpan>()))
                .Returns(() => _v2Response);
                _responseBuilder
                .Setup(x => x.V2FromSearch(
                           It.IsAny <V2SearchRequest>(),
                           It.IsAny <string>(),
                           It.IsAny <SearchParameters>(),
                           It.IsAny <DocumentSearchResult <SearchDocument.Full> >(),
                           It.IsAny <TimeSpan>()))
                .Returns(() => _v2Response);
                _responseBuilder
                .Setup(x => x.V2FromSearchDocument(
                           It.IsAny <V2SearchRequest>(),
                           It.IsAny <string>(),
                           It.IsAny <SearchDocument.Full>(),
                           It.IsAny <TimeSpan>()))
                .Returns(() => _v2Response);
                _responseBuilder
                .Setup(x => x.V3FromSearch(
                           It.IsAny <V3SearchRequest>(),
                           It.IsAny <string>(),
                           It.IsAny <SearchParameters>(),
                           It.IsAny <DocumentSearchResult <SearchDocument.Full> >(),
                           It.IsAny <TimeSpan>()))
                .Returns(() => _v3Response);
                _responseBuilder
                .Setup(x => x.V3FromSearchDocument(
                           It.IsAny <V3SearchRequest>(),
                           It.IsAny <string>(),
                           It.IsAny <SearchDocument.Full>(),
                           It.IsAny <TimeSpan>()))
                .Returns(() => _v3Response);
                _responseBuilder
                .Setup(x => x.AutocompleteFromSearch(
                           It.IsAny <AutocompleteRequest>(),
                           It.IsAny <string>(),
                           It.IsAny <SearchParameters>(),
                           It.IsAny <DocumentSearchResult <SearchDocument.Full> >(),
                           It.IsAny <TimeSpan>()))
                .Returns(() => _autocompleteResponse);
                _responseBuilder
                .Setup(x => x.EmptyV2(It.IsAny <V2SearchRequest>()))
                .Returns(() => _v2Response);
                _responseBuilder
                .Setup(x => x.EmptyV3(It.IsAny <V3SearchRequest>()))
                .Returns(() => _v3Response);
                _responseBuilder
                .Setup(x => x.EmptyAutocomplete(It.IsAny <AutocompleteRequest>()))
                .Returns(() => _autocompleteResponse);

                _searchIndex.Setup(x => x.Documents).Returns(() => _searchOperations.Object);
                _hijackIndex.Setup(x => x.Documents).Returns(() => _hijackOperations.Object);

                _target = new AzureSearchService(
                    _operationBuilder.Object,
                    _searchIndex.Object,
                    _hijackIndex.Object,
                    _responseBuilder.Object,
                    _telemetryService.Object);
            }