public async Task GetJobDefinitionById_GivenDefinitionFound_ReturnsOKObjectResult()
        {
            //Arrange
            const string jobDefinitionId = "jobdef-1";

            List <JobDefinition> jobDefinitions = new List <JobDefinition>
            {
                new JobDefinition
                {
                    Id = jobDefinitionId
                }
            };

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions))
            .Returns(jobDefinitions);

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(cacheProvider: cacheProvider);

            //Act
            IActionResult result = await jobDefinitionsService.GetJobDefinitionById(jobDefinitionId);

            //Assert
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeEquivalentTo(jobDefinitions.First());
        }
        public async Task GetJobDefinitions_GivenNotInCacheAndNotInCosmos_ReturnsNullListAndDoesNotSetInCache()
        {
            //Arrange
            List <JobDefinition> jobDefinitions = null;

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions))
            .Returns(jobDefinitions);

            IJobDefinitionsRepository jobDefinitionsRepository = CreateJobDefinitionsRepository();

            jobDefinitionsRepository
            .GetJobDefinitions()
            .Returns(jobDefinitions);

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(jobDefinitionsRepository, resiliencePolicies: GenerateTestPolicies(), cacheProvider: cacheProvider);

            //Act
            IActionResult result = await jobDefinitionsService.GetJobDefinitions();

            //Assert
            result
            .Should()
            .BeOfType <NotFoundObjectResult>()
            .Which
            .Value
            .Should()
            .Be("No job definitions were found");
        }
        public async Task GetJobDefinitionById_GivenDefinitionNotFound_ReturnsNotFoundResult()
        {
            //Arrange
            const string jobDefinitionId = "jobdef-1";

            List <JobDefinition> jobDefinitions = null;

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions))
            .Returns(jobDefinitions);

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(cacheProvider: cacheProvider, resiliencePolicies: GenerateTestPolicies());

            //Act
            IActionResult result = await jobDefinitionsService.GetJobDefinitionById(jobDefinitionId);

            //Assert
            result
            .Should()
            .BeOfType <NotFoundObjectResult>()
            .Which
            .Value
            .Should()
            .Be($"No job definitions were found for id {jobDefinitionId}");
        }
        public async Task GetJobDefinitions_GivenResultsFoundAndNotInCosmos_ReturnsOKObjectResultotSetInCache()
        {
            //Arrange
            List <JobDefinition> jobDefinitions = new List <JobDefinition>
            {
                new JobDefinition()
            };

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions))
            .Returns(jobDefinitions);

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(cacheProvider: cacheProvider);

            //Act
            IActionResult result = await jobDefinitionsService.GetJobDefinitions();

            //Assert
            result
            .Should()
            .BeOfType <OkObjectResult>()
            .Which
            .Value
            .Should()
            .BeEquivalentTo(jobDefinitions);
        }
        public async Task SaveDefinition_GivenEmptyJson_ReturnsBadRequest()
        {
            //Arrange
            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("json-file", new StringValues(jsonFile));

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            ILogger logger = CreateLogger();

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(logger: logger);

            //Act
            IActionResult result = await jobDefinitionsService.SaveDefinition(request);

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be($"Invalid json was provided for file: {jsonFile}");

            logger
            .Received(1)
            .Error(Arg.Is($"Null or empty json provided for file: {jsonFile}"));
        }
        public async Task GetAllJobDefinitions_GivenNotInCacheAndNotInCosmos_ReturnsNullListAndDoesNotSetInCache()
        {
            //Arrange
            List <JobDefinition> jobDefinitions = null;

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions))
            .Returns(jobDefinitions);

            IJobDefinitionsRepository jobDefinitionsRepository = CreateJobDefinitionsRepository();

            jobDefinitionsRepository
            .GetJobDefinitions()
            .Returns(jobDefinitions);

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(jobDefinitionsRepository, resiliencePolicies: GenerateTestPolicies(), cacheProvider: cacheProvider);

            //Act
            IEnumerable <JobDefinition> definitions = await jobDefinitionsService.GetAllJobDefinitions();

            //Assert
            definitions
            .Should()
            .BeNull();

            await
            cacheProvider
            .DidNotReceive()
            .SetAsync(Arg.Any <string>(), Arg.Any <List <JobDefinition> >());
        }
        public async Task GetAllJobDefinitions_GivenAlreadyInCache_ReturnsFromCache()
        {
            //Arrange
            List <JobDefinition> jobDefinitions = new List <JobDefinition>
            {
                new JobDefinition()
            };

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions))
            .Returns(jobDefinitions);

            IJobDefinitionsRepository jobDefinitionsRepository = CreateJobDefinitionsRepository();

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(jobDefinitionsRepository, cacheProvider: cacheProvider);

            //Act
            IEnumerable <JobDefinition> definitions = await jobDefinitionsService.GetAllJobDefinitions();

            //Assert
            definitions
            .Count()
            .Should()
            .Be(1);

            jobDefinitionsRepository
            .DidNotReceive()
            .GetJobDefinitions();
        }
        public async Task SaveDefinition_GivenValidJsonButSavingThrowsException_ReturnsInternalServerError()
        {
            //Arrange
            string yaml = JsonConvert.SerializeObject(new JobDefinition());

            byte[]       byteArray = Encoding.UTF8.GetBytes(yaml);
            MemoryStream stream    = new MemoryStream(byteArray);

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("json-file", new StringValues(jsonFile));

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            IJobDefinitionsRepository jobDefinitionsRepository = CreateJobDefinitionsRepository();

            jobDefinitionsRepository
            .When(x => x.SaveJobDefinition(Arg.Any <JobDefinition>()))
            .Do(x => { throw new Exception(); });


            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(logger: logger, jobDefinitionsRepository: jobDefinitionsRepository);

            //Act
            IActionResult result = await jobDefinitionsService.SaveDefinition(request);

            //Assert
            result
            .Should()
            .BeOfType <InternalServerErrorResult>()
            .Which
            .Value
            .Should()
            .Be($"Exception occurred writing json file: {jsonFile} to cosmos db");

            logger
            .Received(1)
            .Error(Arg.Any <Exception>(), Arg.Is($"Exception occurred writing json file: {jsonFile} to cosmos db"));
        }
        public async Task SaveDefinition_GivenValidJsonButSavingReturns400_ReturnsStatusCodeResult400()
        {
            //Arrange
            string yaml = JsonConvert.SerializeObject(new JobDefinition());

            byte[]       byteArray = Encoding.UTF8.GetBytes(yaml);
            MemoryStream stream    = new MemoryStream(byteArray);

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("json-file", new StringValues(jsonFile));

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            IJobDefinitionsRepository jobDefinitionsRepository = CreateJobDefinitionsRepository();

            jobDefinitionsRepository
            .SaveJobDefinition(Arg.Any <JobDefinition>())
            .Returns(HttpStatusCode.BadRequest);

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(logger: logger, jobDefinitionsRepository: jobDefinitionsRepository);

            //Act
            IActionResult result = await jobDefinitionsService.SaveDefinition(request);

            //Assert
            result
            .Should()
            .BeOfType <StatusCodeResult>()
            .Which
            .StatusCode
            .Should()
            .Be(400);

            logger
            .Received(1)
            .Error(Arg.Is($"Failed to save json file: {jsonFile} to cosmos db with status 400"));
        }
        public async Task SaveDefinition_GivenJsonSavesOK_ReturnsNoContentResult()
        {
            //Arrange
            string yaml = JsonConvert.SerializeObject(new JobDefinition());

            byte[]       byteArray = Encoding.UTF8.GetBytes(yaml);
            MemoryStream stream    = new MemoryStream(byteArray);

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("json-file", new StringValues(jsonFile));

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            IJobDefinitionsRepository jobDefinitionsRepository = CreateJobDefinitionsRepository();

            jobDefinitionsRepository
            .SaveJobDefinition(Arg.Any <JobDefinition>())
            .Returns(HttpStatusCode.OK);

            ICacheProvider cacheProvider = CreateCacheProvider();

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(logger: logger, jobDefinitionsRepository: jobDefinitionsRepository, cacheProvider: cacheProvider);

            //Act
            IActionResult result = await jobDefinitionsService.SaveDefinition(request);

            //Assert
            result
            .Should()
            .BeOfType <NoContentResult>();

            await
            cacheProvider
            .Received(1)
            .RemoveAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions));
        }
        public async Task SaveDefinition_GivenInvalidJson_ReturnsBadRequest()
        {
            //Arrange
            string yaml = "invalid json";

            byte[]       byteArray = Encoding.UTF8.GetBytes(yaml);
            MemoryStream stream    = new MemoryStream(byteArray);

            IHeaderDictionary headerDictionary = new HeaderDictionary();

            headerDictionary
            .Add("json-file", new StringValues(jsonFile));

            HttpRequest request = Substitute.For <HttpRequest>();

            request
            .Headers
            .Returns(headerDictionary);

            request
            .Body
            .Returns(stream);

            ILogger logger = CreateLogger();

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(logger: logger);

            //Act
            IActionResult result = await jobDefinitionsService.SaveDefinition(request);

            //Assert
            result
            .Should()
            .BeOfType <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be($"Invalid json was provided for file: {jsonFile}");

            logger
            .Received(1)
            .Error(Arg.Any <Exception>(), Arg.Is($"Invalid json was provided for file: {jsonFile}"));
        }
        public async Task GetJobDefinitionById_GivenInvalidDefinitionId_ReturnsBadRequestResult()
        {
            //Arrange
            const string jobDefinitionId = "";

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService();

            //Act
            IActionResult result = await jobDefinitionsService.GetJobDefinitionById(jobDefinitionId);

            //Assert
            result
            .Should()
            .BeAssignableTo <BadRequestObjectResult>()
            .Which
            .Value
            .Should()
            .Be("Job definition id was not provid");
        }
        public async Task GetAllJobDefinitions_GivenNotInCacheButFoundInCosmoshe_ReturnsAndSetsInCache()
        {
            //Arrange
            List <JobDefinition> jobDefinitions = new List <JobDefinition>
            {
                new JobDefinition()
            };

            ICacheProvider cacheProvider = CreateCacheProvider();

            cacheProvider
            .GetAsync <List <JobDefinition> >(Arg.Is(CacheKeys.JobDefinitions))
            .Returns((List <JobDefinition>)null);

            IJobDefinitionsRepository jobDefinitionsRepository = CreateJobDefinitionsRepository();

            jobDefinitionsRepository
            .GetJobDefinitions()
            .Returns(jobDefinitions);

            JobDefinitionsService jobDefinitionsService = CreateJobDefinitionService(jobDefinitionsRepository, resiliencePolicies: GenerateTestPolicies(), cacheProvider: cacheProvider);

            //Act
            IEnumerable <JobDefinition> definitions = await jobDefinitionsService.GetAllJobDefinitions();

            //Assert
            definitions
            .Count()
            .Should()
            .Be(1);

            await
            cacheProvider
            .Received(1)
            .SetAsync(Arg.Is(CacheKeys.JobDefinitions), Arg.Any <List <JobDefinition> >());
        }