public async Task SearchOrganisationBySearchParamsReturnsOrganisationsInTheSortOrderSpecified()
        {
            var session = EntityHelpers.CreateSession("Admin");

            DatabaseContext.Sessions.Add(session);
            Client.DefaultRequestHeaders.Add("Cookie", $"access_token={session.Payload}");
            var rand          = new Random();
            var organisations = EntityHelpers.CreateOrganisations(10).ToList();
            var searchParam   = Randomm.Word();
            var first         = rand.Next(10, 20);
            var second        = rand.Next(20, 30);

            organisations[5].Name = searchParam + first;
            organisations[3].Name = searchParam + second;
            DatabaseContext.Organisations.AddRange(organisations);
            DatabaseContext.SaveChanges();
            var requestUri = new Uri($"api/v1/organisations?search={searchParam}&sort=name&direction=asc", UriKind.Relative);
            var response   = await Client.GetAsync(requestUri).ConfigureAwait(true);

            response.StatusCode.Should().Be(200);
            var content        = response.Content;
            var stringResponse = await content.ReadAsStringAsync().ConfigureAwait(true);

            var deserializedBody = JsonConvert.DeserializeObject <OrganisationResponseList>(stringResponse);

            deserializedBody.Should().NotBeNull();
            deserializedBody.Organisations[0].Name.Should().BeEquivalentTo(organisations[5].Name);
            deserializedBody.Organisations[1].Name.Should().BeEquivalentTo(organisations[3].Name);
        }
        public void CreateOrganisationUseCaseCallsGatewayCreateOrganisation()
        {
            var requestParams = Randomm.Create <OrganisationRequest>();
            var accessToken   = Randomm.Word();

            _classUnderTest.ExecuteCreate(accessToken, requestParams);
            _mockOrganisationsGateway.Verify(u => u.CreateOrganisation(It.IsAny <Organisation>()), Times.Once);
        }
Example #3
0
        public async Task SearchServicesReturnServicesAccordingToRankIfMatched()
        {
            var searchWord1    = Randomm.Word();
            var searchWord2    = Randomm.Word();
            var irrelevantWord = Randomm.Word();
            var bridgeSyn1Word = Utility.SuperSetOfString(searchWord1);
            var bridgeSyn2Word = Utility.SuperSetOfString(searchWord2);
            var synWord1       = Randomm.Word();
            var synWord2       = Randomm.Word();
            var synWord3       = Randomm.Word();
            var synonymGroup1  = EntityHelpers.CreateSynonymGroupWithWords();
            var synonymGroup2  = EntityHelpers.CreateSynonymGroupWithWords();
            var dummySynGroup  = EntityHelpers.CreateSynonymGroupWithWords();
            var bridgeSynonym1 = EntityHelpers.SynWord(synonymGroup1, bridgeSyn1Word);
            var bridgeSynonym2 = EntityHelpers.SynWord(synonymGroup2, bridgeSyn2Word);
            var matchSynonym1  = EntityHelpers.SynWord(synonymGroup1, synWord1);
            var matchSynonym2  = EntityHelpers.SynWord(synonymGroup1, synWord2);
            var matchSynonym3  = EntityHelpers.SynWord(synonymGroup2, synWord3);

            synonymGroup1.SynonymWords.Add(bridgeSynonym1);
            synonymGroup2.SynonymWords.Add(bridgeSynonym2);
            synonymGroup1.SynonymWords.Add(matchSynonym1);
            synonymGroup1.SynonymWords.Add(matchSynonym2);
            synonymGroup2.SynonymWords.Add(matchSynonym3);
            var services      = EntityHelpers.CreateServices(5);
            var matchService1 = EntityHelpers.CreateService();
            var matchService2 = EntityHelpers.CreateService();
            var matchService3 = EntityHelpers.CreateService();
            var matchService4 = EntityHelpers.CreateService();

            matchService1.Name += searchWord2;
            //matchService2.Description += synWord2;
            matchService2.Description += " " + synWord2; //15 Feb 2021 - Change made so we only search for whole words in the service description! - So we add a space.

            matchService3.Organization.Name += synWord3;
            matchService4.Organization.Name += searchWord1;
            services.AddMany(matchService1, matchService2, matchService3, matchService4);
            DatabaseContext.SynonymGroups.AddRange(synonymGroup1);
            DatabaseContext.SynonymGroups.AddRange(synonymGroup2);
            DatabaseContext.SynonymGroups.AddRange(dummySynGroup);
            DatabaseContext.Services.AddRange(services);
            DatabaseContext.SaveChanges();

            var requestUri = new Uri($"api/v1/services?search={searchWord1} {searchWord2} {irrelevantWord}", UriKind.Relative);
            var response   = Client.GetAsync(requestUri).Result;

            response.StatusCode.Should().Be(200);
            var content       = response.Content;
            var stringContent = await content.ReadAsStringAsync().ConfigureAwait(false);

            var deserializedBody = JsonConvert.DeserializeObject <GetServiceResponseList>(stringContent);

            deserializedBody.Services.Count.Should().Be(4);
            deserializedBody.Services[0].Name.Should().Be(matchService4.Name);
            deserializedBody.Services[1].Name.Should().Be(matchService1.Name);
            deserializedBody.Services[2].Name.Should().Be(matchService3.Name);
            deserializedBody.Services[3].Name.Should().Be(matchService2.Name);
        }
        [TestCase(TestName = "Given Addresses API context's GetAddressesRequest method is called, When an unexpected exception is thrown during its execution, Then the AddressesGateway rethrows that exception so it could be handled elsewhere.")] // it should be handled where all the other exceptions are handled. Gateway can't be the one handling it because as requested it only has to return the coordinates. TODO: improve on this.
        public void GivenAnUnexpectedExceptionIsThrownInTheGatewayThenItShouldRethrowThatException()                                                                                                                                                  // Like WebException (Timeout, Connect failure)
        {
            // arrange
            var expectedException = new WebException(Randomm.Word(), WebExceptionStatus.Timeout);

            _mockAddressesApiContext.Setup(c => c.GetAddressesRequest(It.IsAny <string>()))
            .Throws(expectedException);

            // act
            Action gatewayCall = () => _classUnderTest.GetPostcodeCoordinates(It.IsAny <string>());

            // assert
            gatewayCall.Should().Throw <WebException>();
        }
        [TestCase(TestName = "Given user provided search term consisting of multiple words, When services get filtered in SearchService method, Then the returned services are categorized into Full user input match Or Split match.")] // done so to ensure the less relevant services are in the separate collection
        public void SearchServiceGatewaySeparatesOutFullMatchResultsFromSplitMatch()
        {
            // arrange
            var word1           = Randomm.Word();
            var word2           = Randomm.Word();
            var userSearchInput = $"{word1} {word2}";

            var request = new SearchServicesRequest()
            {
                Search = userSearchInput
            };

            var services       = new List <Service>();
            var serviceToFind1 = EntityHelpers.CreateService();                 // full match

            serviceToFind1.Name += userSearchInput;
            var serviceToFind2 = EntityHelpers.CreateService();                 // split match 1

            serviceToFind2.Name += word1;
            var serviceToFind3 = EntityHelpers.CreateService();                 // split match 2

            serviceToFind3.Name += word2;

            services.Add(serviceToFind1);
            services.Add(serviceToFind2);
            services.Add(serviceToFind3);
            DatabaseContext.Services.AddRange(services);
            DatabaseContext.SaveChanges();

            // act
            var gatewayResult = _classUnderTest.SearchServices(request);
            var fullMatches   = gatewayResult.FullMatchServices;
            var splitMatches  = gatewayResult.SplitMatchServices;

            // assert
            gatewayResult.Should().NotBeNull();
            fullMatches.Should().NotBeNull();
            splitMatches.Should().NotBeNull();

            fullMatches.Should().Contain(s => s.Name.Contains(userSearchInput, StringComparison.OrdinalIgnoreCase));
            fullMatches.Should().HaveCount(1);

            splitMatches.Should().Contain(s => s.Name.Contains(word1, StringComparison.OrdinalIgnoreCase));
            splitMatches.Should().Contain(s => s.Name.Contains(word2, StringComparison.OrdinalIgnoreCase));
            splitMatches.Should().NotContain(s => s.Name.Contains(userSearchInput, StringComparison.OrdinalIgnoreCase));
            splitMatches.Should().HaveCount(2);
        }
        public void WhenDoingPartialTextSearchMatchesWordsOf3orLessCharactersLongGetIgnored()  //it's too short - these will be searched and found inside other words in DB
        {
            // arrange
            var shortWordList = new List <string> {
                "and", "a", "an", "the", "bfg", "42"
            };
            var shortWord = shortWordList.RandomItem();

            var word            = Randomm.Word().Replace(shortWord, "test");// have to ensure the shortword is not contained in the actual word for the sake of test
            var userSearchInput = $"{shortWord} {word}";

            var request = new SearchServicesRequest()
            {
                Search = userSearchInput
            };

            var services = EntityHelpers.CreateServices(5).ToList();             //dummy services

            services.ForEach(s => s.Name = s.Name.Replace(word, "ssj"));         //make sure they don't match the search word
            //assuming there's no full match. due to full match containing a shortword, the assertion at the bottom wouldn't be able to test what's needed.
            var serviceToFind = EntityHelpers.CreateService();                   // word 1 match

            serviceToFind.Name  = serviceToFind.Name.Replace(shortWord, "test"); //ensuring random hash does not contain shortword. for the assertion bellow to work as intended, the service name's hash part should not contain shortword.
            serviceToFind.Name += word;

            var serviceToNotFind = EntityHelpers.CreateService();                   // shortword no match. this ensures that the test can fail if the implementation is wrong or not present.

            serviceToNotFind.Name  = serviceToNotFind.Name.Replace(word, "1234");   // make sure the mismatching service does not contain a desired search term
            serviceToNotFind.Name += shortWord;

            services.Add(serviceToFind);
            services.Add(serviceToNotFind);
            DatabaseContext.Services.AddRange(services);
            DatabaseContext.SaveChanges();

            // act
            var gatewayResult = _classUnderTest.SearchServices(request);
            var splitMatches  = gatewayResult.SplitMatchServices;

            // assert
            gatewayResult.Should().NotBeNull();
            splitMatches.Should().NotBeNull();

            splitMatches.Should().NotContain(s => s.Name.Contains(shortWord, StringComparison.OrdinalIgnoreCase));
            splitMatches.Should().HaveCount(1);
        }
        //[TestCase(TestName = "Given an organisation domain object is provided the created organisation is returned")]
        public void ReturnsCreatedOrganisation()
        {
            var requestParams = Randomm.Create <OrganisationRequest>();
            var domainData    = requestParams.ToDomain();
            var accessToken   = Randomm.Word();
            var users         = new List <UserDomain> {
                Randomm.Create <UserDomain>()
            };

            _mockOrganisationsGateway.Setup(g => g.CreateOrganisation(It.IsAny <Organisation>())).Returns(domainData);
            _mockUsersGateway.Setup(ug => ug.GetAllUsers(It.IsAny <UserQueryParam>())).ReturnsAsync(users);
            var expectedResponse = domainData.ToResponse();
            var response         = _classUnderTest.ExecuteCreate(accessToken, requestParams);

            response.Should().NotBeNull();
            response.Should().BeEquivalentTo(expectedResponse);
        }
        public void UponFilteringServicesByAMultiWordInputTheReturnedResultsIncludePartialMatches()
        {
            // arrange
            var word1           = Randomm.Word();
            var word2           = Randomm.Word();
            var userSearchInput = $"{word1} {word2}";

            var request = new SearchServicesRequest()
            {
                Search = userSearchInput
            };

            var services       = EntityHelpers.CreateServices(5).ToList();      // dummy services
            var serviceToFind1 = EntityHelpers.CreateService();                 // full match

            serviceToFind1.Name += userSearchInput;
            var serviceToFind2 = EntityHelpers.CreateService();                 // word 1 match

            serviceToFind2.Name += word1;
            var serviceToFind3 = EntityHelpers.CreateService();                 // word 2 match

            serviceToFind3.Name += word2;

            services.Add(serviceToFind1);
            services.Add(serviceToFind2);
            services.Add(serviceToFind3);
            DatabaseContext.Services.AddRange(services);
            DatabaseContext.SaveChanges();

            // act
            var gatewayResult    = _classUnderTest.SearchServices(request);
            var fullMatches      = gatewayResult.FullMatchServices;
            var splitMatches     = gatewayResult.SplitMatchServices;
            var returnedServices = fullMatches.Concat(splitMatches).ToList();

            // assert
            gatewayResult.Should().NotBeNull();
            fullMatches.Should().NotBeNull();
            splitMatches.Should().NotBeNull();

            returnedServices.Should().Contain(s => s.Name.Contains(userSearchInput, StringComparison.OrdinalIgnoreCase));
            returnedServices.Should().Contain(s => s.Name.Contains(word1, StringComparison.OrdinalIgnoreCase));
            returnedServices.Should().Contain(s => s.Name.Contains(word2, StringComparison.OrdinalIgnoreCase));
            returnedServices.Should().HaveCount(3);
        }
Example #9
0
        public async Task CreateServiceUseCaseCallsGatewayCreateService()
        {
            var requestParams   = Randomm.Create <ServiceRequest>();
            var locationRequest = Randomm.Create <ServiceLocationRequest>();

            requestParams.Locations = new List <ServiceLocationRequest>()
            {
                locationRequest
            };
            var domainData = requestParams.ToDomain();

            domainData.Organisation = Randomm.Create <OrganisationDomain>();
            var accessToken = Randomm.Word();

            _mockServicesGateway.Setup(g => g.CreateService(It.IsAny <ServiceRequest>())).ReturnsAsync(domainData);
            var myResult = await _classUnderTest.Execute(requestParams).ConfigureAwait(false);

            _mockServicesGateway.Verify(u => u.CreateService(It.IsAny <ServiceRequest>()), Times.Once);
        }
        public void AddressesGatewayShouldThrowAnErrorWhenAPICallReturnsUnexpectedSchema(int statusCode) // if anything about the Addresses API changes, ResponseSchemaNotRecognisedException //TODO: should contain api name
        {
            // arrange
            var contextResponse = Randomm.AddressesAPIContextResponse(statusCode == 9000 ? 400 : statusCode);

            switch (statusCode)
            {
            case 200:
                contextResponse.JsonContent =
                    contextResponse.JsonContent.Replace("Data", Randomm.Word()
                                                        , StringComparison.OrdinalIgnoreCase);
                break;

            case 400:
                contextResponse.JsonContent =
                    contextResponse.JsonContent.Replace("validationErrors", Randomm.Word()
                                                        , StringComparison.OrdinalIgnoreCase);
                break;

            case 500:
                contextResponse.JsonContent =
                    contextResponse.JsonContent.Replace("Errors", Randomm.Word()
                                                        , StringComparison.OrdinalIgnoreCase);
                break;

            default:
                contextResponse.JsonContent =
                    contextResponse.JsonContent.Replace("error", Randomm.Word()
                                                        , StringComparison.OrdinalIgnoreCase);
                break;
            }

            _mockAddressesApiContext.Setup(c => c.GetAddressesRequest(It.IsAny <string>())).Returns(contextResponse);

            // act
            Action gatewayCall = () => _classUnderTest.GetPostcodeCoordinates(It.IsAny <string>());

            // assert
            gatewayCall.Should().Throw <ResponseSchemaNotRecognisedException>();
        }
        public async Task UpdateServiceUseCaseWithLocationCallsAddressXrefGateway()
        {
            var requestParams = Randomm.Create <ServiceRequest>();
            var orgDomain     = Randomm.Create <OrganisationDomain>();

            requestParams.OrganisationId = orgDomain.Id;
            var locationRequest = Randomm.Create <ServiceLocationRequest>();

            requestParams.Locations = new List <ServiceLocationRequest>()
            {
                locationRequest
            };
            var serviceDomainData = requestParams.ToDomain();

            serviceDomainData.Organisation = orgDomain;
            serviceDomainData.Id           = 123;
            var accessToken = Randomm.Word();

            _mockServicesGateway.Setup(g => g.UpdateService(It.IsAny <ServiceRequest>(), 123)).ReturnsAsync(serviceDomainData);
            _mockAddressXRefGateway.Setup(g => g.GetNHSNeighbourhood(It.IsAny <string>())).Returns("NHS1");
            var response = await _classUnderTest.Execute(requestParams, 123).ConfigureAwait(false);

            response.Should().NotBeNull();
            response.Should().BeEquivalentTo(serviceDomainData, options =>
            {
                options.Excluding(ex => ex.ImageId);
                options.Excluding(ex => ex.ServiceTaxonomies);
                options.Excluding(ex => ex.Organisation);
                options.Excluding(ex => ex.ServiceLocations);
                return(options);
            });
            response.Locations.FirstOrDefault().Address1.Should().Be(serviceDomainData.ServiceLocations.FirstOrDefault().Address1);
            response.Locations.FirstOrDefault().Address2.Should().Be(serviceDomainData.ServiceLocations.FirstOrDefault().Address2);
            response.Locations.FirstOrDefault().City.Should().Be(serviceDomainData.ServiceLocations.FirstOrDefault().City);
            response.Locations.FirstOrDefault().Country.Should().Be(serviceDomainData.ServiceLocations.FirstOrDefault().Country);
            response.Locations.FirstOrDefault().NHSNeighbourhood.Should().Be(serviceDomainData.ServiceLocations.FirstOrDefault().NHSNeighbourhood);
        }
        public void WholeAndSplitUserInputMatchesAreReturnedInCorrectRank()
        {
            // arrange
            var searchWord1    = Randomm.Word();                         // word that won't match any results, however 1 of its synonyms from synonym group will
            var searchWord2    = Randomm.Word();                         // same as above, but the matching synonym will be in another synonym group
            var irrelevantWord = Randomm.Word();                         // a control word, that won't match anything, nor its synonyms will.

            var userInput = $"{searchWord1} "
                            + $"{irrelevantWord} "
                            + $"{searchWord2}";

            var request = new SearchServicesRequest();

            request.Search = userInput;

            var bridgeSyn1Word = Utility.SuperSetOfString(searchWord1);     // A superset word of search word 1 that will relate to a synonym word inside synonym group 1 - this word has no match in the DB
            var bridgeSyn2Word = Utility.SuperSetOfString(searchWord2);     // A superset word of search word 2 that will relate to a synonym word inside synonym group 2 - this word has no match in the DB


            var synWord1 = Randomm.Word();                            // synonym within the same synonym group (1) as a word related to search word 1 - this word has a match in the DB
            var synWord2 = Randomm.Word();                            // synonym within the same synonym group (1) as a word related to search word 1 - this word has a match in the DB
            var synWord3 = Randomm.Word();                            // synonym within the same synonym group (2) as a word related to search word 2 - this word has a match in the DB


            var synonymGroup1 = EntityHelpers.CreateSynonymGroupWithWords();            // relevant group with dummy synonym words
            var synonymGroup2 = EntityHelpers.CreateSynonymGroupWithWords();            // relevant group with dummy synonym words
            var dummySynGroup = EntityHelpers.CreateSynonymGroupWithWords();            // dummy synonym group that should not be picked up

            var bridgeSynonym1 = EntityHelpers.SynWord(synonymGroup1, bridgeSyn1Word);  // synonym that has no match in DB, however it bridges user input search word with the synonym group 1
            var bridgeSynonym2 = EntityHelpers.SynWord(synonymGroup2, bridgeSyn2Word);

            var matchSynonym1 = EntityHelpers.SynWord(synonymGroup1, synWord1);         // creating a synonym word object to insert that will have a match, creating a link with synonym group 1
            var matchSynonym2 = EntityHelpers.SynWord(synonymGroup1, synWord2);
            var matchSynonym3 = EntityHelpers.SynWord(synonymGroup2, synWord3);


            synonymGroup1.SynonymWords.Add(bridgeSynonym1);                  // added bridge synonym to the synonym group
            synonymGroup2.SynonymWords.Add(bridgeSynonym2);

            synonymGroup1.SynonymWords.Add(matchSynonym1);                   // added match synonym into a synonym group
            synonymGroup1.SynonymWords.Add(matchSynonym2);
            synonymGroup2.SynonymWords.Add(matchSynonym3);


            var services = EntityHelpers.CreateServices(5);                               // creating list of dummy services that should not be found

            var matchService1 = EntityHelpers.CreateService();                            // service that is intended to be found through the synonym of synonym group 1
            var matchService2 = EntityHelpers.CreateService();                            // service that is intended to be found through the synonym of synonym group 1
            var matchService3 = EntityHelpers.CreateService();                            // service that is intended to be found through the synonym of synonym group 2
            var matchService4 = EntityHelpers.CreateService();                            // service that is intended to be found through the main search term

            matchService1.Name += searchWord2;                                            // creating a link between a service and a match synonym 1
                                                                                          // creating a link between a service and a match synonym 2
            matchService2.Description += " " + synWord2;                                  //15 Feb 2021 - Change made so we only search for whole words in the service description! - So we add a space.

            matchService3.Organization.Name += synWord3;                                  // creating a link between a service and a match synonym 3
            matchService4.Organization.Name += searchWord1;                               // creating a link between a service and a main search word

            services.AddMany(matchService1, matchService2, matchService3, matchService4); // include match services into a to be inserted services collection

            DatabaseContext.SynonymGroups.AddRange(synonymGroup1);                        // adding synonym groups containing synonym words into a database
            DatabaseContext.SynonymGroups.AddRange(synonymGroup2);
            DatabaseContext.SynonymGroups.AddRange(dummySynGroup);
            DatabaseContext.Services.AddRange(services);                     // adding services into a database

            DatabaseContext.SaveChanges();

            // act
            var gatewayResult = _classUnderTest.SearchServices(request);
            var splitMatches  = gatewayResult.SplitMatchServices;
            var fullMatches   = gatewayResult.FullMatchServices;

            // assert
            splitMatches.Should().HaveCount(4);
            fullMatches.Should().HaveCount(0);
            splitMatches[0].Name.Should().Be(matchService4.Name);
            splitMatches[1].Name.Should().Be(matchService1.Name);
            splitMatches[2].Name.Should().Be(matchService3.Name);
            splitMatches[3].Name.Should().Be(matchService2.Name);
        }