using System; using Centron.Tests.EndToEnd.Infrastructure; using System.Linq; using Xunit; using Xunit.Abstractions; using System.Collections.Generic; using Centron.Host.Messages; using System.Reflection; using Centron.Interfaces; namespace Centron.Tests.EndToEnd.Tests.CentronRestService { public class CentronRestServiceTest : CentronTest { // we have some wrong implementations here and we know it // but we don't want to retroactivly change them as that might break other products or even customer API calls // so we simply ignore them, and only check it for *new* methods private List KnownMethodsWithWrongRequestOrResponse = new() { "CreateUserStatistics", "CheckConnection" }; // methodname since they are used when using CentronWebService.CallAsync // uritemplate since they might be used in projects using service references or by customer using our api private List KnownMethodsWithWrongUriTemplates = new() { "DeleteBitlockerPoliciesByFilter", "DeleteServerRackTreeCategoriesByFilter", "DeleteServerRackTreeManufacturerByFilter", "ChangePassword", "GetArticleBranchAccountForArticle", "UpdateArticleBranchAccountForArticle", "GetSocialMediaActionEmployeeInteraction", "GetContractEvaluationBillingStartDate", "LoadContractEvaluationIncome", "LoadContractEvaluation", "GetContractEvaluationRevenueDetails", "GetContractEvaluationVirtualServiceRevenueDetails", "GetContractEvaluationVirtualDeliveryRevenueDetails", "GetContractEvaluationVirtualDeliveryRevenueDetailsItems", "GetContractEvaluationUsedBalance", "GetContractEvaluationRevenueDetailsItems", "GetContractEvaluationVirtualServiceRevenueDetailsItems", "GetContractEvaluationUsedBalanceItem", "GetContractEvaluationRevenueDetailsPerBillingInterval", "SearchSupplierWithPaging", "GetAllEDIFiles", "GetOrderSuggestionListArticlePerItems", "GetOrderSuggestionListOrder", "GetOrderSuggestionListWH", "GetOrderSuggestionListFreeSpecAgreement", "GetOrderSuggestionListFreeArticlePerWH", "GetOrderSuggestionListDistributor", "GetOrderSuggestionListDistributorToArticle", "UpdateOrderSuggestionListOrderItems", "GetOrderSuggestionListLastUseArticle", "GetOrderSuggestionListPriceMatrix", "StoreOrderSuggestionListSuggestionInfo", "RemoveOrderSuggestionListDirectDelivery", "GetOrderSuggestionListArticle", "AddMonitoringDevicesForImmediateCheckExecution", "GetAssetManagementComputerSystemByIdentifier", "GetAssetManagementServiceConnectorLogs", "GetAssetManagementDefaultCheckConfigurationByCheckConfigurationId", "GetDiagrams", "IsRentArticleInUse", "GeocodingUpdateWithGeoInfoUpdateFailed" }; private List KnownRestServiceMethodsWithoutInterfaceMethods = new() { "GetProductUpdateFromPlannedUpdate", }; private List _interfaceMethods; public CentronRestServiceTest(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { this._interfaceMethods = typeof(Host.Services.ICentronRestService).GetMethods().ToList(); } [Fact] public void TestInterfaceReturnAndParameters() { foreach (var currentInterfaceMethod in this._interfaceMethods) { if (this.KnownMethodsWithWrongRequestOrResponse.Contains(currentInterfaceMethod.Name)) continue; var isCorrectReturnType = currentInterfaceMethod.ReturnType == typeof(Response) || (currentInterfaceMethod.ReturnType.IsGenericType && currentInterfaceMethod.ReturnType.GetGenericTypeDefinition() == typeof(Response<>)); Assert.True(isCorrectReturnType, $"{currentInterfaceMethod.Name} does not have correct return type"); var parameters = currentInterfaceMethod.GetParameters().ToList(); Assert.True(parameters.Count() == 1, $"{currentInterfaceMethod.Name} does not have request parameter or contains too many parameters"); var parameter = parameters.First(); var parameterIsCorrectType = parameter.ParameterType == typeof(Request) || (parameter.ParameterType.IsGenericType && parameter.ParameterType.GetGenericTypeDefinition() == typeof(Request<>)); Assert.True(parameterIsCorrectType, $"{currentInterfaceMethod.Name} does not have correct request parameter"); } } [Fact] public void TestInterfaceAttributes() { foreach (var currentInterfaceMethod in this._interfaceMethods) { if (this.KnownMethodsWithWrongUriTemplates.Contains(currentInterfaceMethod.Name)) continue; // have to go this weird way, as WebInvokeAttribute is declared once for c-entron and once for riverbird var attribute = currentInterfaceMethod.CustomAttributes.FirstOrDefault(x => x.AttributeType.Name == "WebInvokeAttribute"); Assert.NotNull(attribute); var uriTemplate = (string)attribute.NamedArguments.First(f => f.MemberName == "UriTemplate").TypedValue.Value; var methodName = currentInterfaceMethod.Name; // some methods use uritemplates with prefixes ("Account/dothis" or "Chat/dothat") if (uriTemplate.Contains("/")) uriTemplate = uriTemplate.Split("/").Last(); // some methods have a "CentronDivo", "RiverbirdDivo" or "Rmm" prefix if (methodName.StartsWith("CentronDivo")) methodName = methodName.Replace("CentronDivo", string.Empty); if (methodName.StartsWith("RiverDivo")) methodName = methodName.Replace("RiverDivo", string.Empty); if (methodName.StartsWith("Rmm")) methodName = methodName.Replace("Rmm", string.Empty); Assert.Equal(methodName, uriTemplate); } } [Fact] public void TestRestServiceMethodsHaveMatchingInterfaceMethods() { var restServiceMethods = typeof(Host.Services.CentronRestService) .GetMethods() .Where(f => f.ReturnType == typeof(Response) || (f.ReturnType.IsGenericType && f.ReturnType.GetGenericTypeDefinition() == typeof(Response<>))) .ToList(); foreach (var currentMethod in restServiceMethods) { if (this.KnownRestServiceMethodsWithoutInterfaceMethods.Contains(currentMethod.Name)) continue; var interfaceMethod = this._interfaceMethods.FirstOrDefault(f => f.Name == currentMethod.Name); // using assert.true to be able to return a message, since NullException does not tell you what is missing Assert.True(interfaceMethod != null, $"{currentMethod.Name} does not have matching interface method"); } } [Fact] public void TestDTOsDontHaveIList() { // Our web-service should not return anything that is an IList // ILists often are used like Lists, adding and removing items // But they are actually almost always arrays, where adding and removing items throws an exception // In c-entron.NET we might not notice it, because when testing with BL-Logic, the IList is actually a List // But when running with WS-Logic, it's an array, and then we get exceptions var allWebServiceCoreTypes = typeof(Response).Assembly.GetTypes(); var allCentronInterfaceTypes = typeof(CentronObjectKindNumeric).Assembly.GetTypes(); var allPublicTypes = allWebServiceCoreTypes.Union(allCentronInterfaceTypes); var publicTypesWithIList = allPublicTypes.Where(AnyPropertyIsIList).Select(f => f.Name).ToList(); var knownTypesWithIList = GetKnownTypesWithIList(); var newTypesWithIList = publicTypesWithIList.Where(f => knownTypesWithIList.Contains(f) is false).ToList(); var typesThatDontHaveIListAnymore = knownTypesWithIList.Where(f => publicTypesWithIList.Contains(f) is false).ToList(); Assert.Empty(newTypesWithIList); Assert.Empty(typesThatDontHaveIListAnymore); // If some items are in this list, remove them from the GetKnownTypesWithIList method below bool AnyPropertyIsIList(Type type) { if (type.IsEnum) return false; return type .GetProperties() .Any(f => f.PropertyType.IsGenericType && f.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)); } List GetKnownTypesWithIList() { return new List { "AccountActivitySearchFilter", "AccountActivitySearchItemDTOPagingDTO", "AccountBuisnessLineRequest", "AccountInterestRequest", "AccountLicenseInformationsFilter", "AccountOrderProcessingContractFilter", "AccountPrintOptionsFilter", "AccountProductRequest", "AccountSearchFilter", "AccountSearchItemDTO", "AccountSearchItemDTOPagingDTO", "AccountSpecialPriceFilter", "AccountTypeFilter", "AccountUnpaidInvoiceOverviewFilter", "AddDocumentToDirectoryRequest", "AddDocumentToSpecialDirectoryRequest", "AddEmployeesToCampaignRequest", "AdditionalArticleFilter", "AddParticipantContactsRequest", "AddParticipantsToCampaignRequest", "AddressContactListThroughPagingDTO", "ArticleFixedSpecificationFilter", "ArticleFixedSpecificationValueFilter", "ArticlePreviewDTOListThroughPaging", "ArticleReceiptItemsResultDTO", "ArticleStockPreviewFilter", "ArticleToEnvironmentalProtectionFilter", "ArticleToWorkSafetyFilter", "ArticleVariableSpecificationFilter", "ArticleVolumePricesFilter", "AssignBranchToStockRequest", "AssignEmployeeToSalesAreasRequest", "AssignSalesAreaToEmployeesRequest", "BackupAndRestoreDTO", "BarCode2Filter", "BarcodeConditionFilter", "BarcodeOverviewFilter", "BarcodeOverviewListThroughPagingDTO", "BookKeepingAccountSystemDTO", "BookKeepingAddressDTO", "BookKeepingBookingDataExportFilter", "BookKeepingExportAccountSplitDTO", "BookKeepingExportCashBookDataFilter", "BookKeepingExportSupplierBookingDataDTO", "BookKeepingImportDataPreviewResult", "BookKeepingImportInterfaceWithColumns", "BookKeepingImportInterfaceWithColumnsDTO", "BookKeepingLoadReceiptFilter", "BookKeepingStartImportFilter", "CampaignDTO", "CampaignDTOPagingDTO", "CampaignParticipantDTOPagingDTO", "CampaignParticipantsSearchFilter", "CampaignSearchFilter", "CentronConnectionHelpdeskTypeFilter", "CentronIconDTOPagingDTO", "CentronMailAddressCollection", "CentronMailBody", "CheckOutSerialNumbersRequest", "CompanyFilter", "ContractExternalArticleImportHeadDTO", "ContractToInvoiceParam", "CreateAutomatedBillingInvoiceToContractCompleteRequest", "CreateBackupAndRestoreRequest", "CreateCustomerInformationRequest", "CreateFullReportForReceiptRequest", "CreateHelpdesksForReceiptRequest", "CreateHelpdeskTimerReceiptItemsRequest", "CreateMachineRequest", "CreateMailServerRequest", "CreateNetworkComponentRequest", "CreateNetworkStructureRequest", "CreateNewReceiptRequest", "CreateNewSerialNumberRequest", "CreatePartListArticleFromArticleI3DsRequest", "CreateReceiptItemsFromExistingItemsData", "CreditVoucherPreviewDTO", "CreditVoucherPreviewListThroughPagingDTO", "CRMActivityListThroughPagingDTO", "CTRTypesDTO", "CustomerBookingDataFileExportFilter", "CustomerDataExportFileFilter", "CustomerInformationDTO", "CustomStatisticFilter", "CustomTableDTO", "CustomTableRowDTO", "DashboardContainerFilter", "DataSecurityCleanUpStatsFilter", "DeleteDashboardContainerRequest", "DeliveryListPreviewDTO", "DeliveryListPreviewListThroughPagingDTO", "DocumentDTO", "EDIReceiptItemsDTO", "EmployeeDepartmentDTO", "EmployeePreviewListThroughPagingDTO", "EmployeeStatisticFilter", "EmployeeUtilizationDTO", "EmployeeUtilizationFilter", "EnvironmentalProtectionDTO", "EnvironmentalProtectionFilter", "ExportCustomerBookingDataFileFilter", "ExportCustomerDataFileFilter", "ExportSupplierBookingDataFileFilter", "ExportSupplierDataFileFilter", "ForwardHelpdeskRequest", "ForwardHelpdeskRequestDTO", "ForwardReceiptRequest", "GetAccountContractKindsFilter", "GetAccountContractsFilter", "GetArticlePurchaseInfoRequest", "GetCurrentCounterStateRequest", "GetLogosFilter", "GetOrderSuggestionListPriceMatrix", "GetPasswordManagerCustomersEmployeesRightsRequest", "GetReceiptProjectVariablesRequest", "GetReportPdfStreamRequest", "HelpdeskCategoryDTO", "HelpdeskCategoryFilter", "HelpdeskOverviewFilterDTO", "HelpdeskPreviewListThroughPagingDTO", "HelpDeskShapeSettingDetailDTO", "HelpdeskTypeFilter", "HourlySurchargeRateDTO", "IAccount", "IAccountAddress", "IArticle", "IAssetItemDisplayBase", "IBookKeepingAddress", "ICustomTable", "ICustomTableRow", "IEDIReceiptItems", "IEnvironmentalProtection", "IMaterialGroup", "ImportOrderDTO", "ImportOrderPositionDTO", "ImportOrderResultDTO", "InvoiceArticleStatisticThroughPagingDTO", "InvoicePreviewDTO", "InvoicePreviewListThroughPagingDTO", "IPagingList`1", "IReceiptContract", "IReceiptCreditVoucher", "IReceiptDeliveryList", "IReceiptInvoice", "IReceiptItemBase", "IReceiptItemWithBarcodes", "IReceiptItemWithTimer", "IReceiptOffer", "IReceiptOrder", "IReceiptPickupList", "IReceiptSupplierCreditVoucher", "IReceiptSupplierDeliveryList", "IReceiptSupplierInvoice", "IReceiptSupplierOrder", "IReceiptWithProvision", "ISecondaryMaterialGroup", "ISurveyProcessStepWithInstructions", "IWorkSafety", "LoadByCampaignParticipantsI3DsRequest", "LoggedInUserInformationDTO", "MachineDTO", "MailingSearchFilter", "MailScannerProfileFilter", "MailScannerWorkflow", "MailScannerWorkflowComponent", "MailScannerWorkflowFilter", "MailScannerWorkflowStepDTO", "MailServerDTO", "MasterDataListItemDTO", "MaterialGroupPreviewDTO", "MyDayEmployeeSelectionRequest", "MyDayFinalizedDaysFilter", "MyDaySettingsDTO", "MyDayTextWithParameters", "MyDayWorkItemCommentDTO", "MyDayWorkItemDTO", "MyDayWorkItemsFilter", "NetworkComponentDataAccessPointDTO", "NetworkComponentDataDTO", "NetworkComponentDataFirewallDTO", "NetworkComponentDataPrinterDTO", "NetworkComponentDataRouterDTO", "NetworkComponentDataSwitchDTO", "NetworkComponentDTO", "NetworkStructureDataDHCPDTO", "NetworkStructureDataDNSDTO", "NetworkStructureDataDTO", "NetworkStructureDataNTPDTO", "NetworkStructureDataWINSDTO", "NetworkStructureDTO", "NewExportSupplierBookingDataFileFilter", "OfferArticleStatisticFilter", "OfferPreviewDTO", "OfferPreviewListThroughPagingDTO", "OrderInvoiceDocumentDTO", "OrderPreviewDTO", "OrderPreviewListThroughPagingDTO", "OrderPreviewsThrougPagingDTO", "OrderSuggestionFilter", "OutgoingPaymentReceiptItemsFilter", "OutgoingPaymentsReceiptDTO", "OutgoingPaymentsReceiptDTOPagingDTO", "OutgoingPaymentsReceiptItemDTOPagingDTO", "PagingList`1", "PartListArticlePreviewFilter", "PasswordManagerCustomerEmployeesRightsDTO", "PasswordManagerGuidelineDTO", "PasswordManagerGuidelineExcludedCustomersFilter", "PasswordManagerGuidelineFilter", "PasswordManagerLogFilter", "PaymentTransactionExportInvoicesRequest", "PlannedUpdatesDTO", "ProjectPriceImportDTO", "PurchaseStatisticFilter", "QuickNoteListThroughPagingDTO", "ReceiptContractHeadDTO", "ReceiptContractItemDTO", "ReceiptContractItemVersionDTO", "ReceiptCreatedTicket", "ReceiptCreditVoucherItemDTO", "ReceiptCreditVoucherItemVersionDTO", "ReceiptDeliveryListItemDTO", "ReceiptDeliveryListItemVersionDTO", "ReceiptHelpdeskData", "ReceiptHelpdeskInfo", "ReceiptInfo", "ReceiptInvoiceItemDTO", "ReceiptInvoiceItemVersionDTO", "ReceiptItemBaseDTO", "ReceiptItemServiceArticleClassificationFilter", "ReceiptOfferItemDTO", "ReceiptOfferItemVersionDTO", "ReceiptOrderItemDTO", "ReceiptOrderItemVersionDTO", "ReceiptOrderProjectFilter", "ReceiptPaymentInfo", "ReceiptPdfDocumentDTO", "ReceiptPickupListItemDTO", "ReceiptPickupListItemVersionDTO", "ReceiptSearchFilter", "ReceiptSearchItemPagingDTO", "ReceiptSettingsDTO", "ReceiptSupplierCreditVoucherItemDTO", "ReceiptSupplierDeliveryListItemDTO", "ReceiptSupplierInvoiceItemDTO", "ReceiptSupplierItemBaseDTO", "ReceiptSupplierOrderItemDTO", "ReceiptSupplierOrderItemVersionDTO", "RemoveParticipantsFromCampaignRequest", "ReportDataSettingsDTO", "ReportVersionDataEntity", "SalesArticleStatisticFilter", "SaveAccountVPNAccessesRequest", "SaveCustomPropertyStructureRequest", "SaveCustomPropertyValuesRequest", "SaveHelpdeskTimerAddressSpecialArticleRequest", "SaveHelpdeskTimerSpecialArticlesRequest", "SaveMailingActivityTicketRequest", "SaveOrUpdatePasswordManagerCustomerCategoriesRequest", "SavePasswordManagerExternalApplicationsRequest", "SaveReceiptProjectLayoutItemsRequest", "SaveReceiptUserStateRequest", "ScheduleDTO", "SearchBillingContractsFilter", "SearchCustomerFilter", "SearchReceiptPdfDocumentsFilter", "SearchSpecialArticleToContractHeadFilter", "SearchSupplierFilter", "SearchWebReceiptItemChangeRequestsFilter", "SecondaryMaterialGroupDTO", "SelfCareFormDTO", "SendHelpdeskTimerSignatureReportToCustomerRequest", "SepaContractFilter", "SetBarcodeConditionInBarcodeRequest", "SetDepartmentEmployeeAssignmentsRequest", "SetEmployeeArticlesRequest", "SetEmployeeDepartmentAssignmentsRequest", "SetReceiptsAsExportedRequest", "SkillGroupDTO", "SocialMediaCustomerFeedThroughPagingDTO", "SocialMediaFeedThroughPagingDTO", "SpecialArticleToContracteArticleSpecialPriceFilter", "SpecialArticleToContractHeadDTO", "SpecialArticleToContractHeadImport", "SpecialArticleToContractImportContractDataFilter", "SpecialArticleToContractImportExternalCodesFilter", "SpecialArticleToContractWortmannImportDataResultDTO", "SpecialDMSSyncFileFilter", "StorageAreaFilter", "StoragePlaceFilter", "SupplierBookingDataFileExportFilter", "SupplierBookingPreviewDTO", "SupplierBookingPreviewListThroughPagingDTO", "SupplierBranchInfoFilter", "SupplierCalculationPreviewDTO", "SupplierCalculationPreviewListThroughPagingDTO", "SupplierCreditVoucherPreviewDTO", "SupplierCreditVoucherPreviewListThroughPagingDTO", "SupplierDataExportFileFilter", "SupplierInquiryPreviewDTO", "SupplierInquiryPreviewListThroughPagingDTO", "SupplierOrderInvoicesDTO", "SupplierPdfScanConfigsFilter", "SupplierReceiptDocumentDTO", "SupplierReceiptDocumentsFilter", "SurveyProcessFreeTextProcessStepDTO", "SurveyProcessMultiChoiceProcessStepDTO", "SurveyProcessScaleProcessStepDTO", "SurveyProcessYesNoProcessStepDTO", "TapiCallStateChangedDTO", "TaskManagementWeeklyRecurrenceDTO", "TelemarketingListThroughPagingDTO", "TelemarketingReferenceThroughPagingDTO", "TicketPatternDTO", "TicketStatisticFilter", "ToDoDTOListThroughPaging", "TravelExpenseCategoryDTO", "UpdateActivePrioritiesRequest", "UpdateArticleBranchAccountForArticleRequest", "UpdateBackupAndRestoreRequest", "UpdateCustomerInformationRequest", "UpdateDashboardContainersRequest", "UpdateMachineRequest", "UpdateMailServerRequest", "UpdateNetworkComponentRequest", "UpdateNetworkStructureRequest", "UpdateNotificationUsersFromObjectRequest", "WebReceiptDTO", "WorkflowShapeDTO", "WorkSafetyDTO", "WorkSafetyFilter" }; } } } }