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); }
public V2SearchResponse EmptyV2(V2SearchRequest request) { return(new V2SearchResponse { TotalHits = 0, Data = new List <V2SearchPackage>(), Debug = DebugInformation.CreateFromEmptyOrNull(request), }); }
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); }
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); }
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); }
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), }); } }
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); }
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))); }
public V2SearchResponse V2FromSearchDocument( V2SearchRequest request, string documentKey, SearchDocument.Full document, TimeSpan duration) { return(ToResponse( request, _options.Value.SearchIndexName, documentKey, document, duration, p => ToV2SearchPackage(p))); }
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), }); } }
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)); }
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))); }
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))); }
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); } }
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); }
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); }
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); }