/// <summary>
 /// Runs the Smart Detector's resolution check flow.
 /// </summary>
 /// <param name="request">The alert resolution check request.</param>
 /// <param name="shouldDetectorTrace">Determines if the detector's traces are emitted.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <returns>A <see cref="Task{TResult}"/>, returning the resolution check response generated by the Smart Detector.</returns>
 public async Task <ContractsAlertResolutionCheckResponse> CheckResolutionAsync(
     ContractsAlertResolutionCheckRequest request,
     bool shouldDetectorTrace,
     CancellationToken cancellationToken)
 {
     return(await this.LoadAndRunSmartDetector(
                request.OriginalAnalysisRequest.SmartDetectorId,
                shouldDetectorTrace,
                request,
                this.CheckAlertResolutionAsync,
                cancellationToken));
 }
        /// <summary>
        /// Runs the Smart Detector's resolution check flow.
        /// </summary>
        /// <param name="request">The alert resolution check request.</param>
        /// <param name="smartDetector">The Smart Detector to run</param>
        /// <param name="smartDetectorManifest">The Smart Detector's manifest</param>
        /// <param name="detectorTracer">The tracer to provider for the Smart Detector</param>
        /// <param name="cancellationToken">The cancellation token</param>
        /// <returns>A <see cref="Task{TResult}"/>, returning the resolution check response generated by the Smart Detector.</returns>
        private async Task <ContractsAlertResolutionCheckResponse> CheckAlertResolutionAsync(
            ContractsAlertResolutionCheckRequest request,
            ISmartDetector smartDetector,
            SmartDetectorManifest smartDetectorManifest,
            ITracer detectorTracer,
            CancellationToken cancellationToken)
        {
            // Check that the detector supports resolution
            if (!(smartDetector is IResolvableAlertSmartDetector resolvableAlertSmartDetector))
            {
                throw new ResolutionCheckNotSupportedException($"Smart Detector {smartDetectorManifest.Name} does not support alert resolution of alerts");
            }

            // Create state repository
            IStateRepository stateRepository = this.stateRepositoryFactory.Create(request.OriginalAnalysisRequest.SmartDetectorId, request.OriginalAnalysisRequest.AlertRuleResourceId);

            // Load the resolution state from the repository
            ResolutionState resolutionState = await stateRepository.GetStateAsync <ResolutionState>(GetResolutionStateKey(request.AlertCorrelationHash), cancellationToken);

            if (resolutionState == null)
            {
                throw new ResolutionStateNotFoundException($"Resolution state for Alert with correlation {request.AlertCorrelationHash} was not found");
            }

            // Create the input for the Smart Detector
            AnalysisRequestParameters analysisRequestParameters = await this.CreateAnalysisRequestParametersAsync(
                resolutionState.AnalysisRequestTime,
                request.OriginalAnalysisRequest,
                smartDetectorManifest,
                false,
                cancellationToken);

            var alertResolutionCheckRequest = new AlertResolutionCheckRequest(
                analysisRequestParameters,
                new AlertResolutionCheckRequestParameters(ResourceIdentifier.CreateFromResourceId(request.TargetResource), request.AlertFireTime, resolutionState.AlertPredicates),
                this.analysisServicesFactory,
                stateRepository);

            // Run the Smart Detector
            this.tracer.TraceInformation($"Started running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name} for resolution check");
            try
            {
                AlertResolutionCheckResponse alertResolutionCheckResponse = await resolvableAlertSmartDetector.CheckForResolutionAsync(alertResolutionCheckRequest, detectorTracer, cancellationToken);

                this.tracer.TraceInformation($"Completed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name} for resolution check");

                // If the alert is resolved - delete the state
                if (alertResolutionCheckResponse.ShouldBeResolved)
                {
                    await stateRepository.DeleteStateAsync(GetResolutionStateKey(request.AlertCorrelationHash), cancellationToken);
                }

                // Convert the result
                return(new ContractsAlertResolutionCheckResponse
                {
                    ShouldBeResolved = alertResolutionCheckResponse.ShouldBeResolved,
                    ResolutionParameters = alertResolutionCheckResponse.AlertResolutionParameters?.CreateContractsResolutionParameters()
                });
            }
            catch (Exception e)
            {
                this.tracer.TraceError($"Failed running Smart Detector ID {smartDetectorManifest.Id}, Name {smartDetectorManifest.Name} for resolution check: {e}");
                throw new FailedToRunSmartDetectorException($"Calling Smart Detector '{smartDetectorManifest.Name}' for resolution check failed with exception of type {e.GetType()} and message: {e.Message}", e);
            }
        }
        private void TestInitialize(ResourceType requestResourceType, ResourceType smartDetectorResourceType)
        {
            this.testContainer = new UnityContainer();

            this.testContainer.RegisterType <ISmartDetectorRunner, SmartDetectorRunner>();

            this.testContainer.RegisterInstance(new Mock <ITracer>().Object);

            ResourceIdentifier resourceId;

            switch (requestResourceType)
            {
            case ResourceType.Subscription:
                resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", string.Empty, string.Empty);
                break;

            case ResourceType.ResourceGroup:
                resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", "resourceGroup", string.Empty);
                break;

            default:
                resourceId = new ResourceIdentifier(requestResourceType, "subscriptionId", "resourceGroup", "resourceName");
                break;
            }

            this.resourceIds = new List <string> {
                resourceId.ToResourceId()
            };
            this.analysisRequest = new SmartDetectorAnalysisRequest
            {
                ResourceIds         = this.resourceIds,
                Cadence             = TimeSpan.FromDays(1),
                AlertRuleResourceId = "alertRule",
                SmartDetectorId     = "1",
                DetectorParameters  = new Dictionary <string, object>
                {
                    { "param1", "value1" },
                    { "param2", 2 },
                }
            };
            this.alertResolutionCheckRequest = new ContractsAlertResolutionCheckRequest
            {
                OriginalAnalysisRequest = new SmartDetectorAnalysisRequest
                {
                    ResourceIds         = this.resourceIds,
                    Cadence             = TimeSpan.FromDays(1),
                    AlertRuleResourceId = "alertRule",
                    SmartDetectorId     = "2",
                    DetectorParameters  = new Dictionary <string, object>
                    {
                        { "param1", "value1" },
                        { "param2", 2 },
                    }
                },
                AlertCorrelationHash = "correlationHash",
                TargetResource       = resourceId.ToResourceId(),
                AlertFireTime        = new DateTime(1985, 7, 3)
            };

            var smartDetectorManifest = new SmartDetectorManifest(
                "1",
                "Test Smart Detector",
                "Test Smart Detector description",
                Version.Parse("1.0"),
                "TestSmartDetectorLibrary",
                "class",
                new List <ResourceType>()
            {
                smartDetectorResourceType
            },
                new List <int> {
                60
            },
                null,
                null);

            this.smartDetectorPackage = new SmartDetectorPackage(new Dictionary <string, byte[]>
            {
                ["manifest.json"]            = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(smartDetectorManifest)),
                ["TestSmartDetectorLibrary"] = Array.Empty <byte>(),
            });

            var autoResolveSmartDetectorManifest = new SmartDetectorManifest(
                "2",
                "Test Auto Resolve Smart Detector",
                "Test Auto Resolve Smart Detector description",
                Version.Parse("1.0"),
                "TestSmartDetectorLibrary",
                "class",
                new List <ResourceType>()
            {
                smartDetectorResourceType
            },
                new List <int> {
                60
            },
                null,
                null);

            this.autoResolveSmartDetectorPackage = new SmartDetectorPackage(new Dictionary <string, byte[]>
            {
                ["manifest.json"]            = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(autoResolveSmartDetectorManifest)),
                ["TestSmartDetectorLibrary"] = Array.Empty <byte>(),
            });

            var smartDetectorRepositoryMock = new Mock <ISmartDetectorRepository>();

            smartDetectorRepositoryMock
            .Setup(x => x.ReadSmartDetectorPackageAsync("1", It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => this.smartDetectorPackage);
            smartDetectorRepositoryMock
            .Setup(x => x.ReadSmartDetectorPackageAsync("2", It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => this.autoResolveSmartDetectorPackage);
            this.testContainer.RegisterInstance(smartDetectorRepositoryMock.Object);

            this.testContainer.RegisterInstance(new Mock <IInternalAnalysisServicesFactory>().Object);

            this.smartDetector = new TestSmartDetector {
                ExpectedResourceType = smartDetectorResourceType
            };
            this.autoResolveSmartDetector = new TestAutoResolveSmartDetector {
                ExpectedResourceType = smartDetectorResourceType
            };

            var smartDetectorLoaderMock = new Mock <ISmartDetectorLoader>();

            smartDetectorLoaderMock
            .Setup(x => x.LoadSmartDetector(this.smartDetectorPackage))
            .Returns(() => this.smartDetector);
            smartDetectorLoaderMock
            .Setup(x => x.LoadSmartDetector(this.autoResolveSmartDetectorPackage))
            .Returns(() => this.autoResolveSmartDetector);
            this.testContainer.RegisterInstance(smartDetectorLoaderMock.Object);

            var azureResourceManagerClientMock = new Mock <IExtendedAzureResourceManagerClient>();

            azureResourceManagerClientMock
            .Setup(x => x.GetAllResourceGroupsInSubscriptionAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((string subscriptionId, CancellationToken cancellationToken) => new List <ResourceIdentifier>()
            {
                new ResourceIdentifier(ResourceType.ResourceGroup, subscriptionId, "resourceGroupName", string.Empty)
            });
            azureResourceManagerClientMock
            .Setup(x => x.GetAllResourcesInSubscriptionAsync(It.IsAny <string>(), It.IsAny <IEnumerable <ResourceType> >(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((string subscriptionId, IEnumerable <ResourceType> resourceTypes, CancellationToken cancellationToken) => new List <ResourceIdentifier>()
            {
                new ResourceIdentifier(ResourceType.VirtualMachine, subscriptionId, "resourceGroupName", "resourceName")
            });
            azureResourceManagerClientMock
            .Setup(x => x.GetAllResourcesInResourceGroupAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IEnumerable <ResourceType> >(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((string subscriptionId, string resourceGroupName, IEnumerable <ResourceType> resourceTypes, CancellationToken cancellationToken) => new List <ResourceIdentifier>()
            {
                new ResourceIdentifier(ResourceType.VirtualMachine, subscriptionId, resourceGroupName, "resourceName")
            });
            this.testContainer.RegisterInstance(azureResourceManagerClientMock.Object);

            this.stateRepository     = new Dictionary <string, object>();
            this.stateRepositoryMock = new Mock <IStateRepository>();
            this.stateRepositoryMock
            .Setup(m => m.StoreStateAsync(It.IsAny <string>(), It.IsAny <object>(), It.IsAny <CancellationToken>()))
            .Callback <string, object, CancellationToken>((key, value, token) => this.stateRepository[key] = value)
            .Returns(Task.CompletedTask);
            this.stateRepositoryMock
            .Setup(m => m.GetStateAsync <ResolutionState>(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns <string, CancellationToken>((key, token) => Task.FromResult((ResolutionState)(this.stateRepository.ContainsKey(key) ? this.stateRepository[key] : null)));
            this.stateRepositoryMock
            .Setup(m => m.DeleteStateAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Callback <string, CancellationToken>((key, token) => this.stateRepository.Remove(key))
            .Returns(Task.CompletedTask);
            this.stateRepositoryFactoryMock = new Mock <IStateRepositoryFactory>();
            this.stateRepositoryFactoryMock.Setup(m => m.Create(It.IsAny <string>(), It.IsAny <string>())).Returns(this.stateRepositoryMock.Object);
            this.testContainer.RegisterInstance(this.stateRepositoryFactoryMock.Object);
        }