Exemple #1
0
        public async Task AssertHttpCircuitBreakerWorksCorrectly()
        {
            // Arrange - Setup the handler for the mocked HTTP call
            _isCircuitBroken   = false;
            _isCircuitRestored = false;
            _isRetryCalled     = false;
            _retryCount        = 0;

            mockHttpMessageHandler.Protected()
            .Setup <Task <HttpResponseMessage> >("SendAsync", ItExpr.IsAny <HttpRequestMessage>(), ItExpr.IsAny <CancellationToken>())
            .ReturnsAsync(() =>
            {
                if (_retryCount > 5)
                {
                    return(new HttpResponseMessage()
                    {
                        StatusCode = HttpStatusCode.OK
                    });
                }
                else
                {
                    return(new HttpResponseMessage()
                    {
                        StatusCode = HttpStatusCode.TooManyRequests
                    });
                }
            });


            var client = new HttpClient(mockHttpMessageHandler.Object);

            mockFactory.Setup(_ => _.CreateClient(It.IsAny <string>())).Returns(client);

            // Arrange - Setup the Service/Poco details
            DevToService devtoService = new DevToService(mockFactory.Object, mockLogger.Object);
            DevToPoco    devtoPoco    = new DevToPoco()
            {
                article = new Article()
                {
                    body_markdown = "#Test My Test",
                    description   = "This is a description",
                    canonical_url = "https://www.cloudwithchris.com",
                    published     = false,
                    series        = "Cloud Drops",
                    tags          = new List <string>()
                    {
                        "DevOps", "GitHub"
                    },
                    title = "Descriptive Title"
                }
            };
            Mock <CancellationTokenSource> mockCancellationTokenSource = new Mock <CancellationTokenSource>();

            // Act
            try
            {
                await GetRetryPolicyAsync().WrapAsync(GetCircuitBreakerPolicyAsync()).ExecuteAsync(async() =>
                {
                    return(await devtoService.CreatePostAsync(devtoPoco, "integrationToken", mockCancellationTokenSource.Object));
                });
            }
            catch (BrokenCircuitException ex)
            {
                Console.WriteLine(ex.Message);
            }

            // Assert
            Assert.True(_isRetryCalled);
            Assert.True(_isCircuitBroken);
            Assert.True(_isCircuitRestored);
        }
Exemple #2
0
        /// <summary>
        /// The ConvertAndPostAsync is executed on an individual file. It reads the file, processes it by removing localURLs and pulling the required frontmatter out of the document. This is then added to an appropriate POCO, either for Medium or for DevTo. As a future exercise, could investigate making this POCO agnostic of the third party service.
        /// </summary>
        /// <param name="filePath">File Path of the file to be processed.</param>
        async Task <ProcessedResultObject> ConvertAndPostAsync(string filePath, ThirdPartyService thirdPartyService, CancellationTokenSource cts)
        {
            // Obtain the filename without the directoryPath, so that it can be used for the canonical URL details later on.
            string canonicalPath = filePath.Replace($"{directoryPath}\\", "");

            _logger.LogInformation($"[Loop] Processing ${filePath}");

            // Read the file contents out to a string
            string sourceFile = await _markdownService.readFile(filePath);

            // Process the file contents, by replacing any localURL within the markdown to a full URL.
            string contentWithFrontMatter = await _markdownService.replaceLocalURLs(sourceFile, baseUrl);

            // Also take a copy of the file contents, but without the frontmatter. This may be needed dependant upon the third party service.
            string contentWithoutFrontMatter = await _markdownService.removeFrontMatter(contentWithFrontMatter);

            string publishedDate = await _markdownService.getFrontmatterProperty(contentWithFrontMatter, "PublishDate");

            string canonicalUrl = await _markdownService.getCanonicalUrl(protocol, baseUrl, canonicalPath);


            List <string> series = (await _markdownService.getFrontMatterPropertyList(contentWithFrontMatter, "series", 1));

            // If required, prepend the original post information.

            /*if (originalPostInformation && !string.IsNullOrEmpty(publishedDate))
             *                {
             *                        contentWithoutFrontMatter = await _markdownService.prependOriginalPostSnippet(contentWithoutFrontMatter, DateTime.ParseExact(publishedDate, "yyyy-MM-dd HH:mm:ss", null), canonicalUrl);
             *                }*/

            IThirdPartyBlogPoco payload;

            switch (thirdPartyService)
            {
            case ThirdPartyService.Medium:
                // Initialise the MediumPOCO by using several MarkDown Service methods, including getCanonicalURL, getFrontMatterProperty and getFrontMatterPropertyList.
                payload = new MediumPoco()
                {
                    title        = await _markdownService.getFrontmatterProperty(sourceFile, "title"),
                    content      = contentWithoutFrontMatter,
                    canonicalUrl = canonicalUrl,
                    tags         = await _markdownService.getFrontMatterPropertyList(contentWithFrontMatter, "tags")
                };
                break;

            case ThirdPartyService.DevTo:
                // Initialise the DevToPOCO by using several MarkDown Service methods, including getCanonicalURL, getFrontMatterProperty and getFrontMatterPropertyList.

                payload = new DevToPoco()
                {
                    article = new Article()
                    {
                        title         = await _markdownService.getFrontmatterProperty(sourceFile, "title"),
                        body_markdown = contentWithoutFrontMatter,
                        canonical_url = canonicalUrl,
                        tags          = await _markdownService.getFrontMatterPropertyList(contentWithFrontMatter, "tags", 4, true),
                        description   = await _markdownService.getFrontmatterProperty(contentWithFrontMatter, "description")
                    }
                };

                if (series.Count > 0)
                {
                    (payload as DevToPoco).article.series = series[0];
                }

                int organization_id;

                if (int.TryParse(devtoOrganization, out organization_id))
                {
                    (payload as DevToPoco).article.organization_id = organization_id;
                }

                break;

            default:
                payload = new DevToPoco();
                break;
            }

            // If we were successful, it means we have both pieces of information and should be able to authenticate to Medium.
            _logger.LogInformation($"[{thirdPartyService.ToString()}] Crossposting {filePath}...");

            if (logPayloadOutput.ToLower().Equals("true"))
            {
                _logger.LogInformation($"[{thirdPartyService.ToString()}] {JsonSerializer.Serialize(payload, payload.GetType())}");
            }

            try
            {
                HttpResponseMessage responseMessage = new HttpResponseMessage()
                {
                    StatusCode = System.Net.HttpStatusCode.NotFound
                };

                if (!cts.Token.IsCancellationRequested)
                {
                    switch (thirdPartyService)
                    {
                    case ThirdPartyService.Medium:
                        responseMessage = await _mediumService.CreatePostAsync(payload as MediumPoco, mediumToken, cts, mediumAuthorId, await _markdownService.getFrontmatterProperty(contentWithFrontMatter, "youtube"));

                        break;

                    case ThirdPartyService.DevTo:
                        responseMessage = await _devToService.CreatePostAsync(payload as DevToPoco, devtoToken, cts, null, await _markdownService.getFrontmatterProperty(contentWithFrontMatter, "youtube"));

                        break;

                    default:
                        break;
                    }
                }

                if (responseMessage.IsSuccessStatusCode)
                {
                    _logger.LogInformation($"[{thirdPartyService.ToString()}] Crossposting of {filePath} complete.");
                    return(new ProcessedResultObject()
                    {
                        result = Result.Success
                    });
                }
                else
                {
                    _logger.LogWarning($"[{thirdPartyService.ToString()}] Crossposting of {filePath} cancelled. A previous response was received as Unauthorized, so all operations have been cancelled for this third party service. Please confirm your authentication details are correct for this Third Party Service.");

                    return(new ProcessedResultObject()
                    {
                        result = Result.Unauthorized
                    });
                }
            }
            catch (UnauthorizedResponseException)
            {
                _logger.LogWarning($"[{thirdPartyService.ToString()}] Crossposting of {filePath} cancelled. A previous response was received as Unauthorized, so all operations have been cancelled for this third party service. Please confirm your authentication details are correct for this Third Party Service.");

                return(new ProcessedResultObject()
                {
                    result = Result.Unauthorized
                });
            }
            catch (UnprocessableEntityException ex)
            {
                _logger.LogWarning($"[{thirdPartyService.ToString()}] Crossposting of {filePath} failed, as entity could not be processed.");

                return(new ProcessedResultObject()
                {
                    result = Result.Unprocessable,
                    jsonObject = ex.Message
                });
            }
        }